【问题标题】:How to work with Dynamic Forms (get values from api for update form) in Angular?如何在 Angular 中使用动态表单(从 api 获取更新表单的值)?
【发布时间】:2018-10-15 14:39:24
【问题描述】:

我有一个组件:,我需要更新一个表单。在初始化时,我正在调度操作以加载详细信息,并订阅了成功操作,我将在其中创建 formControls。我正在从商店获取数据,但我仍然总是收到此错误,所有形式

无法读取未定义的属性“名称”

这是出现上述错误 时表单的外观。 这就是表单的外观,。

我试了好几个小时,但不知道我错了。

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>

提前致谢。

【问题讨论】:

  • 您的订阅者函数中显示的console.log(data) 是什么?
  • 在控制台中,我正在从商店获取正确的数据。 screenshot。但是它在模板中没有正确显示,并且还显示错误(上面已经共享屏幕截图)。

标签: angular angular6


【解决方案1】:

可能是,在 API 调用完成之前加载表单。一旦我们收到 API 响应,创建一个 Flag 并设置为 true。

在模板中,你可以使用 *ngIf 来处理。

<div *ngIf="dataLoaded"></div>

组件:

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}`),
          });
        });
  }

【讨论】:

  • 嗨,苏里亚,感谢您的回复。这就像魅力一样。无法想象解决方案会如此简单。你拯救了我的一天。我做了&lt;form *ngIf="dataLoaded"&gt;&lt;/form&gt; :)
【解决方案2】:

我确定这是因为您在设置 this.formGroup 之前就将 getters 添加到了代码中。这些getters 不会等待您的formGroup 被初始化,而是会调用它们的方法,这最终会在控制台上给您带来错误。

您应该在ngOnInit 中设置表单,然后在其上调用patchValue 方法以使用您从商店获取的数据设置表单的值。

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');
}

【讨论】:

  • 嗨,希德。这是启动表单和传递数据的好方法。从下次开始肯定会遵循这种方式.. 非常感谢。 :)
【解决方案3】:

问题是您的视图需要 formGroup 来呈现 html,但默认情况下为 null 并且仅在订阅者中定义。

最好将表单的创建移到构造函数中(默认使用空字符串)。

     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(''),
      });

然后当订阅被触发时,用新数据修补现有表单:

this.formGroup.get('content_type').patchValue(data.payload.content_type);

这样表格就一直存在。

【讨论】:

    猜你喜欢
    • 2021-09-04
    • 2015-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多