В Angular связывание с FormGroup (вместо «реальной модели») - плохая практика? - PullRequest
0 голосов
/ 12 февраля 2019

У меня есть образец реактивной формы со следующей структурой:

- id
- firstName
- lastName
- siblings
  - id
  - firstName
  - lastName

Siblings - это массив, представленный дочерними компонентами.Я протестировал два метода привязки parent / children:

1) Использование FormGroup

<app-child *ngFor="let sibling of form.get('siblings').controls" [formGroup]="sibling"></app-child>

2) Использование «реальной модели»

<app-child *ngFor="let sibling of model.siblings; let i = index;" [model]="sibling" (changed)=updateSiblingModel($event,i)>

Оба работали нормально.У меня вопрос: один подход считается превосходящим другой?

Реактивные формы имеют отношение почти 1: 1 к реальной модели (получено this.form.value) плюс некоторые интересные преимущества, такие каккак каскадные валидаторы и события.Это работает очень хорошо, но я чувствую, что извлекаю «слишком много логики / структуры» из дочернего компонента во внешний компонент.

Привязка к модели также работает нормально, но у меня больше проводки дляdo (например, (changed)=updateSiblingModel($event,i), но я чувствую, что это немного более сплоченно.

Вот полный пример, сравнивающий 2 стратегии:

https://stackblitz.com/edit/angular-form-binding

Я не знаюУ меня большой опыт работы с большими проектами Angular, поэтому мне также интересно, масштабируется ли какой-либо подход лучше, чем другой.

Спасибо

Ответы [ 3 ]

0 голосов
/ 12 февраля 2019

Одно ключевое отличие, которое я вижу между «моделью формы» и «моделью данных», состоит в том, что «модель формы» содержит только те данные, которые содержатся в форме.

Если ваша модель данных имеет свойство idидентификатор, скорее всего, не появится в вашей форме, поэтому он не будет частью вашей «модели формы».То же самое относится и к другим полям, таким как «дата последнего обновления» или метки времени.

Плюс, если кто-то позже решит сгруппировать некоторые из ваших полей формы для дополнительной проверки, это может нарушить вашу ожидаемую «модель формы».

Лично я бы всегда использовал модель данных, так как у вас больше контроля над ней.Вы можете выполнять операции с ним более легко, такие как сортировка или фильтрация.Вы можете легче хранить его в локальном хранилище для автономной работы.

Плюс, если приложение со временем становится больше, вы можете перейти к более формальной библиотеке управления состоянием, такой как NgRx, которая будет работать с вашей "моделью данных".».

0 голосов
/ 17 февраля 2019

Я смог использовать привязки FormGroup, но сохранил логику / структуру внутри каждого дочернего элемента.Я нашел это решение, чтобы дать мне лучший баланс для целей, которые я искал.

Отказ от ответственности: я не претендую на оригинальность этого решения, это результат многих дней исследований и тестирования многихрешения в Интернете.

Таким образом, родительский компонент привязывается к дочернему элементу с помощью FormGroup:

<div class="sibling" *ngFor="let sibling of getSiblings(); let i = index;">
    <app-child [form]="sibling" (deleted)="deleteSibling(i)"></app-child>
</div>

Метод getSiblings () в родительском элементе является простым помощником:

getSiblings(): AbstractControl[] {
  return (<FormArray>this.form.get('siblings')).controls;
}

Ключевое различие заключается в том, как создаются родственные группы FormGroup на родительском элементе:

addSibling() {
  (<FormArray>this.form.controls.siblings).push(ChildComponent.toFormGroup());
}

addSibling () выше использует статический метод из дочернего компонента для создания пустой FormGroup:

static toFormGroup(model: any = {}) {
  return new FormGroup({
    id: new FormControl(model.id, Validators.required),
    firstName: new FormControl(model.firstName, Validators.required),
    lastName: new FormControl(model.lastName, Validators.required),
  });
}

Как видно выше, можно создавать не только пустые группы форм.Метод loadModel родительского объекта может использовать преимущества каждой дочерней логики для создания полевых групп FormGroup.Здесь у нас есть только один дочерний тип, но их может быть много:

loadModel(model: any) {
  this.form.patchValue(model);

  const formArray = this.form.get('siblings') as FormArray;
  while (formArray.length) {
    formArray.removeAt(0);
  }
  model.siblings.forEach(s => formArray.push(ChildComponent.toFormGroup(s)));
}

Сортировка и фильтрация также не сложны.Здесь есть несколько стратегий, но в качестве простого тестового примера:

orderChildren() {
  this.currentModel.siblings = this.currentModel.siblings.sort((a, b) => a.id - b.id);
  this.loadModel(this.currentModel);
}

При таком подходе я могу использовать каскадные функции Reactive Forms, такие как действительный статус, нетронутые / грязные флаги, события изменения и т. Д., Сохраняя логику /структура каждого потомка в своем классе компонентов.Так же, как пример, каскадную валидность можно увидеть в действии (красные границы) окончательного решения.

В качестве основной проблемы привязки к FormGroup было то, что логику / структуру дочерних элементов нужно было перенести в родительский.При таком подходе этого избегают, и поэтому я более готов признать, что это не может считаться плохой практикой.

Полный пример можно увидеть на StackBlitz:

0 голосов
/ 12 февраля 2019

Я думаю, что вы спрашиваете о разнице связывания между Ng Модель и Реактивные формы

ng-model лучше работать с простым связыванием, в то время как reactive formобеспечивает мощную поддержку манипуляций Form, таких как type (например, логическое значение, строка, массив и т. д.), structure (повторное использование группы структуры / формы, например, добавление других людей с именем и фамилией), validation (автодопустим ввод и форму), default value (изменения значений зависят от другого поля), disable и т. д.

Короче говоря, reactive form подходит для сложной формы, динамической формы (например, значения поля или проверкиизменения зависят от других полей) и обслуживания кода.

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