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.
userponent.html
<form [formGroup]="form">
<input type="text" id="name" formControlName="name" />
<input type="text" id="age" formControlName="age" />
</form>
userponent.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
This is an easier way to understand my problem
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.ponent.html
<form [formGroup]="form">
<input type="text" id="name" formControlName="name" />
<input type="text" id="age" formControlName="age" />
</form>
user.ponent.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
Share Improve this question edited Apr 26, 2018 at 19:38 Muhammad Kashif Nazar asked Apr 26, 2018 at 18:25 Muhammad Kashif NazarMuhammad Kashif Nazar 23.9k5 gold badges34 silver badges46 bronze badges 11- Not is clear to me. You're trying to disable the submit until all the inputs are pleted? – Jonathan Brizio Commented Apr 26, 2018 at 18:35
- What is your angular version? – Reza Commented Apr 26, 2018 at 18:41
- Can you make a plunker or ... for it – Reza Commented Apr 26, 2018 at 18:41
- This is Angular 4. I can try to make a plunker for it. – Muhammad Kashif Nazar Commented Apr 26, 2018 at 18:58
- In your headline you've written Angular 2, haven't you @KashifNazar? – Michael W. Czechowski Commented Apr 26, 2018 at 18:59
4 Answers
Reset to default 5You just need enable/disable methods of form control.
Here is stackblitz example. It works perfectly.
@Component({
selector: 'my-app',
templateUrl: './app.ponent.html',
styleUrls: [ './app.ponent.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']();
}
}
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.ponent.html
<form [formGroup]="form" (submit)="_updateForm()">
<input type="text" id="name" fromControlName="name" />
<input type="text" id="age" fromControlName="age" />
</form>
user.ponent.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);
});
}
- Create the
formGroup
directly inngOnit
w/controls disabled by default so you're sure it exists w/o worrying about async issues. - In
this._route.queryParams.subscribe(...)
you can usethis.form.setValue({//set all control values})
orthis.form.patchValue({//set individual controls})
to update the individual controls as needed/once available. - Use ponent instance variables for
condition
andsomeOtherCondition
(or auser
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 accessuser
data model directly.
This way your controls and formGroup exist, and are disabled, until the async data is available.
<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