Home > Enterprise >  Angular doesn't update object array after object is pushed
Angular doesn't update object array after object is pushed

Time:05-21

I am currently working on project where I use angular-google-map (agm), and I use different polygons to display different things. Now I want to draw on map so I get collection of coordinates which I can use problem is my object array doesn't update.

TLDR: Object array doesn't update when I use .push.

home.component.ts

export class HomeComponent implements OnInit {

ngOnInit(): void { 
}

constructor(private cr: ChangeDetectorRef) { }

//this is my polygon with initial values
pathsLs: any[] = [[
  { lat: 43.51270075713179, lng: 16.468134790981548 },
  { lat: 43.51205153579524, lng: 16.46757689150645 },
  { lat: 43.5119745090715, lng: 16.466895610416667 },
  { lat: 43.51273927004248, lng: 16.466659576023357 },
  { lat: 43.51284380496191, lng: 16.467753917301433 },
  
]]
pointList: { lat: number; lng: number }[] = [];
//this is function I use to update my Object array

addSomething() {
  this.pathsLs.push(this.pointList);
  this.pathsLs = [...this.pathsLs];
  this.cr.detectChanges();
}


Problem is when this function is called I can see on console.log(this.pathsLs) that it's updated and it even draws polygon on map but when I refresh its all back to previous(initial value). I guess that I am asking is there a way to physically see this change for example:

if I do something like this this.pathsLs.push([{ lat: 43.51174, lng: 16.46538 }]) to actually get in my typescript this:

pathsLs: any[] = [[
    { lat: 43.51270075713179, lng: 16.468134790981548 },
    { lat: 43.51205153579524, lng: 16.46757689150645 },
    { lat: 43.5119745090715, lng: 16.466895610416667 },
    { lat: 43.51273927004248, lng: 16.466659576023357 },
    { lat: 43.51284380496191, lng: 16.467753917301433 },
    
  ],[{ lat: 43.51174, lng: 16.46538 }] <-- newly added
]

CodePudding user response:

Are you using HTML component to call the function addSomething() ?

Because your component isnt calling it.

Another thing is your array 'pointList', you are pushing an empty array.


About your log, you maybe has to push to array[0], because you are using an array of arrays.

pathsLs: any[] = [[
    { lat: 43.51270075713179, lng: 16.468134790981548 },
    { lat: 43.51205153579524, lng: 16.46757689150645 },
    { lat: 43.5119745090715, lng: 16.466895610416667 },
    { lat: 43.51273927004248, lng: 16.466659576023357 },
    { lat: 43.51284380496191, lng: 16.467753917301433 },
    
  ],[{ lat: 43.51174, lng: 16.46538 }] <-- newly added
]

pathsLs: any[] = [[]], so you are pushing inside the parent array, and you need to push inside the child array;

Looks like a problem at declaration.

pathsLs: any[] = [
    { lat: 43.51270075713179, lng: 16.468134790981548 },
    { lat: 43.51205153579524, lng: 16.46757689150645 },
    { lat: 43.5119745090715, lng: 16.466895610416667 },
    { lat: 43.51273927004248, lng: 16.466659576023357 },
    { lat: 43.51284380496191, lng: 16.467753917301433 }
]

CodePudding user response:

Stackblitz

As discussed in comments, if you want persistent change to data then you'll need to get data from persistent source like local storage or via server.

I recommend a separation of concerns approach with a service to handle storage, a container to act as a go between, and a dumb child component (reusable) that gets the data and displays it.

Use a parent container component to get the paths and pass these down to your child component displaying them:

<app-child-component [pathLs]="pathLs"></app-child-component>

The child gets the paths via @Input() and displays these

@Input() pathLs: IPathL[][] = [];

a local storage service

import { Injectable } from '@angular/core';
import { IPathL } from './paths.model';

@Injectable()
export class PathsLocalStorageService {
  constructor() {}

  // not required but to make getPaths faster implemented cache
  private cachePathLs: IPathL[][] | null = null;
  private initialValue = [
    [
      { lat: 43.51270075713179, lng: 16.468134790981548 },
      { lat: 43.51205153579524, lng: 16.46757689150645 },
      { lat: 43.5119745090715, lng: 16.466895610416667 },
      { lat: 43.51273927004248, lng: 16.466659576023357 },
      { lat: 43.51284380496191, lng: 16.467753917301433 },
    ],
  ];

  getPaths(): IPathL[][] {
    // if defined return cached value
    if (this.cachePathLs) {
      return this.cachePathLs;
    }

    // get pathLs from local storage
    let pStrOrNull = localStorage.getItem('pathsLs');

    if (pStrOrNull == null) {
      // if no stored value provide following initial value
      return this.initialValue;
    } else {
      // otherwise get from local storage
      let pathLs = JSON.parse(localStorage.getItem('pathsLs')) as IPathL[][];
      // save within app
      this.cachePathLs = pathLs;

      return pathLs;
    }
  }

  setPaths(pathLs: IPathL[][]): void {
    localStorage.setItem('pathsLs', JSON.stringify(pathLs));
  }

  addPath(pathL: IPathL[]): IPathL[][] {
    let pathLs = this.getPaths();
    // add path
    pathLs.push(pathL);

    // save within app
    this.cachePathLs = pathLs;

    // save to local storage
    this.setPaths(pathLs);

    return pathLs;
  }

  resetPaths(): IPathL[][] {
    this.setPaths(this.initialValue);
    this.cachePathLs = this.initialValue;
    return this.initialValue;
  }
}

Obviously API of service can be changed to Observables and a server interaction. In fact the first step to do this is often to mock the service via local storage first (as below), change how any components use the service and then replace the service to a server interaction.

import { of } from 'rxjs'
...
@Injectable()
export class PathsLocalStorageService {
  ...etc
  resetPaths(): Observable<IPathL[][]> {
    this.setPaths(this.initialValue);
    this.cachePathLs = this.initialValue;
    return of(this.initialValue);
  }
}
  • Related