2017-01-19 2 views
3

Эй снова для тех, кто видел мои несколько сообщений об этой форме с бутылками ... Это снова.Angular2 странное поведение формы с * ngFor

Прежде чем я начну объяснять ничего, вот работает plunkr показывая вопрос:

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

ответ

Смежные вопросы