22

I have an html structure with a component inside a component (forgot the proper word for it).

working basicly like this (largely simplified):

main html:

<div *ngFor="let item of data">
  <app-item [item]="item"></app-item>
</div>

<button (click)="addItem()">Add</button>

item html:

<div>{{item.name}}</div>

<button (click)="deleteItem()">Delete</button>

inside the app-item I display several items out of a list. The list gets it's data straight out of the database via an http.get request.

Now I also have functionality to add or delete items which both work (items get added or removed respectively to or from the database just fine). Though the change detection does not pick any of it up and the site needs to be refreshed (via F5 for example) to display the changes.

I checked the code (not all of it is from me) and couldn't find any specified change detection strategie.

I also tried to manually tigger change detection from the add and delete function via the ChangeDetectorRef (this.ref.detectChanges();). Though that also did not take away the need to manually refresh the page to see the changes.

Now what am I missing for change detection to pick this up? Or alternatively, how can I manually trigger it within my add/delete methods?

m41n
  • 403
  • 1
  • 5
  • 16
  • 1
    _change detection does not pick any of it _ - what do you expect to happen? what does `addItem` and `deleteItem` do? – Max Koretskyi Aug 04 '17 at 07:21
  • it calls a service that does http.post and http.delete requests, since the data comes from an http.get I thought change detection would pick it up – m41n Aug 04 '17 at 11:15
  • @m41n Well Angular will not automagically fire a request that you have not told angular to do. So you need to fire the `get` request to get the "updated" data from backend. – AT82 Aug 05 '17 at 09:53
  • oddly enough, building the get request into my add/delete methods did not really do the trick, however manipulating the array in the component parallel to the backend did the trick, as I only do that on a successful add/delete, both backend data and "local" array should always be the same – m41n Aug 07 '17 at 06:03

2 Answers2

29

Since you are adding or deleting element in existing array angular is not able to pick the changes.

For this to work you can do like

  • assign array reference with new object of same elements of array as items= items.slice();
  • Or you can use Object.assign method as items= Object.assign([],items);
  • Both the things should be done after making changes to the array.

To manually fire change detection you can follow answer on this link

Inject ChangeDetectorRef in your component and then use detectChanges() method of that object to fire change detection manually.

constructure(private cd: ChangeDetectorRef) {}

someMethod() {
    this.cd.detectChanges();
}
Kamil
  • 127
  • 1
  • 8
Prathmesh Dali
  • 2,250
  • 1
  • 18
  • 21
  • 3
    The second option with the ChangeDetectorRef, I actually tried. Did not bring the desired result though – m41n Aug 04 '17 at 11:17
  • 1
    Can you try first option because if you go through angular documentation change detection mechanism. It is mentioned that if you add element in array or remove element from array change detection might not get fired automatically. Since you are not changing object that is it points to same reference. So try to assign a new object by using slice or by using Object.assign. You can find better description in answer of this question https://stackoverflow.com/questions/34796901/angular2-change-detection-ngonchanges-not-firing-for-nested-object – Prathmesh Dali Aug 04 '17 at 13:43
  • kinda late with answering, but I basicly did the first option now, pushing on the "local" array on add and splicing from the "local" array on delete. The tricky part was that delete is done on a sub-component and I was not aware that when I pass the array done via @Input, I'd be able to manipulate it directly in the subcomponent. Eitherway, better late then never, going to accept the answer. – m41n Aug 07 '17 at 06:01
  • 2
    among the 3 ways, only ChangeDetectorRef worked for me. +1 – Dipendu Paul Apr 22 '18 at 04:09
  • 4
    What i REALLY don't understand, if that when you set up a real simple started project and change and array, the view changes... until the project grows and it does work anymore... this is really strange and opaque. Detcing array change should be native in ng – Romain Bruckert Jul 13 '18 at 13:09
  • If you want to do similar thing for an Object, you can do : `refreshMe = Object.assign({}, refreshMe);` More on this [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) – Ajmal Moochingal May 03 '20 at 17:24
14

If you use a spread operator instead of push it should work.

this.data = [...this.data, newItem];

The reason for this is that angular detects a change when the whole object changes, or the reference changes, so a mutation isn't going to trigger it. So rather than mutating the array, you need to make it a new array.

cpi
  • 271
  • 3
  • 3