Angular NgFor always shoes the last value from the entered object

450 Views Asked by At

I have this markup:

<div *ngFor="let quantity of model.quantities">
                            <div class="form-group kt-form__group row">
                                <label class="col-lg-2 col-form-label">Quantity:</label>
                                <div class="col-lg-6">
                                    <mat-form-field class="example-full-width">
                                        <input matInput [(ngModel)]="quantity.name" name="quantityname" placeholder="Enter Quantity" type="text">
                                    </mat-form-field>
                                </div>
                            </div>
                            <div class="form-group kt-form__group row">
                                <label class="col-lg-2 col-form-label">Price:</label>
                                <div class="col-lg-6">
                                    <mat-form-field class="example-full-width">
                                        <input matInput [(ngModel)]="quantity.price" name="quantityprice" placeholder="Enter Price" type="text">
                                    </mat-form-field>
                                </div>
                            </div>
                            <hr />
                        </div>

Every time I'm adding a new object of type quantity in the model, for each object in the array the same value is set, the one which is entered as last https://screencast-o-matic.com/watch/cqQ1Fbt4zL

This is the button click event:

addNewQuantity() {
        if (this.newQuantity) {
            let quantity = new PriceGridQuantity();
            quantity.name = this.newQuantity;
            this.model.quantities.push(quantity);
            this.newQuantity = '';
        }   
    }

Update: model added:

model: any = {
        TenantId: '',
        CustomFieldName: '',
        quantities: []
    };
3

There are 3 best solutions below

1
On

You should be using FormBuilder and FormControls in Angular, but here's something that might Work

COMPONENT TS

model = {
    id: '',
    name: '',
    quantities: [],
};

newQuantity = {
    name: '',
    price: ''
};

constuctor() {}

ngOnInit() {}

addNewQuantity() {
    this.model.quantities.push(this.newQuantity);
    this.newQuantity = {
        name: '',
        price: ''
    }
}

HTML

<div class="form-group kt-form__group row">
    <label class="col-lg-2 col-form-label">Quantity:</label>
    <div class="col-lg-6">
        <mat-form-field class="example-full-width">
            <input matInput [(ngModel)]="newQuantity.name" name="quantityname" placeholder="Enter Quantity" type="text">
        </mat-form-field>
    </div>
</div>
<div class="form-group kt-form__group row">
    <label class="col-lg-2 col-form-label">Price:</label>
    <div class="col-lg-6">
        <mat-form-field class="example-full-width">
            <input matInput [(ngModel)]="newQuantity.price" name="quantityprice" placeholder="Enter Price" type="text">
        </mat-form-field>
    </div>
</div>

<button (click)="addNewQuantity()">Add Quantity</button>

<div *ngFor="let quantity of model.quantities">
    <div class="form-group kt-form__group row">
        <label class="col-lg-2 col-form-label">Quantity:</label>
        <div class="col-lg-6">
            <mat-form-field class="example-full-width">
                <input matInput [(ngModel)]="quantity.name" name="quantityname" placeholder="Enter Quantity" type="text">
            </mat-form-field>
        </div>
    </div>
    <div class="form-group kt-form__group row">
        <label class="col-lg-2 col-form-label">Price:</label>
        <div class="col-lg-6">
            <mat-form-field class="example-full-width">
                <input matInput [(ngModel)]="quantity.price" name="quantityprice" placeholder="Enter Price" type="text">
            </mat-form-field>
        </div>
    </div>
    <hr />
0
On

Took me a second. This info/answer is based off your other question that seems to relate to this same code: your other question

The reason for the list of quantities being the same is because you have an object called quantity accessible to the entire view via this declaration:

quantity: any = {
    price: '',
    name: ''
}

So in a view if you have the ([ngModel])=quantity.name or ([ngModel])=quantity.price it will be bound to the values in quantity. This is problematic because you are setting the value quantity.name in the addNewQuantity function.

addNewQuantity() {
    if (this.newQuantity) {
        this.quantity.name = this.newQuantity;
        this.model.quantity.push(this.quantity);
        this.newQuantity = '';
    }
}

So any template that is set with ([ngModel])=quantity.name will now have the value set in the previous function.

A better implementation is to have a newQuantityObject and an object that has an array property that stores each newly added quantity. Then you don't need any new classes to implement. For example:

newQuantity = {
    price: '',
    name: ''
};

model: any = {
    TenantId: '',
    CustomFieldName: '',
    quantities: []
};


addNewQuantity() {
    if (this.newQuantity.price !== '' && this.newQuantity.name !== '') {
        this.model.quantities.push(this.newQuantity);
        newQuantity = {
            price: '',
            name: ''
        };
    }
}

Then you could display the list of quantity objects in a view like this:

<div *ngFor="let quantity of model.quantities; let i=index;" >
    <input type="text" value="{{quantity.name}}" [(ngModel)]="model.quantities[i].name" />
    <input type="text" value="{{quantity.price}}" [(ngModel)]="model.quantities[i].price"  />
</div>
0
On

I don't know what PriceGridQuantity() is doing but, You are adding same object reference each time that's why you are get same value in each quantity.

your code should look like this

addNewQuantity() {
if (this.newQuantity) {
let quantity = new PriceGridQuantity();
quantity.name = this.newQuantity;
this.model.quantities.push({name:this.newQuantity,price:quantity.price});
this.newQuantity = '';
}   
}

click here to see exaple