funkenstein funkenstein - 5 months ago 16
Javascript Question

Map function nested within a Foreach is not behaving as Expected Why?

Essentially I am attempting to loop through an array of roles and compare it's related permissions with the master list array and set boolean values within this loop. So I want to alter the original array I'm looping over, adding in the values from the master list that don't exist, and setting a true key value pair for the original values, and a false key value pair for the added values. I can console log out all of the data in the loop and the code I've written seems to do as I'm expecting until I log out the final result wherein both nested arrays contain the booleans from the last time around the loop. There must be some gap in my understanding of map. I also feel like there has to be a much simpler way of doing this without nesting (which I'm trying to learn how to avoid or refactor).

Example Code:

let roles = [];
let allPerms = [];
roles.push({
name: 'role 1',
label: 'role-label-1',
permissions: [
{
name: 'permission 1',
label: 'permission-1'
},
{
name: 'permission 2',
label: 'permission-2'
}]
},
{
name: 'role 2',
label: 'role-label-2',
permissions: [
{
name: 'permission 3',
label: 'permission-3'
},
{
name: 'permission 4',
label: 'permission-4'
}]
});

allPerms.push({
name: 'permission 1',
label: 'permission-1'
},
{
name: 'permission 2',
label: 'permission-2'
},
{
name: 'permission 3',
label: 'permission-3'
},
{
name: 'permission 4',
label: 'permission-4'
});

console.log(roles);
console.log(allPerms);

function setRoles() {
roles.forEach(function (val, key, array) {
let selected = _.difference(array[key].permissions, allPerms);
let mappedPerms = allPerms.map( function(v, k) {
let name = _.find(selected, function(i) {
return i.name == v.name;
});
if (typeof name != "undefined" && name.name == v.name) {
v.selected = true;
} else if (typeof name == "undefined"){
v.selected = false;
}
return v;
});
console.log('ROLE '+key);
console.log(mappedPerms[0].selected);
console.log(mappedPerms[0].name);
console.log(mappedPerms[1].selected);
console.log(mappedPerms[1].name);
console.log(mappedPerms[2].selected);
console.log(mappedPerms[2].name);
console.log(mappedPerms[3].selected);
console.log(mappedPerms[3].name);
array[key].permissions = mappedPerms
});
return roles;
}

let testRoles = setRoles();
console.log(testRoles);


Here is a jSFiddle working example of the problem:
https://jsfiddle.net/patrickisgreat/fu3hza1w/1/

Expected Output:

[
{
"name": "role 1",
"label": "role-label-1",
"permissions": [
{
"name": "permission 1",
"label": "permission-1",
"selected": true
},
{
"name": "permission 2",
"label": "permission-2",
"selected": true
},
{
"name": "permission 3",
"label": "permission-3",
"selected": false
},
{
"name": "permission 4",
"label": "permission-4",
"selected": false
}
]
},
{
"name": "role 2",
"label": "role-label-2",
"permissions": [
{
"name": "permission 1",
"label": "permission-1",
"selected": false
},
{
"name": "permission 2",
"label": "permission-2",
"selected": false
},
{
"name": "permission 3",
"label": "permission-3",
"selected": true
},
{
"name": "permission 4",
"label": "permission-4",
"selected": true
}
]
}
]

Answer

Array.prototype.some could be useful for you here. forEach role we map over allPerms and rebuild the role's permissions. role.permissions.some can be used to check for the pre-existence of a given permission on the role.

function setRoles() {

  roles.forEach(function (role) {

    role.permissions = allPerms.map(function (perm) {

      return {
        name: perm.name,
        label: perm.label,
        selected: role.permissions.some(function (rolePerm) {
          return rolePerm.name === perm.name
        })
      }
    })
  })
}