title: Custom ControlValueAccessor in template-driven forms
body: <p>I have a custom <code>&lt;data-input-text&gt;</code> component which has two modes: regular and disabled. Here is the <strong>template</strong> (I've simplified it a bit for demo case):</p>
  
  <pre><code>&lt;label  *ngIf="!disabled"
      class="field-label" 
      [ngClass]="{'focused' : isFocused, 'with-errors' : errors}"&gt;
      &lt;input class="field-value" 
              [type]="type"
              [required]="required"
              (focus)="onFocus()"
              (blur)="onBlur()"
              [(ngModel)]="value"
              #fieldInput="ngModel"&gt;
  
  &lt;/label&gt;
  &lt;div class="field-label" *ngIf="disabled"&gt;
      &lt;span class="field-value"&gt;{{ value }}&lt;/span&gt;
      &lt;span class="field-name"&gt;{{ label }}&lt;/span&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p>In the <strong>parent form</strong>, I use this component in the following way:</p>
  
  <pre><code>&lt;form #profileForm="ngForm"&gt;
      &lt;data-text-input
            label="lastName"
            [required]="true"
            [disabled]="userIsRegistered"                    
            name="lastName"
            ngModel&gt;&lt;/data-text-input&gt;
  &lt;/form&gt;
  </code></pre>
  
  <p><code>userIsRegistered</code> returns a boolean, which should switch between the input field or spans within the component. It all works fine until here.</p>
  
  <p>I set the <strong>form in the parent component</strong> to match the BehaviorSubject like this:</p>
  
  <pre><code> this._sub = this.dl.selectedEmployee.subscribe( u =&gt; {
    if ( u.id ) {
      this.isLoading = false;
        setTimeout( () =&gt; {
          this.profileForm.setValue(u);
          this.profileForm.control.markAsPristine();
        }, 10);
    }
  });
  </code></pre>
  
  <p>Here is the custom ControlValueAccessor <strong>component</strong>:</p>
  
  <pre><code>import { Component, Input, ViewChild, forwardRef, 
        AfterViewInit, OnInit, OnChanges, 
        NgModule } from '@angular/core';
  
  import { NG_VALUE_ACCESSOR, NG_VALIDATORS, 
        ControlValueAccessor, FormControl, 
        Validator, NgForm } from '@angular/forms';
  
   @Component({
     selector: 'data-text-input',
     template: `
     &lt;label  *ngIf="!disabled"
         class="field-label"&gt;
         &lt;input class="field-value" 
                 [type]="type"
                 [required]="required"
                 (blur)="onBlur()"
                 [(ngModel)]="value"
                 #fieldValue="ngModel"&gt;
         &lt;span class="field-name"&gt;{{ label }}&lt;/span&gt;
  
     &lt;/label&gt;
     &lt;div class="field-label" *ngIf="disabled"&gt;
         &lt;span class="field-value"&gt;{{ value }}&lt;/span&gt;
         &lt;span class="field-name"&gt;{{ label }}&lt;/span&gt;
     &lt;/div&gt;
       `,
       providers: [
         {
           provide: NG_VALUE_ACCESSOR,
           useExisting: forwardRef( ()=&gt; DataTextInputComponent ),
           multi: true
         },
         {
           provide: NG_VALIDATORS,
           useExisting: forwardRef( ()=&gt; DataTextInputComponent ),
           multi: true
         }
       ]
     })
  
     export class DataTextInputComponent implements OnChanges, ControlValueAccessor, Validator  {
  
  @Input() public disabled: boolean = false;
  @Input() public label: string;
  @Input() public required: boolean = false;
  @Input() public type: string = 'text';
  @ViewChild('fieldValue') public fieldValue: FormControl;
  
  // infrastructure
  public registerOnChange(fn: any) { this.propagateChange = fn; }
  public registerOnTouched(fn: any) { this.propagateTouch = fn; }
  
  private propagateChange = (_: any) =&gt; { };
  private propagateTouch = (_: any) =&gt; { };
  
  /**
   * inner value
   */
  private innerValue: any = null;
  
  /**
   * on changes hook
   */
  public ngOnChanges(): void {
      if ( this.disabled ) {
          this.propagateChange(this.innerValue);
      }
  }
  
  /**
   * input events
   */
  public onBlur(): void {
      this.propagateChange(this.innerValue);
      this.propagateTouch(true);
  }
  
  /**
   * value accessor setter and getter
   */
  public get value(): any {
      return this.innerValue;
  };
  
  public set value(value: any) {
      if ( value !== 'undefined' ) {
          this.innerValue = value;
          this.propagateChange(value);
          this.propagateTouch(true);
      }
  }
  
  /**
   * value accessor implementation
   * @param value 
   */
  public writeValue(value: any): void {
      if (value !== this.innerValue) {
          this.innerValue = value;
      }
  }
  
  /**
   * validation
   * @param c 
   */
  public validate(c: FormControl) {
      return this.errors = (this.disabled) ? null : this.customValidate(c);
  }
  private customValidate(c: FormControl): {} {
    if ( c.touched ) {
      // some validation logic which is not relevant here;
      return null;
    }
    return null;
  }
  }
  </code></pre>
  
  <p>There are other components used in the form, too (like a color picker and a ng-select). </p>
  
  <p>So the weird part is this. The form value is set alright. No errors. The values are displayed correctly (for both, <code>disabled</code> and <code>!disabled</code>) within data-text-input components, as well as other components in the form). The weird part is that when I inspect the <code>this.profileForm</code> object with the debugger, the <code>controls</code> property has all of the controls with their respective values, but the <code>value</code> property of the form misses those, where <code>disabled</code> property (aka no input field) is set to true. </p>
  
  <p>Here is the Plunker: <a href="https://plnkr.co/edit/nbWQZzQjhGae622CanGa?p=preview" rel="nofollow noreferrer">https://plnkr.co/edit/nbWQZzQjhGae622CanGa?p=preview</a></p>
  
  <p>Any ideas?</p>