Ваша проблема
- У вас есть 2 массива элементов одного типа
- Вы хотите отобразить массив форм для каждого массива
- Вы хотите быть возможность перемещать элементы между массивами
- Вы хотите иметь возможность привязать значения формы обратно к элементам при отправке
Дизайн
Как и в большинстве случаев каждая проблема, связанная с компонентами в Angular, вы должны сначала подумать о модели. Ваша модель - король, а все остальное построено вокруг нее.
В вашей демонстрации вы перемещаете элементы между списками. Вы обновляете свою модель и привязываете к ней HTML. В этом нет ничего плохого - это правильный подход и работает.
Дополнительная проблема здесь заключается в том, что вы также хотите перемещать группы форм. Нам все еще нужно думать в первую очередь о модели, но также думать о перемещении связанного состояния в то же время, когда мы перемещаем элементы между списками.
В абстрактных терминах у вас есть
list1: [];
selected1: [];
list2: [];
selected2: [];
Если вы Если вы хотите переместить элементы с 1 -> 2, ваш метод перемещения удалит все выбранные элементы с items1
до items2
. Просто.
Как только вы добавите формы, у вас будет такая структура:
list1: [];
selected1: [];
form1: FormGroup;
formArray1: FormArray;
list2: [];
selected2: [];
form2: FormGroup;
formArray2: FormArray;
И когда вы будете перемещать элементы с 1 -> 2, вы продолжите перемещать элементы с list1
на list2
, но теперь вам также необходимо удалить связанный элемент из formArray1
и добавить его к formArray2
.
Я храню ссылку на массивы форм, чтобы впоследствии с ними было легче работать. .
Создание формы
Работа с массивами форм, пожалуй, самая сложная часть этого ответа. Ключ с массивами форм заключается в том, что структура HTML имитирует структуру создаваемого вами объекта FormGroup
.
Мы можем использовать FormBuilder
для создания формы из массива и привязки к ней следующим образом:
component.ts
buildForm() {
this.model = [
{ value: 'a' }, { value: 'b' }, { value: 'c' }
];
// create a form group for each item in the model
const formGroups = this.model.map(x => this.formBuilder.group({
value: this.formBuilder.control(x.value)
}));
// create a form array for the groups
const formArray = this.formBuilder.array(formGroups);
// create the top-level form
this.form = this.formBuilder.group({
array: formArray
});
}
И привязки к ней в HTML примерно так:
<form [formGroup]="form1" (submit)="onSubmit()">
<div formArrayName="array">
<div *ngFor="let item of list1; let i = index" [formGroupName]="i">
<input formControlName="value" />
</div>
</div>
<button>Submit</button>
</form>
Это сгенерирует вход для каждого элемента в массиве, содержащий значения "a", "b", "c" соответственно.
Перемещение элементов
Перемещение элементов между массивами - простая javascript проблема. Нам нужно splice
исходный массив и push
к целевому массиву.
Чтобы переместить элементы из списка 1 в список 2:
// move selected items from model 1
this.selected1.forEach(item => {
const index = this.list1.indexOf(item);
this.list1.splice(index, 1);
this.list2.push(item);
});
this.selected1.length = 0;
Это будет через l oop каждый выбранный элемент в списке 1, склейте его из списка, добавьте его в список 2. Затем он очистит выбранные элементы;
Перемещение групп форм
Вы переместите группы форм одновременно с перемещением предметов. Это похоже на концепцию - вы удаляете из одного и добавляете к другому. Вы построили массив форм из своей модели, так что вы знаете, что ваши индексы совпадают.
// move selected items from model 1
this.selected1.forEach(item => {
const index = this.list1.indexOf(item);
const formGroup: FormGroup = this.formArray1.controls[index] as FormGroup;
this.list1.splice(index, 1);
// move between form arrays
this.formArray1.removeAt(index);
this.formArray2.push(formGroup);
this.list2.push(item);
});
Обратите внимание, что здесь есть две строки для перемещения между массивами форм, которые похожи на две строки, используемые для перемещения между обычными массивами .
formArray.removeAt(index)
и formArray.push(formGroup)
делают движение. Разница с массивом форм заключается в том, что нам нужно сначала получить ссылку на него, используя this.formArray1.controls[index] as FormGroup;
.
DEMO: https://stackblitz.com/edit/angular-3cwnsv
Внимание
В этом проекте важен порядок, в котором вы удаляете массивы и формы и добавляете их в них. Вы привязываете HTML к своим массивам и своей форме. Вы создаете массив входных данных, циклически перебирая свой массив и привязывая каждый элемент к i
-й группе в массиве форм. Если вы сначала удалите из формы, теперь у вас будет n
элементов в массиве и n - 1
элементов в вашем массиве форм. У вас будет ошибка при попытке привязки к неопределенной n
-й группе форм.
Теперь вы выполняете транзакцию с несколькими операциями.
Помимо обеспечения удаления и добавления в правильный порядок, один из способов - использовать OnPush
обнаружение изменений. Читайте об этом, так как это хорошая стратегия для всех, кроме самых простых приложений.
Следующие шаги
Я оставил свою демонстрацию простой для целей ответа. Это не особенно масштабируемый или многоразовый, как он есть. Существует много повторяющихся кодов и неправильных имен, чтобы не отвлекаться на вложенные компоненты и имена свойств, относящиеся к вашему приложению.
В действительности вы, вероятно, захотите создать дочерний компонент, который отвечает за много кода, который я продублировал. Дизайн этого вопроса определенно выходит за рамки этого вопроса.