3

Im filtering menu array by permission once user logged in.
Im generating static menu and then give copy of array to filter.

constructor(public menu: MenuService, public permissionService: PermissionService) {
    console.log(menu.getMenu()) // this changes after filtering below
    this.menuItems = this.permissionService.filterMenuByTopic([...menu.getMenu()]); // here I'm using a copy
  }

Why do this happen ? If I have used spread operator and I do not use original array [...menu.getMenu()].
Only If I refresh the pages menu.getMenu() returns to original value

UPD 1
answering to the comments , here is getMenu() func

import { Injectable } from '@angular/core';
@Injectable()
export class MenuService {

  menuItems: Array<any>;

  constructor() {
    this.menuItems = [];
  }


  addMenu(items: Array<{
    text: string,
    heading?: boolean,
    link?: string,     // internal route links
    elink?: string,    // used only for external links
    target?: string,   // anchor target="_blank|_self|_parent|_top|framename"
    icon?: string,
    alert?: string,
    submenu?: Array<any>
  }>) {
    items.forEach((item) => {
      this.menuItems.push(item);
    });
  }


  getMenu() {
    return this.menuItems;
  }

}
Sunstrike527
  • 515
  • 1
  • 4
  • 17
  • Not sure what the `filterMenuByTopic` or `getMenu` does but` [...array]` only creates a shallow copy of the array. The objects will still be the same. – adiga Dec 23 '20 at 07:36

2 Answers2

2

The spread operator creates a shallow copy. If the content of a menu was objects, then changing those objects in a copy array will change those objects in the original array (or technically, those two references are for the same object):

const obj1 = {
  val: 1
}

const obj2 = {
  val: 2
}

const obj3 = {
  val: 3
}

const arr = [obj1, obj2, obj3]

// creating a copy with the spread operator
const copy = [...arr]

// changing the second element in the copy
copy[1].val = 22

// the element in the original array is changed too
console.log(arr)
IvanD
  • 2,728
  • 14
  • 26
  • Yes exactly , I have array of objects, so what is the best way to copy array of object not changing original array with objects ? – Sunstrike527 Dec 23 '20 at 08:12
  • You need to do a deep copy https://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-deep-clone-an-object-in-javascript – IvanD Dec 23 '20 at 08:21
  • use `const copy=arr.map(x=>{...x})` – Eliseo Dec 23 '20 at 09:04
0

Thanks to Ivan's comment
I've made a deep clone by following

const cloned = menu.getMenu().map(x => Object.assign({}, x));
    console.log('cloned ', cloned)
    this.menuItems = this.permissionService.filterMenuByTopic(cloned);

One of the answer I have found here link

Sunstrike527
  • 515
  • 1
  • 4
  • 17
  • Just beware that in case of nested objects, it gets complicated really quickly. You'll need to do deep copy of nested objects too :) – IvanD Dec 23 '20 at 18:37