Angular is programmed to detect any alterations

Upon detecting changes, the NgOnChanges function triggers an infinite service call to update the table, a situation that currently perplexes me. Any assistance on this matter would be greatly appreciated. Many thanks.

The TableMultiSortComponent functions as the parent component in my setup, with the output EventEmitter passing along the table data.

The event emitted by the EventEmitter is transmitted to the child component where I utilize parameters like pagesize and pageindex for querying purposes within the dataServiceEvent function.

Subsequently, the request's output, dealsListData, is relayed from the child component back to the parent component as data destined for populating the table.

The intended behavior is for the table to dynamically update when changes occur, which led me to place it under the ngOnchanges method, specifically the initTableMultiSort function. However, the table undergoes repeated updates indefinitely instead of just once following a change.

https://i.sstatic.net/KTUUN.png

#Within this.parent component, data transmission towards the child component is facilitated through: this.dataServiceEvent.emit(this.table); given its necessity for attributes like pageindex and size.

https://i.sstatic.net/xZQsb.png

#HTML CODE - Parent Component

<mat-card *ngIf="table !== undefined">
  <mat-table mat-table [dataSource]="table.dataSource" matMultiSort (matSortChange)="table.onSortEvent()"> 
    <ng-container *ngFor="let column of table.columns" [matColumnDef]="column.id">
      <mat-header-cell class="table-multi-sort-header" *matHeaderCellDef [mat-multi-sort-header]="column.id"> 
        <div>{{column.name}}</div> 
        <div class="sub-text">{{getColumnSubtitle(column.id)}}</div>
      </mat-header-cell>
      <mat-cell *matCellDef="let row">
          <ng-container *ngIf="column.id !== 'action'; then col; else actionCol"></ng-container>
          <ng-template #col>
            <app-table-multi-sort-cell-default [cellData]="row" [id]="column.id" [subId]="getColumnSubId(column.id)"></app-table-multi-sort-cell-default>
          </ng-template>
          <ng-template #actionCol>
            <app-table-multi-sort-cell-action [rowData]="row" [actions]="getActions(column.id)" (actionClickEvent)="clickTableAction($event,row)"></app-table-multi-sort-cell-action>
          </ng-template>
      </mat-cell>
    </ng-container>
    <mat-header-row *matHeaderRowDef="table.displayedColumns; sticky:true"></mat-header-row>
    <mat-row *matRowDef="let item; columns: table.displayedColumns;"></mat-row>
  </mat-table> 
  <mat-progress-bar *ngIf="isLoading" mode="indeterminate"></mat-progress-bar>
</mat-card>

#ts code- parent component

export class TableMultiSortComponent implements OnInit {
  @Input() tableOptions:any;
  @Input() tableData:any = [];
  @Input() isClientSide:boolean = false;
  @Input() isLoading: boolean = false;
  @Output() tableActionsEvent = new EventEmitter<any>();
  @Output() dataServiceEvent = new EventEmitter<any>() ;
  @ViewChild(MatMultiSort, { static: false }) sort: MatMultiSort;
  
  tableConfig: any = TABLE_MULTI_SORT_OPTIONS.DEFAULT;
  table:TableData<any>;
  displayedColumns: any;
  
  constructor() { }

  ngOnInit(): void {   
    this.initTableMultiSort();
  }

  initTableMultiSort(){
    this.tableConfig = {
      ...this.tableConfig,
      ...this.tableOptions
    }
    
    // Rest of the initialization process goes here...
    
  }

  ngOnChanges(changes: SimpleChanges) {  
    if (changes.tableData && changes.tableData.currentValue){  
      console.log("changes" , changes)
      this.initTableMultiSort()
    }
  }

  getData(){
    // Method logic for getting data...
    
  }

#child component HTML code

  <app-table-multi-sort  (dataServiceEvent)="dataServiceEvent($event)" [tableOptions]="tableOptions" [tableData]="dealsListData" (tableActionsEvent)="tableActions($event)"></app-table-multi-sort>

#child component ts code

   export class DealsTransactionComponent implements OnInit {
  // Child component functionality and methods implementation...

Answer №1

Whenever you call the getData function in the TableMultiSortComponent's ngOnInit lifecycle hook, you emit this.table.

This emission likely triggers a data fetch in the parent component's tableActions method (the implementation of which is not visible in the provided code). The tableActions method probably resembles _pageEventMyList, which retrieves data from the API and assigns it to the dealsListData property of the TableMultiSortComponent (

[tableData]="dealsListData"
).

Subsequently, this triggers the onChange function in

TableMultiSortComponent</code, passing through the <code>if
check validating that the tableData has indeed changed. Upon invoking initTableMultiSort within onChange, this.table gets reinitialized and emitted via
this.dataServiceEvent.emit(this.table);
, creating a recurring cycle.

To avoid triggering unnecessary data reloads, it's advisable to include additional checks to ensure that the table configuration remains unchanged before refetching data.

In essence, the table facilitates access to information such as pageIndex, pageSize, sortParams, and sortDirs. Therefore, preserving the values of these properties while attempting to load data again, comparing them, and fetching data only upon detecting changes is recommended.

  private currentTableConfig: TableData<any>;

  private _pageEventMyList() {
    if (!shouldLoadData(currentTableConfig, this.table)) {
      return;
    }
    this.currentTableConfig = this.table;
    this.searchInput = '';
    this.isLoading = true;
    this.dealService
      .getAllDeals(
        this.accountId,
        this.transaction.id,
        this.table.pageIndex + 1,
        this.table.pageSize,
        this.searchInput,
        this.table.sortParams,
        this.table.sortDirs
      )
      .pipe(finalize(() => (this.isLoading = false)))
      .subscribe({
        error: (err) => this.notificationService.showError(err),
        next: (res) => {
          this.dealsListData = res.totalItemCount;
          this.dealsListData = res.lastItemOnPage;
          this.totalDeals = res.items.length;
          this.dealsListData = res.items;
        },
        complete: noop,
      });
  }

The new shouldLoadData method carries out the necessary comparisons:

private shouldLoadData(oldTableConfig: TableData<any>, tableConfig: TableData<any>): boolean {
  if (!oldTableConfig) {
    return true;
  }
  return oldTableConfig.pageIndex !== tableConfig.pageIndex
    || oldTableConfig.pageSize !== tableConfig.pageSize
    || JSON.stringify(oldTableConfig.sortParams) !== JSON.stringify(tableConfig.sortParams)
    || JSON.stringify(oldTableConfig.sortDirs) !== JSON.stringify(tableConfig.sortDirs);
}

Regarding the use of JSON.stringify:

While functional, it may not be the most efficient approach. If an alternative third-party library like lodash is available, utilizing _.isEqual or an equivalent method for array comparison is recommended.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Understanding Three.js Fundamentals: Resolving GLTFLoader Animation and Variable Not Found Issues

My understanding of JS is very basic. After exploring the three.js docs on Loading 3D models, I managed to successfully render a 3D object and center it: const loader = new GLTFLoader(); loader.load( 'Duck.gltf', function ( duck ) { con ...

Display a FullCalendar showcasing events for the next 30 days

I am currently working with the FullCalendar library and I have a unique request. I need to create a rolling 30-day view using the month grid style, complete with day headers. Additionally, I need the flexibility to set the starting day in the grid. For ...

Modify the color of the components in Select from Material-UI

After reviewing numerous questions and answers on this topic, I have yet to find a suitable solution for my issue. Seeking guidance from the community for assistance. Utilizing the Select component from @mui/material to showcase the number of records per ...

Idiosyncratic TypeScript behavior: Extending a class with comparable namespace structure

Lately, I've been working on creating a type library for a JavaScript written library. As I was defining all the namespaces, classes, and interfaces, I encountered an error TS2417 with some of the classes. I double-checked for any issues with method o ...

Using the `require('ts-node/register')` method for programmatic implementation in TypeScript

ts-node recommends using require('ts-node/register'). This is also evident in the angular2-webpack-starter Protractor configuration. What exactly does require('ts-node/register') do? Does it modify require to compile TS files, allowing ...

Having difficulty transferring information from the component to the service

I am having trouble passing a parameter to a function that is defined in a service. No matter what I try, the parameter always ends up being undefined. login.component.ts import { Component, OnInit } from '@angular/core'; import { Authenticati ...

Template for Vue.js Component Registration

Below is a simple Vue component example: const MyComponent = Vue.component('my-component', { data () { // data here... }, methods: { // methods here... }, template: '<p>Hello, world !!!</p>' }); I ...

Saving three different forms with just a single submission using Angular 10

Trying to simultaneously save 3 forms of an angular stepper, where the products (secondFormGroup) and values(thirdFormGroup) may contain multiple rows. The API model is structured as follows: { "product": [ { "description": ...

Issue with Vuetify v-alert not appearing after updating reactive property

I am trying to set up a conditional rendering for a v-alert if the login response code is 401 Unauthorized. Here is how I have defined the alert: <v-alert v-if="this.show" type="error">Invalid email and/or password.</v-alert> Within the data ...

The function chartobject-1.render() is returning an error message stating: "Unable to locate the specified container within the document. This issue is occurring in the

I've encountered an issue while trying to integrate FusionCharts into my Vue.js project. Every time I attempt to render the charts within my components, I consistently run into this error. Here's a snippet of one of the components: <template&g ...

Having trouble with expressJs router.post() not functioning properly with multiple middleware, resulting in an [object Undefined] error

I have been working on developing a REST API for my users, utilizing express-validator for validation before adding the user to the database. However, I encountered an issue while chaining my middleware in the router.py file which resulted in the error Err ...

Is there a way to access the value of a variable that is defined in FileReader.onloadend from within the callback function of XMLHttpRequest.onreadystatechange

I'm trying to access the value of the variable ext (defined within the function reader.onloadend) in the function xhr.onreadystatechange. Currently, it is returning undefined. Does anyone have any suggestions on how to resolve this issue? function pr ...

Failed to establish Modbus TCP connection

Currently, I am utilizing the "Panasonic FP7" master PLC along with their official software "FPWIN GR7" to monitor data flow on my PC. However, since the software lacks certain functions, I have decided to develop a solution using nodeJS. Below is the code ...

The incredible power of the MongoDB $inc field

I am facing a challenge in writing a function that accepts a record id, an action (inc or dec), and a field name as a string to be incremented (can be 'likes', 'subs' or any other). The issue is that I am unable to find a way to replac ...

Different types of subscriptions for forkJoin observable

I am currently making two API requests with typed responses and combining them using the Observable.forkJoin method. My goal is to store each of the results in separate typed variables. var observableOrganization: Observable<Organization> = this.get ...

Is it possible for NodeJS to prioritize IPv6 DNS lookups as the default option?

In my work with multiple TypeScript (NodeJS 14) client applications that are all Dockerized, I primarily use axios for most HTTP requests. However, there are other tools used as well. Typically, DNS queries default to resolving IPv4 addresses, resulting i ...

Opening a modal in Angular2+ when selecting an item from ngx-chips (tag-input)

I need to implement a functionality where clicking on a tag in a dropdown should trigger the opening of a modal window in my Angular application. Below is the code snippet related to this feature: <div class="force-to-the-bottom"> <tag-input [ ...

Is the image flickering non-stop when the button is pressed?

Every time I push the button, the image on the HTML 5 canvas flickers. After investigating, it seems like the issue might be related to the ctx.clearRect(0,0,100,500) function. Any suggestions on how to fix this problem? I'm currently working on anim ...

All web resources need to be included in the web_accessible_resources manifest key

I'm encountering an issue with my Angular app. The error message on the client console reads: Denying load of chrome-extension://fiekimdgbphfmnlbiahcfdgcipcopmep/js/lib/angular/angular.min.js.map. Resources must be listed in the web_accessible_resour ...

Deploy Node.js on a Debian server hosted on Google Compute Engine

Currently, I am operating a Debian server on Google Compute Engine using a host called example.com. My goal is to run a node.js app within a specific directory on this server, for instance, example.com/mynodeapp. Fortunately, the necessary components such ...