Эй снова для тех, кто видел мои несколько сообщений об этой форме с бутылками ... Это снова.Angular2 странное поведение формы с * ngFor
Прежде чем я начну объяснять ничего, вот работает plunkr показывая вопрос:
NB: Я отображая бутылки typeId
во 2-й массив, он показывает проблему ясно.
Вопрос:
Я проверял привязок, чтобы убедиться, что значения я отбирал были приняты правильно, когда я столкнулся вопрос со следующим сценарием:
- 1 : Добавьте
Order
илиReturn order
, чтобы у вас было несколько входов. - 2: Выберите некоторые типы и установите некоторые значения на этих входах.
- 3: Если вы удалите какие-либо из входов, которые НЕ являются последним из массива, а затем повторно добавите вход, значения будут испорчены, хотя привязки к ngModel все еще верны.
Есть ли способ избежать этого странного поведения, используя стандарт Template Driven Forms
? Или мне нужно пройти через ReactiveForms
?
Я объясню здесь большую часть моего кода:
Я посылаю массив газовых баллонов (bottleArray
), содержащие их name
и typeId
к моей форме @Input()
.
Я глубоко клонировал этот массив и его объекты на два отдельных массива: orderedClonedArrayBottles
и returnedClonedArrayBottles
.
Затем я добавляю значения в соответствующие отображаемые массивы: orderedBottles
и returnedBottles
, которые имеют значение count
.
...
@Input() private bottleArray: Bottle[];
private orderedClonedArrayBottles: Bottle[] = [];
private returnedClonedArrayBottles: Bottle[] = [];
private orderedBottles: BottleCommand[] = [];
private returnedBottles: BottleCommand[] = [];
ngOnChanges(changes) {
// Get @Input data when it's ready
if (changes.bottleArray) {
// Cloning the Array AND the Bottles
this.orderedClonedArrayBottles = this.deepClone(changes.bottleArray.currentValue);
this.returnedClonedArrayBottles = this.deepClone(changes.bottleArray.currentValue);
// Display first rows
if (this.orderedClonedArrayBottles.length > 0) {
this.orderedBottles.push(this.orderedClonedArrayBottles[0]);
}
if (this.returnedClonedArrayBottles.length > 0) {
this.returnedBottles.push(this.returnedClonedArrayBottles[0]);
}
}
}
Я могу удалить любой индекс любого массива с помощью следующего метода:
removeRow(index: number, type: string, event: Event): void {
event.stopPropagation();
if (type == 'order') {
// Cleans the reference 'count' value.
this.orderedBottles[index].count = null;
this.orderedBottles.splice(index, 1);
} else {
this.returnedBottles[index].count = null;
this.returnedBottles.splice(index, 1);
}
}
я могу толкнуть элементы в любой из этих 2-х массивов с 2 отдельными кнопками: AddOrder()
и AddReturnOrder()
(тот же код):
addOrder(event: Event): void {
event.stopPropagation();
// Limits to the number of types
if (this.orderedBottles.length < this.orderedClonedArrayBottles.length) {
let index = this.getAvailableIndex(this.orderedBottles, this.orderedClonedArrayBottles);
this.orderedBottles.push(this.orderedClonedArrayBottles[index]);
}
}
Чтобы избежать толкания существующей ссылки в моих массивах, я использую следующий метод, который получит мне первый доступный индекс, который не ALR Eady отображается:
/**
* Gets the first available index from 2 arrays containing the same references.
*
* @param {Object[]} displayedArray Array containing the occupied indexes
* @param {Object[]} referenceArray Array containing all the indexes
* @return {number} Index of the first available position
*/
getAvailableIndex(displayedArray: Object[], referenceArray: Object[]): number {
let index: number = null;
// Gets the available indexes of Bottles by filtering the referenceArray with the displayedArray
let availablePositions: Object[] = referenceArray.filter(element => displayedArray.indexOf(element) < 0);
// Return the first position available
return index = referenceArray.indexOf(availablePositions[0]);
}
Вот соответствующий HTML: (яснее Plunkr)
<div fxLayout="row" style="max-width: 80%">
<div fxLayout="column" style="min-width: 50%">
<div fxLayout="row" style="max-width: 100%" *ngFor="let bottle of orderedBottles; let i = index">
<md-select class="select" placeholder="Select bottle type" name="orderedTypeSelect_{{i}}" [(ngModel)]="orderedBottles[i].typeId">
<md-option class="options" *ngFor="let type of bottleArray" [value]="type.typeId">
{{ type.name }}
</md-option>
</md-select>
<md-input-container class="container">
<input md-input type="number" name="orderedBottleInput_{{i}}" autocomplete="off" [(ngModel)]="orderedBottles[i].count"
step="1" min="0" max="99">
</md-input-container>
<button class="button-row" type="button" (click)="removeRow(i, 'order', $event)">-</button>
{{orderedBottles[i].typeId}} -
{{orderedBottles[i].count}}
</div>
</div>
<div fxLayout="column" style="min-width: 50%">
<div fxLayout="row" style="max-width: 100%" *ngFor="let bottle of returnedBottles; let j = index">
<md-select class="select" placeholder="Select bottle type" name="returnedTypeSelect_{{j}}" [(ngModel)]="returnedBottles[j].typeId">
<md-option class="options" *ngFor="let type of bottleArray; let z = index" [value]="bottleArray[z].typeId">
{{ bottleArray[z].typeId }}
</md-option>
</md-select>
<md-input-container class="container">
<input md-input type="number" name="returnedBottleInput_{{j}}" autocomplete="off" [(ngModel)]="returnedBottles[j].count"
step="1" min="0" max="99">
</md-input-container>
<button style="margin-top: -20px;" class="button-row" type="button" (click)="removeRow(j, 'return', $event)">-</button>
{{returnedBottles[j].typeId}} -
{{returnedBottles[j].count}}
</div>
</div>
</div>
<div class="margin">
<button md-raised-button type="button" class="submit-button" (click)="addOrder($event)">Add Order</button>
<button md-raised-button type="button" class="submit-button" (click)="addReturnOrder($event)">Add Return Order</button>
</div>
Черт это было так просто ... Спасибо! –