0

I'm using a form where I have the following model repeated several times :

  • I have a select where I can choose whatever type of Bottle I have.
  • An Input where I can select the quantity of bottles for the selected type.

This pattern is repeated for 2 arrays of Bottle (the Bottle type is made of an Id and a Name) as followed :

  • An Array of orderedBottles where the user can order some bottles.
  • An Array of returnedBottles where the user can return some bottles.

I want to be able to choose whatever type of bottle and corresponding count on the submit, but I believe I'm missing something because the behavior is all messed up :

  • the Inputs of the 2 arrays are linked one-another,
  • When I change some options in the select, sometimes the other selects are updated which is not what I want (obviously)...

Here is a working example in a plunkr : http://plnkr.co/edit/1z6dN6?p=preview


Here is my html file (I'm using AngularMaterial 2) :

  <div fxLayout="row" style="max-width: 80%">

    <!-- ORDERED BOTTLES -->
    <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 orderedClonedArrayBottles" [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')">-</button>
      </div>
    </div>

    <!-- RETURNED BOTTLES -->
    <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 typed of returnedClonedArrayBottles" [value]="typed.typeId">
            {{ typed.name }}
          </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 class="button-row" type="button" (click)="removeRow(j, 'return')">-</button>
      </div>

    </div>
  </div>

To add some explanation, this is a child component that has a single Array of Bottle as @Input(), which I clone in 2 different arrays (orderedClonedArrayBottles and returnedClonedArrayBottles) so that my parent array isn't updated from the child updates.

I then display my bottles with the orderedBottles Array and the returnedBottles that get their values from the 2 cloned beforehand.

ngOnChanges(changes) {
    // Get @Input data when it's ready
    if (changes.bottleArray) {
      // Cloning
      //this.orderedClonedArrayBottles = [...changes.bottleArray.currentValue];
      //this.returnedClonedArrayBottles = [...changes.bottleArray.currentValue];

      this.orderedClonedArrayBottles = Array.from(changes.bottleArray.currentValue as Bottle[]);
      this.returnedClonedArrayBottles = Array.from(changes.bottleArray.currentValue as Bottle[]);

      console.log(this.orderedClonedArrayBottles);
      console.log(this.returnedClonedArrayBottles);

      // 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]);
      }
    }
  }

I have no idea why this isn't working correctly, most probably because I don't manage the *ngFor as I should. I have seen posts about trackBy for *ngFor but I have no idea if that will help or not.

Alex Beugnet
  • 4,003
  • 4
  • 23
  • 40

1 Answers1

1

You are cloning the bottleArray. But in your case the bottle objects are not cloned. The same references are pushed in two arrays.

Check this answer.

You may have to use Object.assign for each bottle object. If you have nested objects you will have to traverse the properties and copy.

Community
  • 1
  • 1
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103