Reputation: 1120
I have a Component:, where i need to update a form. On init, i am dispatching action to load the detail, and subscribed to success-action, where i will create formControls. I am getting the data from store, but still i always get this error, in all the forms:
Cannot read property 'name' of undefined
This is how the form looks when there is the above error, . And this is how the form should be looking, .
I tried for many hours but could not figure wIere i was going wrong.
component.ts
formGroup: FormGroup;
ngOnInit() {
this.store.dispatch(new fromCourse.LoadCardDetails());
this.actionsSubject$
.pipe(filter(action => action.type === CourseActionTypes.LOAD_CARD_DETAILS_SUCCESS))
.subscribe((data: {type, payload: ICardContent } ) => {
this.formGroup = new FormGroup({
name: new FormControl(`${data.payload.name}`, []),
content_type: new FormControl(`${data.payload.content_type}`),
actual_content: new FormControl(`${data.payload.actual_content}`),
content_url: new FormControl(`${data.payload.content_url}`),
additional_content: new FormControl(`${data.payload.additional_content}`),
media_type: new FormControl(`${data.payload.media_type}`),
media_source: new FormControl(`${data.payload.media_source}`),
language_id: new FormControl(`${data.payload.language_id}`),
thumbnail: new FormControl(`${data.payload.thumbnail}`),
});
});
}
get content_type () { return this.formGroup.get('content_type'); }
get name () { return this.formGroup.get('name'); }
get actual_content () { return this.formGroup.get('actual_content'); }
get content_url () { return this.formGroup.get('content_url'); }
get additional_content () { return this.formGroup.get('additional_content'); }
get media_type () { return this.formGroup.get('media_type'); }
get media_source () { return this.formGroup.get('media_source'); }
get language_id () { return this.formGroup.get('language_id'); }
get thumbnail () { return this.formGroup.get('thumbnail'); }
component.html
<form novalidate class="mainForm" [style.fontSize.px]="15" [formGroup]="formGroup">
<div>
<h3 class="sHeading"> Form Type </h3>
<mat-form-field appearance="fill" class="formField">
<mat-select placeholder="Select Type" formControlName="content_type">
<mat-option
#formType
class="option"
*ngFor="let type of types"
[value]="type"
(click)="updateFormType(formType.value)">
{{type}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div>
<h3 class="sHeading"> Name </h3>
<mat-form-field appearance="outline" class="formField">
<input matInput
placeholder="Name should have 3 characters min."
formControlName="name">
</mat-form-field>
</div>
<div>
<h3 class="sHeading"> Content </h3>
<mat-form-field appearance="outline" class="formField">
<textarea
matInput
placeholder="Describe the content"
rows=6
formControlName="actual_content"></textarea>
</mat-form-field>
</div>
<div class="button-container">
<button mat-raised-button type="submit" class="submitBtn" (click)="onSubmit(formGroup.value)">Update Form</button>
</div>
</form>
Thanks in advance.
Upvotes: 0
Views: 1499
Reputation: 39432
I'm sure it's because you're adding get
ters to your code before even setting the this.formGroup
. These get
ters will not wait for your formGroup
to be initialized and will call methods on them which would end up giving you errors on the console.
You should set the form in ngOnInit
and then call the patchValue
method on it to set the value of the form with the data that you're getting from your store.
formGroup: FormGroup;
ngOnInit() {
this.formGroup = new FormGroup({
name: new FormControl(),
content_type: new FormControl(),
actual_content: new FormControl(),
content_url: new FormControl(),
additional_content: new FormControl(),
media_type: new FormControl(),
media_source: new FormControl(),
language_id: new FormControl(),
thumbnail: new FormControl(),
});
this.store.dispatch(new fromCourse.LoadCardDetails());
this.actionsSubject$
.pipe(filter(action => action.type === CourseActionTypes.LOAD_CARD_DETAILS_SUCCESS))
.subscribe((data: {
type,
payload: ICardContent
}) => {
this.formGroup.patchValue(data.payload);
});
}
get content_type() {
return this.formGroup.get('content_type');
}
get name() {
return this.formGroup.get('name');
}
get actual_content() {
return this.formGroup.get('actual_content');
}
get content_url() {
return this.formGroup.get('content_url');
}
get additional_content() {
return this.formGroup.get('additional_content');
}
get media_type() {
return this.formGroup.get('media_type');
}
get media_source() {
return this.formGroup.get('media_source');
}
get language_id() {
return this.formGroup.get('language_id');
}
get thumbnail() {
return this.formGroup.get('thumbnail');
}
Upvotes: 1
Reputation: 364
The problem is that your view needs the formGroup to render the html but that is null by default and only defined in the subscriber.
You better move the creation of the form to the constructor (use empty strings by default).
constructor(){
this.formGroup = new FormGroup({
name: new FormControl('', []),
content_type: new FormControl(''),
actual_content: new FormControl(''),
content_url: new FormControl(''),
additional_content: new
FormControl(''),
media_type: new FormControl(''),
media_source: new FormControl(''),
language_id: new FormControl(''),
thumbnail: new FormControl(''),
});
Then when the subscription is triggered patch the existing form with new data:
this.formGroup.get('content_type').patchValue(data.payload.content_type);
In this way the form always exists.
Upvotes: 0
Reputation: 9764
Might be, Form is getting loaded before the API call is getting completed. Create a Flag and set to true once we receive API response.
In Template, you can handle using *ngIf.
<div *ngIf="dataLoaded"></div>
Component:
dataLoaded = false;
ngOnInit() {
this.store.dispatch(new fromCourse.LoadCardDetails());
this.actionsSubject$
.pipe(filter(action => action.type === CourseActionTypes.LOAD_CARD_DETAILS_SUCCESS))
.subscribe((data: {type, payload: ICardContent } ) => {
this.dataLoaded = true;
this.formGroup = new FormGroup({
name: new FormControl(`${data.payload.name}`, []),
content_type: new FormControl(`${data.payload.content_type}`),
actual_content: new FormControl(`${data.payload.actual_content}`),
content_url: new FormControl(`${data.payload.content_url}`),
additional_content: new FormControl(`${data.payload.additional_content}`),
media_type: new FormControl(`${data.payload.media_type}`),
media_source: new FormControl(`${data.payload.media_source}`),
language_id: new FormControl(`${data.payload.language_id}`),
thumbnail: new FormControl(`${data.payload.thumbnail}`),
});
});
}
Upvotes: 1