4

I have 2 Array<object>. One of them has initial elements and another one has its elements added by array.push() in ngOnInit. In the end, both have the elements in output but html doesn't render the elements which were pushed with .push

//the result of array that made by array.push
> [] 
 > 0: {id: '1', title: 'title 1'}
 > 1: {id: '2', title: 'title 2'}
 > 2: {id: '3', title: 'title 3'}
   length: 3
 > __proto__: Array(0)


//initialize array
> (3) [{…}, {…}, {…}] 
 > 0: {id: '1', title: 'title 1'}
 > 1: {id: '2', title: 'title 2'}
 > 2: {id: '3', title: 'title 3'}
   length: 3
 > __proto__: Array(0)

the code

newObj;
error;

myObjects: Array<object> = [];

itsObjects: Array<object> = [
  {
    id: '1',
    title: 'title 1'
  },
  {
    id: '2',
    title: 'title 2'
  },
  {
    id: '3',
    title: 'title 3'
  }
];

ngOnInit() {
  this.subscription = this.mys.myService().subscribe(
    res => {
      this.newObj = res,
      this.myObjects.push(
          {
            id: element.id,
            title: element.title
          }
        )
    },
    error => this.error = error,
  )
}

Solved

The main notice was this.myObjects = this.tmpObj after forEach that collects all elements for pass to out of ngOnInit scope, I edited my code to:

servicOutput; //get data
tmpObj: Array<object> = []; //manage data as temp;
myObjects: Array<object> = []; //for collect all elements to html
error;

ngOnInit() {
  this.subscription = this.mys.myService().subscribe(
    res => {
      this.servicOutput = res,
      this.servicOutput.forEach(element => {
        this.pushFunc(element);
        }
      ),
      this.myObjects = this.tmpObj; //here collect all elements as an object and pass out of ngOnInit scope
    },
    error => this.error = error,
  )
}

pushFunc(element) {
  this.tmpObj.push(
    {
      id:    element.id,
      title: element.title
    }
  )
}
Hama Bohel
  • 95
  • 2
  • 10
  • https://stackoverflow.com/questions/48041597/angular-4-updating-view-on-array-push – Damian Pioś Aug 28 '19 at 09:07
  • Share your html code – Yash Aug 28 '19 at 09:09
  • Please check that you have got success response and log the response first to check the structure, also please mention the html code – Yasser Mas Aug 28 '19 at 09:11
  • this.myObjects = [...this.myObjects,this.newObj[0]] may be it helps. or can you share more details about what problem you are facing? – Rushi Patel Aug 28 '19 at 09:23
  • Angular change detection will not detect elements being pushed into an array, only the reference of the array being changed. – skolldev Aug 28 '19 at 09:24
  • I've updated my question with explain result of each array (dynamic define and direct define element), both of them have elements but only direct define shows in output and has rendered – Hama Bohel Aug 29 '19 at 04:45
  • I have their result in console but seems the read process for render has problem with dynamic array! same progress for static array works correct and render – Hama Bohel Aug 29 '19 at 05:15
  • Could you put your solution into an answer please. – Caltor Feb 26 '20 at 17:24

4 Answers4

2

Angular's change detection mechanism does not handle the content change of an array. You can either change the referance of the array as xdecdec suggested earlier in comments or you can implement your own ngDoChange so that you can implement your own way to detect the change of array content.

Check this answer for further explanation on implementing ngDoChange: https://stackoverflow.com/a/42962723/11420760

talhature
  • 2,246
  • 1
  • 14
  • 28
  • my code could catch elements and push into array and I have all elements inside array but couldnt use them and render it – Hama Bohel Aug 29 '19 at 04:48
  • I can't see a comment by xdecdec so no idea what that refers to. Perhaps it has been deleted. – Caltor Feb 27 '20 at 12:43
2

Angular doesn't detect changes within an array. It only detects when the reference to the array itself changes. To get the html to re-render you need to use one of the following methods which will alert Angular that something has changed.

Method 1 - Use rest / spread operator instead of a push to change the array

Kudos to Rushi Patel for this method.

this.myObjects = [...this.myObjects, this.newObj[0]];

Method 2 - Use rest / spread operator to change array reference after a push

this.myObjects.push(this.newObj[0]);
this.myObjects = [...this.myObjects];

Method 3 - Use JSON.stringify/parse to change array reference after a push

this.myObjects.push(this.newObj[0]);
this.myObjects = JSON.parse(JSON.stringify(this.myObjects));

Method 4 - Use detectChanges() to notify Angular that something has changed

This is also suggested in https://stackoverflow.com/a/57689299/470014

constructor(private changeDetectorRef: ChangeDetectorRef) { }

public testMethod() {
    this.myObjects.push(this.newObj[0]);
    this.changeDetectorRef.detectChanges();}
Caltor
  • 2,538
  • 1
  • 27
  • 55
0

assuming your service return any value, you can call detectchanges method after each arr.push(), because angular does not recognize changes like push / pop automatically. Like so:

constructor(private changeDetectorRef: ChangeDetectorRef) { }

public testMethod() {
    this.arr.push({name: 'test'});
    this.changeDetectorRef.detectChanges();
}
Caltor
  • 2,538
  • 1
  • 27
  • 55
0

if in this.tmpObj you get all data and the problem is when you try to assign this data to this.myObjects then use slice method from arrays this.myObjects = this.tmpObj.slice()

David
  • 61
  • 4