Select multiple <li> elements - best practice?


#1

Hi there, I just started learning Meteor. I’m a quit experienced developer with PHP and Rails but this is my first JavaScript adventure.

I finished the leaderboard tutorial (Meteor Tips Tutorial) and it worked like a charm. Now I am trying to expand the app to improve my understanding and came across the following question:

In the tutorial you can select only one player at a time but I want to be able to select multiple players. (< li > elements) So that when I click on a player it gets selected and when I click on the next player both become highlighted.

I thought it might be a good idea to edit this function from the tutorial:

  Template.leaderboard.events({

      "click .player" : function(){
        var playerId = this._id;
        Session.set("selectedPlayer", playerId)
      }
  }

My approach was to store the players in an array within the “selectedPlayer” session variable but I see quite a lot of people bashing stuff like this as “misusing sessions” as they were intended to be a simple key, value pair and I can’t really argue with that opinion.

Is there a cleaner way to do this?


#2

Hi,

Perhaps you can use a ReactiveVar or better ReactiveDict. Something like

Template.leaderboard.created = function () {
    var instance = this;
    instance.selectedPlayer = new ReactiveDict();
}
Template.leaderboard.events({
  'click .player': function(event, instance) {
     var playerId = this._id;
     instance.selectedPlayer.set(playerId, someData)
     ...

#3

Nothing wrong with what you’re suggesting (using an array in a Session variable), in my opinion. If it’s abusing Session you’re worried about, read this excellent post from @robfallows about the alternatives.

The approach above by @robsw is sound, in terms of keeping the scope limited and the global keyspace in Session unpolluted, and is a pattern that lots of Meteor devs (including myself) would use.


#4

Hey, thanks for the informative answers. I tried to implement the solution with ReactiveDict() but it throws an error:

ReferenceError: Can't find variable: ReactiveDict

#5

You need to meteor add reactive-dict


#6

Sorry @drgonzo I should have mentioned that. Also for ReactiveVar you need

meteor add reactive-var

#7

Nevermind! Adding reactive-dict worked perfectly and I have a working solution now:

  Template.leaderboard.created = function () {
      var instance = this;
      instance.selectedPlayers = new ReactiveDict();
      var playerArray = [];
      instance.selectedPlayers.set({"playerIds": playerArray})
  };


  Template.leaderboard.events({
        "click .player" : function(event,instance){
        var playerId = this._id;
        var playersArray = instance.selectedPlayers.get('playerIds');
        var index = playersArray.indexOf(playerId);

        if(index === -1){
            playersArray.push(playerId);
        }
        else{
            playersArray.splice(index, 1);
        }

        instance.selectedPlayers.set({"playerIds": playersArray});
      }

Thanks for the great support so far, if you have any suggestions I’d be glad to hear them.