Angular 5 + Angular Material Select + Reactive Forms == 没有初始选项显示

14

正如标题所述,我有一个反应式表单,其中包含多个<mat-select>。在初始加载表单时,即使form.value显示了它,初始选项也没有显示。

相关组件.ts:

export class DesJobInfoEditComponent implements OnInit {

...

currentJobData: IJob;
jobTypes: IJobType[];

...

constructor(private fb: FormBuilder) {

    ...

        // Construct forms
        this.createForm();

        this.initializeForm();

}

createForm() {
    this.editJobInfoForm = this.fb.group({
        ...
        JobType: '', // mat-select
        ...
    });
}

initializeForm() {
    this.rebuildForm();
}

rebuildForm() {
    this.editJobInfoForm.reset({
        ...
        JobType: this.jobTypes[this.currentJobData.JobType].DisplayDesc,
        ...
    });
}

<mat-form-field fxFlex>
      <mat-label>Job Type</mat-label>
       <mat-select formControlName="JobType" placeholder="Job Type">
              <mat-option *ngFor="let jobType of jobTypes" value="jobType.value">
                     {{ jobType.DisplayDesc }}
               </mat-option>
        </mat-select>
  </mat-form-field>
当表单加载时,选择框不会显示最初选定的选项,但是它们已经被正确地设置了。
Form value { ... "JobType": "0 - Standard", ... } 

表单上显示的只是占位符。

这似乎不应该这么困难。

我做错了什么?

编辑:

this.jobTypes 在模块加载时被加载,它是一个 BehaviorSubject,存在于我的数据服务中。 我在此组件的构造函数中进行订阅:

this.data.jobTypes.subscribe(jobTypes => { this.jobTypes = jobTypes });


也许你需要使用管道异步操作?let jobType of jobTypes | async - Tin
你是怎么加载jobTypes的?我没有看到填充this.jobTypes的代码。 - Stanton
@Stanton,我已经更新了我的问题。 - OCDDev
你有关于这个的任何更新吗?我遇到了完全相同的问题... 当我改成一个简单的HTML选择器时,一切都正常运行... - Victor Carvalho
4个回答

13

几件事情:

  1. [formControlName] 必须与 [formGroup] 搭配使用。如果你不想使用 [formControlName] + [formGroup],可以使用 [formControl] 替代。

  2. 在 Angular 中,将属性指定为 value[value] 是有区别的。当一个属性被方括号 [] 包围时,它会被解释为 Angular 模板脚本(与 {{}} 相同,我想)。而当它没有被包围时,它会被解释为字符串(例如,value="jobType.value" 等同于 [value]="'jobType.value'"[value]="jobType.value" 等同于 value="{{jobType.value}}" (实际上我认为 [value]="jobType.value"value="{{jobType.value}}" 之间有微小的差异,但随便了)。所以当你写成 <mat-option *ngFor="let jobType of jobTypes" value="jobType.value"> 的时候,每个 mat-option 的值都是 "jobType.value",这可能不是你想要的。因此你需要将代码更改为 <mat-option *ngFor="let jobType of jobTypes" [value]="jobType.value">

例如:

<mat-form-field [formGroup]='editJobInfoForm' fxFlex>
  <mat-label>Job Type</mat-label>
  <mat-select formControlName="JobType" placeholder="Job Type">
    <mat-option *ngFor="let jobType of jobTypes" [value]="jobType.value">
      {{ jobType.DisplayDesc }}
    </mat-option>
  </mat-select>
</mat-form-field>

与您的问题有些无关,为什么要同时拥有createForm()initializeForm()这两个方法呢?为什么不简单地

constructor(private fb: FormBuilder) {

    ...

        // Construct forms
        this.createForm();    
}

createForm() {
    this.editJobInfoForm = this.fb.group({
        ...
        JobType: this.jobTypes[this.currentJobData.JobType].DisplayDesc,
        ...
    });
}

解释得非常清楚 - 我的赞美! - Jan

7

Angular Material 的 compareWith 方法:(o1: any, o2: any) => boolean (来自 Angular Material 选择框的 API 参考)

component.ts

 export class ParentOneComponent implements OnInit {
  materialFormSample: FormGroup;
  constructor() { }

  ngOnInit() {
    this.configureMaterialFormSample();
  }
  name: string = 'Emilius Patrin Mfuruki';
  toppingList: string[] = ['Extra cheese', 'Mushroom', 'Onion', 'Pepperoni', 'Sausage', 'Tomato'];
  selectedToppingList = ['Extra cheese', 'Tomato', 'Onion'];

  compareWithFunc = (a: any, b: any) => a == b;

  configureMaterialFormSample() {
    this.materialFormSample = new FormGroup({
      name: new FormControl(this.name),
      toppings: new FormControl(this.selectedToppingList)
    })
  }
  onSubmitForm() {
    if (this.materialFormSample.valid) {
      console.log('submitting Form Content Valid', this.materialFormSample.value);
    }
  }
}

component.html

<form [formGroup]="materialFormSample" (ngSubmit)="onSubmitForm()" autocomplete="off">
      <mat-form-field class="w-100">
        <input matInput placeholder="Name" formControlName="name">
      </mat-form-field>
      <mat-form-field class="w-100">
        <mat-label>Toppings</mat-label>
        <mat-select formControlName="toppings" multiple [compareWith]="compareWithFunc">
          <mat-option *ngFor="let topping of toppingList" [value]="topping">{{topping}}</mat-option>
        </mat-select>
      </mat-form-field>
      <div class="clearfix">
        <button type="submit" mat-raised-button color="primary" class="float-right">Submit Form</button>
      </div>
    </form>

4

使用原样的compareWith函数…

步骤1:按照如下格式添加[compareWith]标签

<mat-form-field>
  <mat-select placeholder="Pick item..." formControlName="selectedItem" 
    [compareWith]="compareFn">
    <mat-option *ngFor="let item of items">
        {{item.name}}
    </mat-option>
  </mat-select>
</mat-form-field>
<button (click)="changeValue()">Change value</button>

步骤2:声明变量compareFn和函数compareByValue,如下所示,无需更改。
compareFn: ((f1: any, f2: any) => boolean) | null = this.compareByValue;

compareByValue(f1: any, f2: any) { 
  return f1 && f2 && f1.name === f2.name; 
}

2
嗨,我知道可能有点晚了,但我知道一个更简单的解决方案。您的UI(HTML)组件已经正确描述了。
在您的TypeScript中,您正在将对象与字符串进行比较,这不会产生任何验证。因此,在验证时始终将对象与null进行比较。
简单地说
``` createForm() { this.editJobInfoForm = this.fb.group({ ... JobType: [null], // mat-select ... }); } ``` 将 JobType: '' 替换为 JobType:[null]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接