title: In Angular 4, why do asynchronously validated nested controls not propagate their validity to the parent FormGroup?
body: <p>In my Angular 4.0.2 app, I have a <code>FormGroup</code> containing a nested component that implements <code>ControlValueAccessor</code> and <code>Validator</code>. This component validates itself asynchronously. The problem is, even when the nested component becomes valid, the parent <code>FormGroup</code> remains invalid.</p>
  
  <p>But, if I simply change the validation to be synchronous, the validity propagates correctly to the parent group.</p>
  
  <p>I have boiled it down as minimally as possible to the following Plunker:</p>
  
  <p><a href="http://plnkr.co/edit/H26pqEE3sRkzKmmhrBgm" rel="noreferrer">http://plnkr.co/edit/H26pqEE3sRkzKmmhrBgm</a></p>
  
  <p>Here is a second Plunker showing a similar setup, but this time the input <code>FormControl</code> is directly inside the <code>FormGroup</code> rather than being part of a nested component. Here, asynchronous validation propagates correctly:</p>
  
  <p><a href="http://plnkr.co/edit/DSt4ltoO1Cw2Nx1oXxbD" rel="noreferrer">http://plnkr.co/edit/DSt4ltoO1Cw2Nx1oXxbD</a></p>
  
  <p><strong>Why is my asynchronous validator not propagating its validity when defined inside a component?</strong></p>
  
  <hr>
  
  <p>Here is the code from the first (broken) Plunker:</p>
  
  <pre><code>import {Component, NgModule, VERSION, forwardRef} from '@angular/core'
  import {BrowserModule} from '@angular/platform-browser'
  import {FormsModule, ReactiveFormsModule} from '@angular/forms'
  import {Observable} from 'rxjs/Rx'
  import {
      FormGroup, FormControl, FormBuilder, Validators, AbstractControl, Validator,
      ControlValueAccessor, NG_VALUE_ACCESSOR, NG_VALIDATORS, ValidationErrors
  } from '@angular/forms';
  
  
  @Component({
    selector: 'my-app',
    template: `
  &lt;p&gt;When validated asyncronously, why is the parent form group invalid even though its 
  inner control is valid?&lt;/p&gt;
  &lt;p&gt;Try clearing the value to see the asyncronous validation at work.&lt;/p&gt;
  &lt;p&gt;Try swapping line 58 for 60 to change to syncronous validation, which propagates correctly.&lt;/p&gt;
  &lt;hr /&gt;
  &lt;div&gt;&lt;code&gt;FormGroup valid = {{form.valid}}&lt;/code&gt;&lt;/div&gt;&lt;br /&gt;
  &lt;div [formGroup]="form"&gt;
    &lt;nested-control formControlName="nested"&gt;&lt;/nested-control&gt;
  &lt;/div&gt;
  &lt;hr /&gt;
  `
  })
  export class App {
    form: FormGroup;
    constructor(fb: FormBuilder) {
      this.form = fb.group({
        nested: ['required']
      });
    }
  }
  
  
  @Component({
      selector: 'nested-control',
      providers: [{
          provide: NG_VALUE_ACCESSOR, 
          useExisting: forwardRef(() =&gt; NestedControl),
          multi: true
      }, {
          provide: NG_VALIDATORS,
          useExisting: forwardRef(() =&gt; NestedControl),
          multi: true,
      }],
      template: `
  &lt;div [formGroup]="form"&gt;
    &lt;input type="text" formControlName="input" (keyup)="keyup($event)"&gt;
    &lt;code&gt;NestedControl valid = {{form.controls.input.valid}}, errors = {{form.controls.input.errors|json}}&lt;/code&gt;
  &lt;/div&gt;
  `
  })
  export class NestedControl implements ControlValueAccessor, Validator {
    form: FormGroup;
    private propagateChange = () =&gt; {};
  
    constructor(fb: FormBuilder) {
      this.form = fb.group({
        // if we change the validation to be syncronous then everything works as expected:
        //input: [null, Validators.required]
        input: [null, null, this.asyncRequiredValidator]
      });
    }
  
    asyncRequiredValidator(control: AbstractControl): ValidationErrors {
      // run the built in required validator after 1 second
      return Observable.interval(1000).take(1).map(_ =&gt; {
        const result = Validators.required(control);
        console.log('result', result);
        return result;
      });
    }
  
    keyup() {
      this.propagateChange();
    }
  
    writeValue(v: any): void {
      this.form.setValue({ input: v });
    }
  
    registerOnChange(fn: any): void {
      this.propagateChange = fn;
    }
  
    registerOnTouched(fn: any): void {
    }
  
    validate(c: AbstractControl): ValidationErrors {
      return this.form.valid ? null : {invalid: true};
    }
  }
  
  
  @NgModule({
    imports: [ BrowserModule, FormsModule, ReactiveFormsModule ],
    declarations: [ App, NestedControl ],
    bootstrap: [ App ]
  })
  export class AppModule {}
  </code></pre>