Кажется, что в вашем образце кода есть комбинация двух проблем :
- Два входа имеют одинаковое имя, что приводит к тому, что они совместно используют один и тот же FormControl
- Каждый элемент ввода удаляется и воссоздается, когда он обновляется при обнаружении изменений.Если другое значение не было изменено, соответствующий элемент ввода не воссоздается.По-видимому, это вызывает десинхронизацию с FormControl, и мы видим разные значения в двух полях.
Чтобы проиллюстрировать последнюю точку, вы можете принудительно воссоздать два входа при обнаружении изменений, изменив обаиз них в коде:
changeValues() {
this.arr[0] = 2;
this.arr[1] = 3;
}
Вы можете увидеть в этот стек , что оба входа имеют одинаковое содержимое после обновления.
Уничтожение / создание связанных входных элементов в цикле ngFor
можно предотвратить с помощью метода trackBy
, чтобы отслеживать элементы массива по их индексу, а не отслеживать их по их значению.Вы можете видеть в этом стеке , что два элемента ввода правильно используют один и тот же FormControl.
<div *ngFor="let item of arr; trackBy: trackByFn">
<input name="name" [ngModel]="item">
</div>
trackByFn(index, value) {
return index;
}
В конце концов, правильное поведение можно получить с 3 изменениями исходного кода:
- Присвойте каждому входу уникальное имя
- Предотвращение уничтожения / создания элемента ввода с помощью
trackBy
метод (по индексу) - Для двусторонней привязки связывайте значение массива по его индексу вместо привязки к переменной цикла
item
<div *ngFor="let item of arr; let i = index; trackBy: trackByFn">
<input name="name_{{i}}" [(ngModel)]="arr[i]">
</div>
trackByFn(index, value) {
return index;
}
Вы можете увидеть этот стек для демонстрации.
Поток данных в управляемых шаблонами формах (модель для просмотра)
Директива ngModel
обновляет FormControl
при изменении связанных данных путем вызова FormControl.setValue
:
Исходный код ngModel :
ngOnChanges(changes: SimpleChanges) {
...
if (isPropertyUpdated(changes, this.viewModel)) {
this._updateValue(this.model);
this.viewModel = this.model;
}
}
private _updateValue(value: any): void {
resolvedPromise.then(
() => { this.control.setValue(value, {emitViewToModelChange: false}); });
}
, и вы можете видеть, что FormControl.patchValue
также вызывает setValue
:
Источник FormControlкод :
patchValue(value: any, options: {
onlySelf?: boolean,
emitEvent?: boolean,
emitModelToViewChange?: boolean,
emitViewToModelChange?: boolean
} = {}): void {
this.setValue(value, options);
}