9

I am having trouble enabling and disabling a form controls in my application. It is probably because the form is being enabled/disabled in an asynchronous context.

Here is how the code is.

user.component.html

<form [formGroup]="form">
    <input type="text" id="name" formControlName="name" />
    <input type="text" id="age" formControlName="age" />
</form>

user.component.ts

ngOnInit() {

     this._route.queryParams.subscribe(params => {
            getUser(params.userId).subscribe(user => {
                 this._buildForm(user);
            })
     });
}

private _buildForm(user){
    this.form = _fb.group({
        name: [{value: user.name, disabled: user.someCondition}, Validators.required],
        age: [{value: user.age, disabled: user.anotherCondition}, Validators.required]
    })
}    

When the first time the user is loaded upon param change, the controls do get enabled/disabled on the basis of their relevant conditions. When the params change subsequently, the state of the controls remain the same although the values are set appropriately.

I have tried different ways to fix this but no help. For example, I have tried the following at the end of the _buildForm method.

this.form.disable() //Doesn't do anything

this.form.controls.name.disable(); //Doesn't help

One thing that does work as expected is the following (but this isn't what is required).

<button (click)="form.disable()" value="Disable Form" />
<button (click)="form.enable()" value="Enable Form" />

What I feel is that the problem is due the fact the _buildForm() is being called from the asynchronous context (subscribe method).

How can I fix this problem?

UPDATE

Please note that the Observable subscription is triggered on the basis of the navigation as below.

this._router.navigate([], {
   relativeTo: this._route,
   queryParams: {userId: 10}
})

UPDATE 2 https://angular-cvf1fp.stackblitz.io

This is an easier way to understand my problem

11
  • Not is clear to me. You're trying to disable the submit until all the inputs are completed? Commented Apr 26, 2018 at 18:35
  • What is your angular version? Commented Apr 26, 2018 at 18:41
  • Can you make a plunker or ... for it Commented Apr 26, 2018 at 18:41
  • This is Angular 4. I can try to make a plunker for it. Commented Apr 26, 2018 at 18:58
  • In your headline you've written Angular 2, haven't you @KashifNazar? Commented Apr 26, 2018 at 18:59

4 Answers 4

5

You just need enable/disable methods of form control.

Here is stackblitz example. It works perfectly.

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  group;
  isDisabled = true;

  constructor(fb: FormBuilder) {
    this.group = fb.group({
      stuff: fb.control({value: 'stuff', disabled: this.isDisabled})
    });
  }

  toggle() {
    this.isDisabled = !this.isDisabled;

    this.group.controls.stuff[this.isDisabled ? 'enable' : 'disable']();
  }
}
Sign up to request clarification or add additional context in comments.

10 Comments

Thanks for the answer but the problem is that I am trying to toggle from the subscribe method. If I have a button in the UI, that can easily enable/disable the component. Let me try to modify the example.
Do you have ChangeDetectionStrategy set up?
No. I don't have
I updated to the subscribe. It works. Even with ChangeDetectionStrategy.OnPush.
Ok then just provide repro on stackblitz. We will fix it easily then.
|
2

You're right. The subscription is only fired once, so after submitting the form the user entity does not change anymore. To do it, add for instance an event handler to your form submit.

user.component.html

<form [formGroup]="form" (submit)="_updateForm()">
    <input type="text" id="name" fromControlName="name" />
    <input type="text" id="age" fromControlName="age" />
</form>

user.component.ts

private userId: any;


ngOnInit() {
    this._route.queryParams.subscribe(params => {
        this.userId = params.userId;
        this._updateForm();
    });
}

private _buildForm(user){
    this.form = _fb.group({
        name: [{value: user.name, disabled: user.someCondition}, Validators.required],
        age: [{value: user.age, disabled: user.anotherCondition}, Validators.required]
    });
} 

// The update function has to be public to be called inside your template
public _updateForm(){
    getUser(this.userId).subscribe(user => {
        this._buildForm(user);
    });
}    

1 Comment

Thanks for your answer. The subscribe method does fire multiple times whenever there is a change in the params. (userId)
2
  • Create the formGroup directly in ngOnit w/controls disabled by default so you're sure it exists w/o worrying about async issues.
  • In this._route.queryParams.subscribe(...) you can use this.form.setValue({//set all control values}) or this.form.patchValue({//set individual controls}) to update the individual controls as needed/once available.
  • Use component instance variables for condition and someOtherCondition (or a user object as a whole if you want to separate your data model from the form's model - they don't have to be the same). Initialize these to "false", and refer to them instead for enabling/disabling the controls in the formGroup creation. You can also update those variables in the same .subscribe() block once the user data is in place, instead of waiting to access user data model directly.

This way your controls and formGroup exist, and are disabled, until the async data is available.

Comments

1
<form [formGroup]="form">
    <input type="text" id="name" fromControlName="name" />
    <input type="text" id="age" fromControlName="age" />
</form>

do you see a typo here?fromControlName should be formControlName After that change toggling will work ;)

https://angular-rivxs5.stackblitz.io

1 Comment

Nice catch. This typo isn't there in the code. It's just here. Let me correct it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.