Skip to content

FormGroup & FormControl statusChanges are not emitted on creation #14542

Closed

Description

@MickL

I'm submitting a ...

[X] bug report
[ ] feature request
[ ] support request

Current behavior
FormGroup and FormControl don't emit statusChange after first creation (while untouched / pristine?) with asyncValidator.

  1. Initial status of FormGroup and FormControl is "PENDING"
  2. Both status changes to "VALID" or "INVALID"
  3. statusChange is not emitted

Expected behavior
statusChange should always be emitted.

Minimal reproduction of the problem with instructions

  1. Create a FormGroup with the FormBuilder and add a FormControl with asyncValidator(e.g. with a TimeOut Promise of 2sec).
  2. Subscribe to FormGroup.statusChange or FormGroup.controls.key.statusChange

Angular version
2.4.1

Activity

  1. DzmitryShylovich commented on Feb 16, 2017

    @DzmitryShylovich
    Contributor

    Pls provide a plunkr

  2. MickL commented on Feb 16, 2017

    @MickL
    Author

    https://plnkr.co/edit/BvnnfxHK3mgNVIVI7Yhs?p=preview

    => Emitted status is not set to "VALID" on first validation on init. Only if u start typing the status is emitted correctly.

  3. Toxicable commented on Feb 16, 2017

    @Toxicable

    This is not a bug, the type of statusChanges is an EventEmitter which is a class that extends Subject which does not emit an initial value. If you want it to emit then call the control.updateValueAndValidity() method after subscribing to get the initial value

  4. MickL commented on Feb 16, 2017

    @MickL
    Author

    I know there is no initial value that is fine. But then the status changes from "PENDING" to "VALID" or "INVALID" which is not emitted.

    Thanks for the hint to use updateValueAndValidity(). This updates to "PENDING" but then still the status-change is not emitted as described above and would still be "PENDING". I updated the Plunkr to make the bug more obvious.

  5. MickL commented on Feb 16, 2017

    @MickL
    Author

    I also noticed the async validator is called 4 times on FormBuilder.group(). This would cause 4 server requests.

    I updated my plunker, just check the console.

    Opened another issue for this here: #14551

  6. jackkoppa commented on Jul 11, 2017

    @jackkoppa

    +1 to this. There would seem to be a need to modify angular/packages/forms/src/model.ts, and have statusChanges fire on a change of pending. The plunker linked above properly demonstrates this issue, which I'm also having in my project: no way to tell on initialization of the component whether or not the form has finished its pending status.

  7. RobYed commented on Jul 12, 2017

    @RobYed

    I encounter the same issue. On page load a canActivate method checks the status of my FormGroups. As I have some async validator functions, I have to wait until the status of my FormGroup is not PENDING anymore. This does never happen, due to the above mentioned bug.

    As a workaround, I now dirty check the status (not so cool):

    asyncCanActivate(form: FormGroup): Observable<boolean> {
    
        const result = new Subject();
    
        const interval = setInterval(() => {
          if (form.status === 'VALID') {
            result.next(true);
            result.complete();
            clearTimeout(timeout);
            clearInterval(interval);
          }
        }, PermissionService.STATUS_UPDATE_RATE);
    
        const timeout = setTimeout(() => clearInterval(interval), PermissionService.MAX_UPDATE_INTERVAL);
    
        return result;
    }
    
  8. mikeperri commented on Sep 8, 2017

    @mikeperri

    I worked around this in my async validator by calling the parent control's updateValueAndValidity on the next tick after the asynchronous call completes.

    This causes the parent control (the FormGroup) to emit a VALID status, but it doesn't cause the control itself to emit anything. If you call the control's updateValueAndValidity, that makes the async validator run again, which isn't ideal already, and worse, it creates an infinite loop. So if you need the control itself to emit, not its parent, then this doesn't help much.

      console.log('myAsyncValidator is called!');
      
      return new Promise (resolve => {
        setTimeout(() => {
          console.log('myAsyncValidator finished!')
          setTimeout(() => c.parent.updateValueAndValidity()) // Workaround
          if(c.value != '123') {
            resolve({"isNot123": true});
          }
          else
            resolve(null)
        }, 2500);
      });
    }
    

    Here's a fork of the plunker: https://plnkr.co/edit/QykVJrgM8j3EA51VU9Xl?p=preview

  9. JohnYoungers commented on Oct 4, 2017

    @JohnYoungers

    I guess I also don't know how we're supposed to be handling this:

    I have a directive that in ngOnInit() will subscribe to statusChanges, and when the state switches between Valid/Invalid it'll render the validation message appropriately.

    This has been working fine since the async validator runs as the user changes the fields; however, I've run into a situation where I'm async validating fields as they're created in the form group (the form is created based on an existing object that may be invalid).

    In my directive I can see the initial state of the control is 'PENDING', but once that completes my statusChanges subscription is not hit: is the only resolution to do some sort of setTimeout hack if it's initially pending and wait for that to complete?

    edit

    Here's my workaround for now:

               this.formControl.statusChanges.subscribe((a) => {
                    this.statusChanged(a);
                });
    
                //TODO: remove this at some point
                if (this.formControl.pending) {
                    let setInitialStatus = () => {
                        if (this.formControl.pending) {
                            t = setTimeout(setInitialStatus, 50);
                        } else {
                            this.statusChanged(this.formControl.valid ? 'VALID' : 'INVALID');
                            clearTimeout(t);
                        }
                    };
    
                    let t = setTimeout(setInitialStatus, 50);
                }
    
  10. kiancross commented on Jan 4, 2018

    @kiancross

    Any update on this?

  11. added this to the Backlog milestone on Jan 24, 2018
  12. 10 remaining items

  13. pburgmer commented on May 6, 2020

    @pburgmer
    Contributor

    I also have this problem.
    Dear Angular team, could you please fix it 😍

    The original plunkr doesn't work anymore. I copied the code to a new stackblitz: https://stackblitz.com/edit/angular-tv8yss

  14. AndrewKushnir commented on Jun 18, 2020

    @AndrewKushnir
    Contributor

    Hi, it looks like this issue is related to #20424 and might be fixed by #20806. Thank you.

  15. johnwcb commented on Jul 9, 2020

    @johnwcb

    I have similar issue when user does not input anything and click submit button, my validators do not fire error messages when the message component is relying on listening the input's statusChanges.

    My solution is calling the following function when the submit button is clicked, and it works:

        validateAllFields(formGroup: FormGroup) {
            Object.keys(formGroup.controls).forEach(field => {
                const control = formGroup.get(field);
                if (control instanceof FormControl) {
                    control.markAsTouched({ onlySelf: true });
                    control.updateValueAndValidity();
                }
            });
        }
    
  16. nicolasguilhem commented on Sep 1, 2020

    @nicolasguilhem
  17. added a commit that references this issue on Sep 5, 2020
    bae9668
  18. angular-automatic-lock-bot commented on Oct 2, 2020

    @angular-automatic-lock-bot

    This issue has been automatically locked due to inactivity.
    Please file a new issue if you are encountering a similar or related problem.

    Read more about our automatic conversation locking policy.

    This action has been performed automatically by a bot.

  19. locked and limited conversation to collaborators on Oct 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions