Home > Blockchain >  The Input() data passed in child component remains same after changing in the child
The Input() data passed in child component remains same after changing in the child

Time:02-04

So i am passing an object having length of data and the data itself which is an array of objects

Now what is happening is that when I change the data in the child component and reload the page the data is still showing the edited property

To clarify more see the following screenshots:

  1. When we navigate to the route for the first time there would be no modified data: enter image description here

  2. When I edit the data:: enter image description here As you can see on the right side finalAmount property is added and its value is initialised

  3. Now when renavigate to the same component finalAmount is set to 5 enter image description here

The property itself should not be present in the data as I am getting it from the parent

These are the relevant files:

  1. stepper.component.html (Parent Component)
<mat-step [stepControl]="thirdFormGroup" >
        <ng-template matStepLabel>Prepare Invoice</ng-template>
        <ng-template matStepContent>
            <div >
            
                <app-create-invoice [selectedCustomersInfo]="selectedCustomerData"
                    [selectedProductsData]="{lengthOfData:cartItems.length , selectedProducts:cartItems}"></app-create-invoice>
            
            </div>
        </ng-template>
    </mat-step>
  1. stepper.component.ts:
@Component({
  selector: 'app-stepper',
  templateUrl: './stepper.component.html',
  styleUrls: ['./stepper.component.scss'],
  providers: [
    {
      provide: STEPPER_GLOBAL_OPTIONS,
      useValue: { showError: true }
    }
  ]

})
export class StepperComponent implements OnInit, OnDestroy {

  getProductsSubscription = new Subscription
  cartItems: ProductDataModel[] = []
  selectedCustomerData: any
  products = this._formBuilder.group({
    firstCtrl: ['', Validators.required],
  });

  thirdFormGroup = this._formBuilder.group({
    thirdCtrl: ['', Validators.required],
  });
  stepperOrientation: Observable<StepperOrientation>;

  constructor(private _formBuilder: FormBuilder, breakpointObserver: BreakpointObserver, private cartService: CartService) {
    this.stepperOrientation = breakpointObserver
      .observe('(min-width: 800px)')
      .pipe(map(({ matches }) => (matches ? 'horizontal' : 'vertical')));
  }
  ngOnDestroy(): void {
    console.log("Stepper destroyed");
    this.getProductsSubscription.unsubscribe()
  }

  ngOnInit(): void {
    this.getProductsSubscription = this.cartService.getProducts().subscribe((items) => {
      this.cartItems = [...items]
      console.log("Cart items::", this.cartItems)
    })
  }

  setCustomerData(customerData: any) {
    this.selectedCustomerData = customerData
  }

}

  1. create-invoice.component.html (Child Component):
 <div >
                <table >
                    <thead>
                        <tr>
                            <th scope="col">#</th>
                            <th scope="col">Product Category</th>
                            <th scope="col">Sub Category</th>
                            <th scope="col">Master Category</th>
                            <th scope="col">Product Weight</th>
                            <th scope="col">Price</th>
                            <th scope="col">Labour</th>
                            <th scope="col">SGST (In %)</th>
                            <th scope="col">CGST (In %)</th>
                            <th scope="col">Discount</th>
                            <th scope="col">Final Amount</th>
                        </tr>
                    </thead>

                    <tbody>
                        <tr *ngFor="let item of _selectedProductsData;index as i">
                            <th scope="row">{{i 1}}</th>
                            <td>{{item.productCategory}}</td>
                            <td>{{item.subCategory}}</td>
                            <td>{{item.masterCategory}}</td>
                            <td>{{item.productWeight}} gms</td>
                            <td>
                                <input  type="number" id="{{item.productGuid}}-price"
                                    min="0" (input)="item.price = getValue($event,item.id,'price')" #price
                                    placeholder="Enter Price">
                            </td>

                            <td>
                                <input  type="number" id="{{item.productGuid}}-labour"
                                    min="0" (input)="item.labour = getValue($event,item.id,'labour')" #labor
                                    placeholder="Enter Labour">
                            </td>

                            <td>
                                <input  type="number" id="{{item.productGuid}}-SGST"
                                    min="0" (input)="item.SGST = getValue($event,item.id,'sgst')" #sgst
                                    placeholder="Enter SGST">
                            </td>
                            <td>
                                <input  type="number" id="{{item.productGuid}}-CGST"
                                    min="0" (input)="item.CGST = getValue($event,item.id,'cgst')" #cgst
                                    placeholder="Enter CGST">
                            </td>
                            <td>
                                <input  type="number" min="0"
                                    (input)="item.discount = getValue($event,item.id,'discount')" #discount
                                    id="{{item.productGuid}}-discount" placeholder="Enter Discount">
                            </td>
                            <td>
                                {{ item.finalAmount ?? 0 }}
                                <input  type="hidden" [value]="item.finalAmount ?? 0">
                            </td>
                        </tr>
                    </tbody>

                </table>
            </div>
  1. create-invoice.component.ts:
@Component({
  selector: 'app-create-invoice',
  templateUrl: './create-invoice.component.html',
  styleUrls: ['./create-invoice.component.scss']
})
export class CreateInvoiceComponent implements OnInit,OnDestroy {
  
  _selectedCustomersInfo:any
  _selectedProductsData:InvoiceProductDataModel[] = []
  totalWeight = 0
  totalDiscount = 0
  totalGST = 0
  totalAmountWithGST = 0
  currentDate:Date = new Date()

  @Input() set selectedProductsData(productsData: {lengthOfData:number,selectedProducts:ProductDataModel[]}) {
    this.totalWeight = 0
    this.totalDiscount = 0
    this.totalAmountWithGST = 0
    this.totalGST = 0
    var temp = Object.assign({},productsData)
    this._selectedProductsData = []
    this._selectedProductsData = [...temp.selectedProducts]
    // this._selectedProductsData = [...productsData.selectedProducts]
    this._selectedProductsData.forEach((product) => {
      this.totalWeight  = product.productWeight
    })
    console.log(this._selectedProductsData)
  }

  @Input() set selectedCustomersInfo(customerInfo: any) {
    this._selectedCustomersInfo = customerInfo
  }
  constructor() { }
  ngOnDestroy(): void {
    console.log("Create Invoice Destroyed!!")
    this._selectedProductsData = []
  }

  ngOnInit(): void {
  }

  getValue(event: Event, productId:number, valueOf:string): number {
    let product = this._selectedProductsData.find(item => item.id === productId)
    if (product) {
      switch (valueOf) {
        case 'labour':
          product.labour = Number((event.target as HTMLInputElement).value)
          this.setFinalAmountOfEachProduct(product)
          this.setTotalAmountWithGST()
          break

        case 'price':
          product.price = Number((event.target as HTMLInputElement).value)
          this.setFinalAmountOfEachProduct(product)
          this.setTotalAmountWithGST()
          break

        case 'sgst':
          product.SGST = Number((event.target as HTMLInputElement).value)
          this.setFinalAmountOfEachProduct(product)
          this.setTotalAmountWithGST()
          this.setTotalGST()
          break

        case 'cgst':
          product.CGST = Number((event.target as HTMLInputElement).value)
          this.setFinalAmountOfEachProduct(product)
          this.setTotalAmountWithGST()
          this.setTotalGST()
          break

        case 'discount':
          product.discount = Number((event.target as HTMLInputElement).value)
          this.setFinalAmountOfEachProduct(product)
          this.setTotalDiscount()
          this.setTotalAmountWithGST()
          break

      }
    }
    console.log(this._selectedProductsData.find(i => i.id == productId))
    return Number((event.target as HTMLInputElement).value);
  }

  setFinalAmountOfEachProduct(product:InvoiceProductDataModel) {

      product.finalAmount = 0
      let partialSum = (product.labour ?? 0)   (product.price ?? 0) - (product.discount ?? 0)
      let cgst = product.CGST ? partialSum * ((product.CGST ?? 100) / 100) : 0
      let sgst = product.SGST ? partialSum * ((product.SGST ?? 100) / 100) : 0

      product.totalGST = cgst    sgst 
      product.finalAmount = partialSum   cgst   sgst
  }

  setTotalDiscount() {
    this.totalDiscount = 0
    this._selectedProductsData.forEach((item)=> {
      this.totalDiscount  = item.discount ?? 0
    })
  }

  setTotalAmountWithGST() {
    this.totalAmountWithGST = 0
    this._selectedProductsData.forEach((item)=> {
      this.totalAmountWithGST  = item.finalAmount ?? 0
    })
  }

  setTotalGST() {
    this.totalGST = 0
    this._selectedProductsData.forEach((item)=> {
      this.totalGST  = item.totalGST ?? 0
    })
  }

}

And its not limited to finalAmount property it happens with other properties too like discount,sgst etc..

Any help will be appreciated

CodePudding user response:

From what I've understood you've got a problem with some data that have been changed in parent but it's not updated in child component, that have received it thru @input(). If I am right, you should read about Angular lifecycle hooks: enter image description here

Also JSON.parse(JSON.stringify(productsData)) has its own limitations

For more information refer these links:

  1. https://stackoverflow.com/a/5344074/18480147
  2. https://stackoverflow.com/a/10916838/18480147
  • Related