Issues with Angular Component not detecting changes in @Input array

I'm dealing with a challenging setup where:

The Parent Service (A) is imported in the Parent Component (B). Then, the Parent Component passes an array of Objects to a Child Component (C), which are referenced from the Parent Service (e.g. <child-component [input]="A.x">, where A.x = [{a},{b},...]).

This setup is rigid and cannot be changed easily because we've abstracted certain parts of our app for reusability in other tools.

Typically, change detection doesn't work properly in this scenario. Workarounds like x = [...x] or x=[]; x=dataArray; don't work with this particular array of objects (Esri ArcGIS Graphic objects). Even lodash cloneDeep fails to solve the issue.

I have tried various approaches:

  • Using the usual x = [...x] method.
  • Setting x=[] then x=data.
  • Experimenting with lodash clone and cloneDeep (cloneDeep doesn't work).
  • Implementing @Input() set function along with @Input x: Graphics[] = [];
  • Passing a BehaviorSubject and sending data via subject.next(x), but it only triggers the first time.

The initial transition from an empty array to a populated one works fine. The problem arises when trying to filter this array.

I'm running out of ideas on how to tackle this within the limitations of the parent component/service structure. If anyone has suggestions or would like to see more detailed code, I'm willing to provide as much information as possible.

Here's a snippet of the Parent Component (HTML):

<app-gs-arcgis [basemap]="'hybrid'" [graphics]="estateDataDashboardSvc.dashGraphic" [graphicsSubject]="estateDataDashboardSvc.dashGraphicSubject" (clickedPoints)="displayTooltip($event)" [(center)]="center" [(zoom)]="zoom" [padding]="arcgisPadding" [filterEvent]="estateDashboardFiltersSvc.filterEvent" class="absolute w-full h-full"></app-gs-arcgis>

Corresponding code from the Parent Service (TS):

dashGraphic: Graphic[] = [];
dashGraphicSubject: Subject<Graphic[]> = new Subject<Graphic[]>();

...

this.dashGraphic = [];
const graphics: Graphic[] = [];
point.forEach((d, i) => {
const graphic = new Graphic({
    geometry  : d as any,
    symbol    : symbol[i],
    attributes: {
      data: d
    }
});
graphics.push(graphic);
});

this.dashGraphic = graphics;
this.dashGraphicSubject.next(this.dashGraphic);

Snippet from the Child Component (TS):

@Input() graphicsSubject = new Subject<Graphic[]>();

...

private _graphics: Graphic[] | null = [];

get graphics(): Graphic[] | null {
    return this._graphics;
}

@Input()
set graphics(graphics: Graphic[] | null) {
    console.log('Graphics received', graphics);
    this._graphics = graphics;
    this.rebuildGraphics();
}

...

ngOnInit() {
    ...
    this.graphicsSubject.subscribe(next => {
        console.log(next);
        this.graphics = next;
    });
}

Answer №1

Although I haven't delved deeply into the code, I have encountered similar issues before. The key aspect to consider is the change detection strategy specified for your component. It seems you may have implemented the onPush strategy, which implies that change detection will only occur when references are altered. Since your array reference remains constant, no changes are being detected. While utilizing BehaviorSubject and async-pipe as recommended elsewhere might be helpful, it will only work if the actual array reference undergoes a modification. My suggestion would be to modify your array reference by performing immutable operations on the original array. If this approach raises efficiency concerns, consider creating change detection through an input setter. To begin, start by applying immutable operations on your array.

An alternative option is to use the default change detection strategy, which monitors the contents of the object more thoroughly.

Answer №2

In my opinion, the most effective approach is for the parent component to pass an array to the child component through a Subject and utilizing the async pipe.

Whenever the data is altered, the Subject will emit a new array containing the modifications, using immutable data structures and updating the reference of the @Input. This ensures that even if the child component implements ChangeDetectionStrategy.OnPush, it will still detect changes since the reference is updated with each modification in the data.

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

How should I proceed if a TypeScript definition file that I am relying on is lacking a specific definition?

I have encountered an issue while using the React type definitions for my project. The focus method is missing on elements in the array returned by the refs property, which prevents me from getting a specific example to work. The compiler error states: pro ...

Nested iteration using a for loop in Javascript

I am attempting to iterate through a large array of values and calculate the average of one of the values for each second. I seem to be having trouble getting this code to function correctly, and it appears that the issue lies within the nested while loop. ...

What could be the reason my "mandatory" function is not providing any output?

Recently, I've been working on an Express.js application that handles POST requests with a "city" parameter in the body. The application processes this request and utilizes an external service for further operations. To maintain clean code, I separate ...

Encountering a bindings issue when trying to utilize libxml-xsd within an electron application

Seeking guidance on validating an XML file against its schema within an electron application. Prior to adding the 'libxml-xsd' require statement to my angular2 service, it functioned properly. However, upon inclusion of this statement: const xs ...

Is it possible to customize error messages in @hapi/joi?

Seeking assistance with custom error message overrides in Joi. Consider the schema outlined below. const joiSchema = Joi.object({ name: Joi.string().required(), email: Joi.string().email().required() }) try{ const schema = joiSchema.validateAsyn ...

Adding up and finding the contrast between odd and even numbers

After successfully segregating the odd and even numbers, I am faced with a challenge in determining how to add the odds together and the evens together before subtracting them to find the final result. For example: (1 + 3 + 5 + 7 + 9) - (2 + 4 + 6 + 8) = ...

I aim to capture user input values and store them in a variable for future use in other functions, or to perform operations on the input data

const readline = require('readline').createInterface({ input: process.stdin, output: process.stdout, }) readline.question('Please enter the first number: ', function (a) { readline.question('Please enter the second number: & ...

How can I programmatically control the scrollbar of an iframe displaying a PDF using JavaScript?

As I explore ways to display PDF documents on a Smart TV, I have decided to implement invisible buttons for scrolling up and down the document. This functionality needs to be integrated into a web environment, so this is what I have attempted: Here is the ...

How to utilize jQuery to replace the first occurrence of a specific

Suppose I have an array structured like this: var acronyms = {<br> 'NAS': 'Nunc ac sagittis',<br> 'MTCP': 'Morbi tempor congue porta'<br> }; My goal is to locate the first occurrence ...

What is the best way for me to access and analyze the information?

I have recently developed a matrix using pointer to pointers. int** grid = new int*[5]; for(int i = 0; i < 5; i++) grid[i] = new int[5]; Just as I understand it, what this code does is create a pointer called grid, which directs to an array of poi ...

Preventing User Duplication in MERN Stack: Strategies to Avoid Multiple Registrations

A developer fairly new to the field is working on a project using the MERN stack. Within this app, there are two models: one for Users and another for Tournaments. The Tournament model contains an attribute called participants, which is an array. The dev ...

What is the best way to delete a nested document within an array in MongoDB by referencing its _id?

I am trying to remove a nested object from an array of objects called createdEvents if the createdEventId matches the id I pass to it. This is the JavaScript query I am using: db.collection("users").updateOne({ _id: userId }, { $pull: { createdEv ...

"PHP array generated from JSON will exhibit variances if there is only a single

My current project involves using the Australia Post postcode lookup API, which returns a JSON response. For example, when I search for postcode 3094, the API returns: Array ( [localities] => Array ( [locality] => Array ...

Identifying the moment when the body scroll reaches the top or bottom of an element

I have been experimenting with javascript and jquery to determine when the window scroll reaches the top of a specific element. Although I have been trying different methods, I have yet to see any successful outcomes: fiddle: https://jsfiddle.net/jzhang17 ...

What seems to be the issue with Collapse.js in Bootstrap 3.3.4 on this page?

I am currently utilizing Bootstrap version 3.3.4. All of my resources are linked relatively and the HTML file is in the correct location for access. I am creating a 'Learn More' button that should display a collapsed unordered list either above ...

Positioning elements next to each other in jQuery on mouse over - while also addressing scrolling issues in a div

After tinkering with this interesting concept of mouseover combined with absolute positioning divs on a jsFiddle, I encountered some unexpected results. The code was inspired by a stackoverflow thread on positioning one element relative to another using j ...

Develop dynamic components in Angular using up-to-date methods

I currently have three components named PersonComponent, AddressComponent, and CompanyComponent all already defined. Is there a way to dynamically create each component when I have the component name as text, for example, "PersonComponent"? I have inject ...

How can I effectively separate the impact of Next.js onChange from my onClick function?

The buttons in my code are not functioning properly unless I remove the onChange. Adding () to my functions inside onClick causes them to run on every keystroke. How can I resolve this issue? In order to post my question, I need to include some dummy text. ...

Rails offers a unique hybrid approach that falls between Ember and traditional JavaScript responses

My current project is a standard rails application that has primarily utilized HTML without any AJAX. However, I am planning to gradually incorporate "remote" links and support for JS responses to improve the user experience. While I acknowledge that gener ...

Adjusting the transparency of TabBadge in Ionic 2

I am currently working on a project that involves tabs, and I'm looking to update the style of the badge when the value is 0. Unfortunately, I am unsure how to dynamically change the style of my tabs or adjust the opacity of the badge in the style. M ...