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.