0

I'm using underscore in an Angular controller and attempting to turn a string into an object with several properties.

vm.availableGames = _.each(availableGames, function(game) {
  game.name = game;
  if (_.contains(user.allowed_games.games, game)) {
    game.allowed = true;
  } else {
    game.allowed = false;
  }
});

availableGames is an array of strings of available games allowed_games is also an array of strings of allowed games

My aim is to create an array of objects (vm.availableGames) which contains all available games. Each of these objects will have a name property (the original string) and an allowed property (a boolean).

The above code results in a Cannot assign to read only property... error. How would I go about accomplishing what I'm aiming for without running into this error?

MattDionis
  • 3,534
  • 10
  • 51
  • 105
  • 3
    `_.each` doesn't return anything. You can use `_.map` instead (and `return game;` after your if/else block) – Matt Jan 13 '16 at 14:30
  • @Matt, I still encounter the same error because I'm still attempting to assign properties (`name`, `allowed`) to a string `game`. However, if I setup a new empty object (`var gm = {}`) and then do `gm.name = game` it works. Thanks for pointing me in the right direction. – MattDionis Jan 13 '16 at 14:36

2 Answers2

2

this should work:

vm.availableGames = _.map(availableGames, function(game) {
  return {
    name: game,
    allowed: _.contains(user.allowed_games, game)
  };
});

and without underscore:

vm.availableGames = availableGames.map(function(game) {
  return {
    name: game,
    allowed: (user.allowed_games.indexOf(game) !== -1)
  };
});
gabrielperales
  • 6,935
  • 1
  • 20
  • 19
-1

It's not underscore, but will this work?

vm.availableGames = [];

for( game in availableGames ) {
    if( allowed_games.indexOf(game) !== -1 )
        vm.availableGames.push({ allowed: true, name: availableGames[game] });
    else
        vm.availableGames.push({ allowed: false, name: availableGames[game] });
}
for( game in allowed_games ) {
    if( availableGames.indexOf(allowed_games[game]) !== -1 )
        vm.availableGames.push({ allowed: true, name: allowed_games[game] });
}

EDIT: Answer using forEach...

NOTE: This only works if everything in allowed_games is also in availableGames.

availableGames.forEach(function( game ) {
    vm.availableGames.push({ allowed: allowed_games.indexOf(game) !== -1, name: game });
});
birdoftheday
  • 816
  • 7
  • 13
  • This answer assumes ES6, doesn't use strict equality tests, and doesn't use braces for if statements? _sigh_ – Matt Jan 13 '16 at 14:40
  • Sorry, where am I assuming ES6? I kind of wrote the second part in a rush. – birdoftheday Jan 13 '16 at 14:42
  • `for..of` in the first part of the answer. – Matt Jan 13 '16 at 14:42
  • Oh, I'm just to assumed to all major browsers supporting it that I forgot it was ES6. Should be an easy fix – birdoftheday Jan 13 '16 at 14:43
  • ~You just need to remove that first part of the answer, because `for..in` needs a [`hasOwnProperty`](http://stackoverflow.com/a/684692) check anyway.~ Actually, for arrays, that doesn't matter I guess. Also that condition can be inlined into the `allowed` boolean (see my edit on the second part). – Matt Jan 13 '16 at 14:47
  • @Matt no, in modern code `for .. in` does _not_ need a `hasOwnProperty` check. However you shouldn't use `for .. in` on arrays anyway. – Alnitak Jan 13 '16 at 14:56
  • I guess I was right to get the downvote... If people want to use bloated frameworks that replace vanilla JavaScript with slow methods, that's their choice and they'll probably not want to compromise their beliefs – birdoftheday Jan 13 '16 at 19:48