1

I am trying to process an array in angular. I need to get admin user name from an array and trying below approach

export class AppComponent  {
  adminName = ''
  data = {
    id:1,
    name:'Test User One',
    users:[
      {id:1,name:'User 2',role:'Management Admin'},
      {id:2,name:'User 3',role:'User'},
      {id:3,name:'User 1',role:'Profile Admin'},
    ]
  }

  ngOnInit(){
     this.getAdminName(this.data.users)
  }

  getAdminName(users){
   let name = ''
    name = users.filter((user)=>{
      user.role = user.role.replace(/\s/g, '-').toUpperCase()
      return user.role === 'PROFILE-ADMIN'
    }).map(row=>{
      return row.name
    })
    this.adminName = name[0]
  }
}

This is working and i am able to get adminName but it also changes role of data object and converts object like this

{
  "id": 1,
  "name": "Test User One",
  "users": [
    {
      "id": 1,
      "name": "User 2",
      "role": "MANAGEMENT-ADMIN"
    },
    {
      "id": 2,
      "name": "User 3",
      "role": "USER"
    },
    {
      "id": 3,
      "name": "User 1",
      "role": "PROFILE-ADMIN"
    }
  ]
}

I understand why this happened and i tried using spread operator but it is not working i tried below approach

Approach one

this.getAdminName([...this.data.users]) // passing from here using spread operator

Approach Second

getAdminName(users){
   let usersList = [...users]
   let name = ''
    name = usersList.filter((user)=>{
      user.role = user.role.replace(/\s/g, '-').toUpperCase()
      return user.role === 'PROFILE-ADMIN'
    }).map(row=>{
      return row.name
    })
    this.adminName = name[0]
  }

I am able to do it like below

getAdminName(users){
   let name = ''
   let role;
    name = users.filter((user)=>{
      role = user.role //used a variable in which holds 
      role = role.replace(/\s/g, '-').toUpperCase()
      return role === 'PROFILE-ADMIN'
    }).map(row=>{
      return row.name
    })
    this.adminName = name[0]
  }

But I want to do it using spread Operator approach so Please suggest me where i am going wrong

Stackblitz link is here

https://stackblitz.com/edit/angular-rjnytr

Passionate Coder
  • 7,154
  • 2
  • 19
  • 44
  • 1
    `user.role = user.role.replace(/\s/g, '-').toUpperCase()` this will modify the user role. Can you not check without assigining it to `user.role`? – Anurag Srivastava Apr 14 '20 at 17:26
  • yes i know and i explained it in my question i am getting issue in creating copy from spread operator only – Passionate Coder Apr 14 '20 at 17:28
  • Why exactly do you want to use spread syntax? You can filter out any element without changing the data itself. I don't think there is any need to shallow-copy the array first. – Đinh Carabus Apr 14 '20 at 17:29
  • That approach is frankly unnecessary. As long as you use `user.role = user.role.replace(/\s/g, '-').toUpperCase()`, no amount of spread operators will give the desired result – Anurag Srivastava Apr 14 '20 at 17:32
  • ok so could you tell me which one will be better this will help me to know right approach – Passionate Coder Apr 14 '20 at 17:33

5 Answers5

4

I would change filter logic to avoid any side effects.

getAdminName(users) {
  const name = users
    .filter(user => user.role.replace(/\s/g, '-').toUpperCase() === 'PROFILE-ADMIN')
    .map(row => row.name);

  return name ? name[0] : '';
}

This way you do not need to think about how spread operator works.

this.getAdminName(this.data.users) 
yurzui
  • 205,937
  • 32
  • 433
  • 399
2

users is a reference type. So you need to create a deep copy of an object. Try to use JSON.parse method to create a deep copy of an object:

let usersList = [...JSON.parse(JSON.stringify(users))]
StepUp
  • 36,391
  • 15
  • 88
  • 148
  • In this specific case, this may work, but generally, you will lose any functions and non-enumerable properties for your objects using this method of "deep copy" Also, deep copying has been covered in [many](https://stackoverflow.com/q/122102/215552) [many](https://stackoverflow.com/q/39968366/215552) [duplicates](https://stackoverflow.com/q/38416020/215552)... – Heretic Monkey Apr 14 '20 at 17:32
0

In your function, replace the user.role = user.role.replace(/\s/g, '-').toUpperCase() by a new variable, this:

getAdminName(users){
   let usersList = [...users]
   let name = ''
    name = usersList.filter((user)=>{
      let role = user.role;
      role = role.replace(/\s/g, '-').toUpperCase()
      return role === 'PROFILE-ADMIN'
    }).map(row=>{
      return row.name
    })
    this.adminName = name[0]
  }
Reynier Rivero
  • 2,042
  • 2
  • 8
  • 12
  • 1
    This is the same as what the user has in their question, except it has `let` in front of the definition of `role`. Which is great, but... – Heretic Monkey Apr 14 '20 at 17:36
0

First of all, Spread operation won't work,

Reason, it's only helpful for single layered data structure, meaning array of primitive data types, for array of objects it dose not create deep copy when nested properties are in picture.

So you should use Lodashs cloneDeep method.

UPDATED

install lodash in your angular project

Then import it like

import { cloneDeep } from 'lodash'; Blockquote

and use it like,

  getAdminName(users){
   let usersList = cloneDeep(users);
   let name = ''
    name = usersList.filter((user)=>{
      user.role = user.role.replace(/\s/g, '-').toUpperCase()
      return user.role === 'PROFILE-ADMIN'
    }).map(row=>{
      return row.name
    })
    this.adminName = name[0]
  }

This should solve your problem here

Indrajeet
  • 491
  • 3
  • 10
0

The spread operator on the array do just that spreads the array. In the way you are using it you are simply passing an equivalent amount of arguments to the getAdmin() method or the userList variable as the elements in the array.

Try something like this:

ngOnInit(){
 this.getAdminName(this.data.users)
}

getAdminName(users){
   const adminUser = users.find(({ role }) => {
     role = role.replace(/\s/g, '-').toUpperCase()
     return role === 'PROFILE-ADMIN'
   });
   this.adminName = adminUser.name;
}
jogarcia
  • 2,327
  • 2
  • 19
  • 34