如何正确配置使用嵌套表单组的反应性选择元素?

时间:2018-06-05 20:53:54

标签: angular angular-reactive-forms angular6

我有一个Angular 6,Reactive Forms项目,它连接到ASP.NET Web Api 2 / MS SQL Server 2017后端。我正在连接前端,遇到了一个我还没有遇到的情况,找不到如何完成的例子:

Nested FormGroups,其对象由select元素表示。到目前为止,我没有错误,它似乎在加载时下拉列表中选择了正确的项目。但是,在选择时,更新一个字段而不是整个对象。

我需要使用formGroupName="company"告诉registerOnChange()要查找哪个控件,然后使用某种形式的formControlName="...",但我不明白如何使用selectoption元素来实现我正在寻找的东西。我需要一个选择来更新整个对象,包括id和name属性。

Click here to view the StackBlitz editor/demo

站点edit.component.html

...
<form class="form-horizontal" novalidate (ngSubmit)="save()" [formGroup]="siteForm">
  <fieldset>
    ...
    <div class="form-group" formGroupName="company">
      <label class="col-md-2 control-label" for="companyId">Company</label>
      <div class="col-md-8">
        <select id="companyId" class="form-control" formControlName="company">
          <option *ngFor="let company of companies" [ngValue]="company.name">
            {{ company.name }}
          </option>
        </select>
      </div>
    </div>
    ...
  </fieldset>
</form>

站点edit.component.ts

siteForm: FormGroup;

// TODO: refactor to use http Company Service instead
companies: Company[] = [
  { id: 1, name: 'Company 1'},
  { id: 2, name: 'Company 2'},
  { id: 3, name: 'Company 3'}
];
site: Site;

constructor(private fb: FormBuilder,
            private siteService: SiteService) { }

ngOnInit(): void {
  this.siteForm = this.fb.group({
    ...
    company: this.fb.group({
      id: null,
      name: ''
    }),
    ...
  });
}

getSite(id: number): void {
  this.siteService.getSite(id)
    .subscribe(site => this.onSiteRetrieved(site));
}

save(): void {
  if (this.siteForm.dirty && this.siteForm.valid) {
    // copy form values over the site object values
    const s = Object.assign({}, this.site, this.siteForm.value);

    // simulate call to save service
    console.log('Saved: ' + JSON.stringify(s));
  }
}

onSiteRetrieved(site: Site): void {
  // clear all the state flags (dirty, touched, etc.)
  if (this.siteForm) {
    this.siteForm.reset();
  }
  this.site = site;

  // update the data on the form
  this.siteForm.setValue({
    ...
    company: {
      id: this.site.company.id,
      name: this.site.company.name
    },
    ...
  });
}  

... more

2 个答案:

答案 0 :(得分:1)

因为有很多代码需要连接,我相信这就是你需要的,

<select formControlName="id">
    <option *ngFor="let company of companies" [ngValue]="company.id">{{country.name}}</option>
  </select>

更新

上述解决方案是正确的,但您需要对stackblitz进行一些更改,我已经为您修好了,请查看this

  1. [ngValue] = “company.id”
  2. formControlName = “ID”
  3. 您的密码this.siteForm.patchValue中的
  4. 代替setValue
  5. 请注意公司名称不要更新,如果您需要更改公司名称,您必须订阅更改活动并更改表单或更改site对象和补丁表格

答案 1 :(得分:0)

我已经按照Angular的SetControlValueAccessor模型驱动示例解决了这个问题,它使用对象标识来选择选项。

<强> Click here to see StackBlitz demo

我从包装div中删除formGroupName="company",在整个对象formControlName="company"上使用select,然后在[ngValue]="company"上使用option也是整个对象。

见下文:

<div class="form-group">
  <label class="col-xs-2 control-label" for="companyId">Company</label>
  <div class="col-xs-8">
    <select id="companyId" 
            class="form-control" 
            formControlName="company"
            [compareWith]="compareCompanies">
      <option *ngFor="let company of companies" [ngValue]="company">
        {{ company.name }}
      </option>
    </select>
  </div>
</div>

我需要在课堂上做出的唯一改变是:

  1. 删除company: this.fb.group({ id: null, name: ''})的FormGroup分配,并将其替换为company: null
  2. 实施compareWith功能。 需要,因为默认比较使用对象标识,不同的对象具有不同的标识。您可以使用自己的实现覆盖此方法以确定唯一性。
  3. 见下文:

    ngOnInit(): void {
    
      this.siteForm = this.fb.group({
        name: ['', Validators.required],
        company: null
      });
    
      ...
    
    }
    
    compareCompanies(c1: Company, c2: Company): boolean {
      return c1 && c2 ? c1.id === c2.id : c1 === c2;
    }