Angular 2 with async form field validation
<p>I am trying to validate a field with synchronous and async validation. There is a problem occuring when the field changes before the async validation ends. If after changing the validation returns an error (the field is invalid), but there is still an async validation running (from a previous value), and the async validation return after that, the field becomes valid again, but should stay invalid.</p>

<hr>

<p><strong>Plunker</strong></p>

<p>I created a plunker to show this occurrence: <a href="http://plnkr.co/edit/q0jttO" rel="nofollow">http://plnkr.co/edit/q0jttO</a></p>

<p>The plunker code that create the FormGroup (using the new forms) with the validators is:</p>

<pre class="lang-js prettyprint-override"><code>this.formGroup = formBuilder.group({
    id: [''],
    name: [
        '', 
        (c: AbstractControl) =&gt; (c.value != null &amp;&amp; c.value.length &gt;= 3) ? null : {
            key: 'name_minlength', 
            msg: 'The name must have at least 3 characters'
        }
    ],
    email: [
        '', 
        (c: AbstractControl) =&gt; {
            if (c.value != null &amp;&amp; c.value.length !== 4) {
                console.log('sync - success -&gt; ' + c.value);

                return null; // OK
            } else {
                console.log('sync - error -&gt; ' + c.value);

                return {
                    key: 'email_4char', 
                    msg: 'The email must not have 4 characters'
                };
            }
        },
        (c: AbstractControl) =&gt; new Promise(
            resolve =&gt; {
                console.log('async started -&gt; ' + c.value);

                setTimeout(() =&gt; {
                    if (c.value !== 'aaa') {
                        console.log('async ended - success -&gt; ' + c.value);

                        resolve(null); //OK
                    } else {
                        console.log('async ended - error -&gt; ' + c.value);

                        resolve({
                            key: 'email_aaa', 
                            msg: 'The email must be different than "aaa"'
                        });
                    }
                }, 2000)
            }
        )
    ]
});
</code></pre>

<p>I don't know if this something that I forgot to do or that I did wrong, or if it's a problem of angular 2 (after all, it's still in beta). </p>

<hr>

<p><strong>Steps to Simulate</strong></p>

<p>I made the steps to simulate this problem simple making the validation give an async error if <code>aaa</code> is typed and a sync error if <code>aaaa</code> is typed.</p>

<p>You can reproduce these steps in the plunker (you can see the logs of the validations in the browser console):</p>

<ol>
<li>Typing <code>aa</code> in the email field (the field is valid).</li>
<li>Then you type another <code>a</code> and wait for the validation (the async
validation will show an error).</li>
<li>Then type another <code>a</code> (becoming <code>aaaa</code>), and the sync validation
will show an error (until now it's alright, but wait).</li>
<li>Delete the last 2 <code>a</code>s to become <code>aa</code> again.</li>
<li>Type 1 <code>a</code> and then another <code>a</code> before the validation end.</li>
</ol>

<p><strong>The error message from the validation with <code>aaaa</code> will show, but then the async validation will end and the message will disappear.</strong></p>

<hr>

<p><strong>Logs</strong></p>

<p>Sync Validation where email must not have 4 characters (just for example purposes) and an error message must be shown:</p>

<p>1) Shows the error (console logs when typing slowly):</p>

<pre><code>sync - success -&gt; aaa
async started -&gt; aaa
async ended - error -&gt; aaa
sync - error -&gt; aaaa
</code></pre>

<p>2) Shows the error, but then hide it after the previous async call return with success (console logs when typing faster):</p>

<pre><code>sync - success -&gt; aaa
async started -&gt; aaa
sync - error -&gt; aaaa
async ended - success -&gt; aaaa
</code></pre>

<p>It's not only the error not showing, but the class also stays as ng-valid (should be invalid, the error is not shown because of it).</p>

<p>This also occurs if I change the async validator to only return valid (resolve with <code>null</code>), because what happens is that the async return from the previous value changes the validation result of the last value typed (this shouldn't happen; only the validations related to the last value should define its validity):</p>

<pre class="lang-js prettyprint-override"><code>resolve =&gt; {
    console.log('async started -&gt; ' + c.value);

    setTimeout(() =&gt; {
        console.log('async ended -&gt; ' + c.value);
        resolve(null); //OK
    }, 2000)
}
</code></pre>

<p><strong>Is there a way to make the field stay invalid even if the async validation from a previous value ends after a validation error from the last value typed?</strong></p>