Home > Enterprise >  OnChanges won't detect the changes
OnChanges won't detect the changes

Time:03-13

I am creating a simple app. And I pass an array to the child component. When I remove an item from the array, ngOnChanges won't detect the changes unless I refresh the page.

I can log the changes only once at the first page load but not when the array changes.

Thanks in advance for your time.

Parent Component:

    <div >
      <div >
        <h1>In Cart</h1>
        <mat-card  *ngFor="let x of shoppingCart">
          <div >{{ x.title }}</div>
          <button color="warn" mat-icon-button (click)="deleteFromCart(x)">
            <mat-icon >clear</mat-icon>
          </button>
        </mat-card>
        <app-calculator [shoppingCart]="shoppingCart"></app-calculator>
      </div>
      <hr />
      <app-favourites></app-favourites>
    </div>
    import { Component, Input, OnInit } from '@angular/core';
    import { ProductModel } from 'src/app/models/product/product-model';
    import { CartService } from 'src/app/services/cart.service';
    
    @Component({
      selector: 'app-shopping-cart',
      templateUrl: './shopping-cart.component.html',
      styleUrls: ['./shopping-cart.component.scss']
    })
    export class ShoppingCartComponent implements OnInit {
      public shoppingCart: ProductModel[] = [];
    
      constructor(
        private cartService: CartService
      ) { }
    
      ngOnInit(): void {
        this.getItems();
      }
    
      getItems(): void {
        this.shoppingCart = this.cartService.getItems();
      }
    
      deleteFromCart(item: ProductModel): void {
        this.shoppingCart = this.cartService.deleteItemFromCart(item);
    
      }
    }

Child Component:


    import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
    import { ProductModel } from 'src/app/models/product/product-model';
    
    @Component({
      selector: 'app-calculator',
      templateUrl: './calculator.component.html',
      styleUrls: ['./calculator.component.scss']
    })
    export class CalculatorComponent implements OnChanges {
      @Input() shoppingCart: ProductModel[] = [];
      public total: number = 0;
    
      constructor() { }
    
      ngOnChanges(changes: SimpleChanges): void {
        console.log(changes)
      }
    }

CodePudding user response:

Try this:

  deleteFromCart(item: ProductModel): void {
    this.shoppingCart = [...this.cartService.deleteItemFromCart(item)];
  }

But it's more correct that cartService.deleteItemFromCart returns a copy of the array of items without the item removed, rather than returning the same array from which the item was removed.

CodePudding user response:

I guess the problem is with your change detection. I'm not sure how exactly your service looks like and if it returns observable or array, so the easiest way to check where the problem is:

  1. log this.shoppingCart in your deleteFromCart. If it logs out the right result ( so the item is removed ) - that means the problem is with change detection. Perhaps you're not assigning the array again, you're just modifying it, so angular doesn't check for the changes. This would mean that you have two options to fix the problem. The better way:

    deleteFromCart(item: ProductModel): void { this.shoppingCart = [...this.cartService.deleteItemFromCart(item)]; }

This would assign a totally new array to this.shoppingCart and would trigger angular to check for changes. The "worse" way, is to add private changeDetectorRef: ChangeDetectorRef in your constructor, and then:

deleteFromCart(item: ProductModel): void {
        this.shoppingCart = this.cartService.deleteItemFromCart(item);
        this.changeDetectorRef.markForChanges()
      }

This will tell angular that he must check if anything has changed - but it's not a good way ( it's best to avoid changeDetectorRef)

  1. If your log is saying that result is still the same - then it would mean that your service is doing something wrong, and then you should check what's going on over there - you can paste the code here so we can help.

CodePudding user response:

You are right, adding or removing an item would not raise onChanges event, because the array object's reference is not changed. If you want to force onChanges then you'll have to create a new array object each time you modify the array. Something like this

      deleteFromCart(item: ProductModel): void {
    this.shoppingCart = [...this.cartService.deleteItemFromCart(item)];
  }

Otherwise if you just want to check whether the array change event is raised, you have plenty of other methods for example you can put the array inside a service where its accessible from both parent and child component, or you can create a subject and subscribe to it in the child component.

  • Related