Как правильно настроить реактивный элемент выбора, который использует вложенную группу форм? - PullRequest
0 голосов
/ 05 июня 2018

У меня есть проект Angular 6, Reactive Forms, который подключается к серверной части ASP.NET Web Api 2 / MS SQL Server 2017.Я нахожусь в процессе подключения внешнего интерфейса и столкнулся с ситуацией, с которой я еще не сталкивался, и не могу найти примеры того, как это сделать:

Вложенные группы FormGroups , чьим объектом являетсяпредставлен элементом select.То, что я имею до сих пор, не является ошибкой, и, по-видимому, он выбирает правильный элемент в раскрывающемся списке при загрузке.Однако после выбора только обновляет одно поле, а не весь объект.

I думаю Мне нужно использовать formGroupName="company", чтобы сообщить registerOnChange(), какой элемент управленияискать и затем какую-то форму formControlName="...", но я не понимаю, как это сделать с элементами select или option, чтобы добиться того, что я ищу.Мне нужен выбор для обновления всего объекта, а также свойств идентификатора и имени.

Нажмите здесь, чтобы просмотреть редактор StackBlitz / демонстрационную версию

site-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>

site-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 голосов
/ 06 июня 2018

Я решил это, следуя Angular SetControlValueAccessor Пример на основе модели, где он использует идентификатор объекта для выбора опции.

Нажмите здесь, чтобысм. демонстрацию StackBlitz

Я удалил formGroupName="company" из div-оболочки, использовал 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. Удалите присвоение FormGroup company: this.fb.group({ id: null, name: ''}) и замените его на company: null.
  2. Реализация функции compareWith. Необходим, потому что сравнение по умолчанию использует идентичность объекта и разные объекты имеют разные идентификаторы.Вы можете переопределить этот метод своей собственной реализацией, чтобы определить уникальность.

См. Ниже:

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;
}
0 голосов
/ 06 июня 2018

, так как существует много кода для подключения, я считаю, что это то, что вам нужно,

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

Обновление

Приведенное выше решение является правильным, но вам нужно внести некоторые измененияв вашем стеке, я исправил это для вас, пожалуйста посмотрите this

  1. [ngValue] = "company.id"
  2. formControlName = "id"
  3. в вашем коде ts this.siteForm.patchValue вместо setValue

обратите внимание, что название компании не будет обновляться, если вам нужно изменить название компании, а также вы должны подписаться на изменениесобытие и измените либо свою форму, либо измените site объект и форму патча снова

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...