Question

I tried to play with the leaderboard example by adding a button to toggle sorting by name/score.

I succeed in adding event, but I also want to change the text value on the button.

I expect the added button text value(sort by name/score) get updated reactively(every time I click the button), however it fails to do so, only get updated when manually click on the player item.

Code added:

leaderboard.html(leaderboard template):

    <template name="leaderboard">
    <div class="leaderboard">
    <input type="button" name="sort" value="Sort by {{sort_type}}" class='sort'/>

     {{#each players}}
      {{> player}}
     {{/each}}
    </div>

    {{#if selected_name}}
      <div class="details">
        <div class="name">{{selected_name}}</div>
        <input type="button" class="inc" value="Give 5 points" />
       </div>
    {{else}}
      <div class="none">Click a player to select</div>
    {{/if}}
   </template>

leaderboard.js(client part):

    if (Meteor.isClient) {

    Meteor.startup(function(){
        Session.setDefault('sort_order', {score: -1, name: 1});
    Session.setDefault('sort', 'name');
    }); 

    Template.leaderboard.players = function () {
      return Players.find({}, {sort: Session.get('sort_order')});
    };

    Template.leaderboard.selected_name = function () {
      var player = Players.findOne(Session.get("selected_player"));
      return player && player.name;
    };

    Template.leaderboard.sort_type = function() {
  return Session.get('sort');
    };

    Template.player.selected = function () {
      return Session.equals("selected_player", this._id) ? "selected" : '';
    };

    Template.leaderboard.events({
      'click input.inc': function () {
        Players.update(Session.get("selected_player"), {$inc: {score: 5}});
      },

      'click input.sort': function(){
        var sort_order = Session.get('sort_order');
    if (_.isEqual(sort_order, {score: -1, name: 1}) || _.isEqual(sort_order, {score: 1})) {
        Session.set('sort_order', {name: 1});
            Session.set('sort', 'score');
    } else if (_.isEqual(sort_order, {name: 1})){
        Session.set('sort_order', {score: 1});
        Session.set('sort', 'name');
    }  

  }
    });
      Template.player.events({
        'click': function () {
           Session.set("selected_player", this._id);
        } 
    });
   }

Thanks!

B.R.

Ian

Was it helpful?

Solution

This has to do with the preserve-inputs package. From the Meteor Docs:

By default, new Meteor apps automatically include the preserve-inputs package. This preserves all elements of type input, textarea, button, select, and option that have unique id attributes or that have name attributes that are unique within an enclosing element with an id attribute. To turn off this default behavior, simply remove the preserve-inputs package.

So basically because your button has a name attribute, Meteor is preventing it from changing when the template is re-rendered. There are three ways you can solve this:

  1. Simply remove the name attribute from your input.sort attribute.

  2. Remove the preserve-inputs package (not recommended if you're using the current template engine).

  3. You can use the preview release of the new Meteor template engine, which no longer needs the preserve-inputs package because it automatically does more fine-grained DOM updates. You can run the app once with the preview release using:

    meteor --release shark-1-29-2014-e
    

    Or you can tell Meteor to update your app to this version by running:

    meteor update --release shark-1-29-2014-e
    

    Note that this new templating engine will be included in the Meteor core release by 1.0.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top