Skip to content

Forms: NgControlStatus directive won't update if in ChangeDetectionStrategy.OnPush #11563

@fank

Description

@fank

I'm submitting a ... (check one with "x")

[x] bug report => search github for a similar issue or PR before submitting
[ ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Not sure if bug or feature.

Current behavior
If you create following:

@Component ("A")
- @Component ("B", with changeDetection: ChangeDetectionStrategy.OnPush)
-- [formControl] (directive on input or something else)

Create a FormGroup in "A" and pass the FormControl through "B" to the <input>.
Now change the value if the FormControl by using setValue or similar, the NgControlStatus directive on the <input> will not be triggered by change detection. And the input will show the old "state" (i.E. invalid) but the new "state" (i.E. valid) isn't shown (Old classes will are still there).

Expected behavior
Create a FormGroup in "A" and pass the FormControl through "B" to the <input>.
Now change the value if the FormControl by using setValue or similar, the NgControlStatus directive on the <input> will not be triggered. And the input will show the new "state" (i.E. valid).

Reproduction of the problem
http://plnkr.co/edit/JlOOqXSqjXbw8BC2xyav?p=preview

What is the motivation / use case for changing the behavior?
We have about 200-500 components on one page at the same time, to ensure everything works smooth. We need to control the changedetection on our self.
Currently we created a workaround and cloned the existing NgControlStatus directive and added a listener on FormControl.statusChanges to ensure the right classes will be shown on the <input> element, it would be nice if angular could do that.
Here our directive:

import {ChangeDetectorRef, Directive, HostBinding, OnInit, Self} from '@angular/core';
import {NgControl} from '@angular/forms';

import {isPresent} from '@angular/common/src/facade/lang';

@Directive({
    selector: '[formControlName],[ngModel],[formControl],[formControlDummy]',
})
export class NxControlStatusDirective implements OnInit {
    private _cd: NgControl;

    constructor(
        @Self() cd: NgControl,
        private _cdRef: ChangeDetectorRef
    ) {
        this._cd = cd;
    }

    public ngOnInit(): void {
        this._cd.control.statusChanges.subscribe(() => {
            this._cdRef.markForCheck();
        });
    }

    @HostBinding('class.ng-untouched') public get ngClassUntouched(): boolean {
        return isPresent(this._cd.control) ? this._cd.control.untouched : false;
    }

    @HostBinding('class.ng-touched') public get ngClassTouched(): boolean {
        return isPresent(this._cd.control) ? this._cd.control.touched : false;
    }

    @HostBinding('class.ng-pristine') public get ngClassPristine(): boolean {
        return isPresent(this._cd.control) ? this._cd.control.pristine : false;
    }

    @HostBinding('class.ng-dirty') public get ngClassDirty(): boolean {
        return isPresent(this._cd.control) ? this._cd.control.dirty : false;
    }

    @HostBinding('class.ng-valid') public get ngClassValid(): boolean {
        return isPresent(this._cd.control) ? this._cd.control.valid : false;
    }

    @HostBinding('class.ng-invalid') public get ngClassInvalid(): boolean {
        return isPresent(this._cd.control) ? !this._cd.control.valid : false;
    }
}

Please tell us about your environment:

  • Angular version: 2.0.0-rc.7

  • Browser: [all]

  • Language: [all]

  • Node (for AoT issues): node --version = 6.5.0

/cc @kara

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions