Tom
Tom

Reputation: 4033

Array.push() increases amount of entries globally

I have a mock array inside of my caseService, from this array data is distributed through the whole web-app.

To get the data inside of another component I use the following code:

this.cases = this.caseService.data;

It works fine, but there's one thing bothering me.

In one of my components I have an infinite scroll:

@HostListener('window:scroll', ['$event'])
scroll() {
  const pos = (document.documentElement.scrollTop || document.body.scrollTop) + document.documentElement.offsetHeight;
  const max = document.documentElement.scrollHeight;
  if (pos === max) {
    this.cases.push(...this.casesService.data);
    // causes trouble
  }
}

As the user scrolls, the array this.cases is being pushed. It works fine, but when I leave this component by going back or routing somewhere else, this.cases & even this.casesService.data keep the amount of entries (amount depends on for how long the user scrolled) - hence every other component displays an increased amount of cases.

Reloading the page solves the issue again.

Upvotes: 1

Views: 66

Answers (1)

Vlad274
Vlad274

Reputation: 6844

This happens because this.cases and this.caseService.data are different references to the same object.

To illustrate the issue:

var a = [];
var b = a;
b.push("test");
console.log(a) // ["test"]

To fix this, you need to ensure the two objects are not the same. When you set the initial value, simply clone the array:

this.cases = [...this.caseService.data];

NOTE: There are many ways to clone an array, this is just my personal preference.

Now you can freely modify this.cases without changing this.caseService.data.


As noted by @Rich, this will only prevent changes to the contents of the arrays. This will not prevent changes to properties of these objects.

For example:

var a = [{ name: "Original Name" }];
var b = [...this.caseService.data];
b[0].name = "Test Name";
a[0].name === "Test Name"; // True

To avoid this you would need to perform a deep clone:

this.cases = JSON.parse(JSON.stringify(this.caseService.data));

NOTE: Again, there are many ways to accomplish a deep clone, this is just my personal preference.

Upvotes: 1

Related Questions