Search code examples
javascriptjquerytwitter-bootstrapmeteorspacebars

How to make closable tabs with Meteor? My solution, your feedback


Note: as I wrote this question, I solved it. Since I think it would be useful for both others and me to have feedback on my approach, I finished explaining the different steps. Feel free to comment/answer.

Hello,

I want to dynamically load/unload tabs using a dropdown for loading and a close button for unloading. I use bootstrap.

See my answer for the approach.


Solution

  • Here is what seems to me the best way to achieve that:

    1. In my template.created function, I create a local collection as follows

      tabs = new Meteor.Collection(null);
      
    2. I create an array to hold my collection data

      var myArray = [
      {
              "name": "List",
              "template": "This is the list view",
              "loaded": true,
              "active": true,
              "diplayed": true,
              "icon": "fa fa-bars"
          },
          {
              "name": "Gallery",
              "template": "This is the gallery view",
              "loaded": false,
              "active": false,
              "diplayed": false,
              "icon": "fa fa-bars"
          }
      ];
      
    3. I iterate on my array to load every item in my local collection

      for (var i = 0; i < myArray.length; i++) {
          tabs.insert(myArray[i]);
      }
      
    4. I load my collection elements using {{#each loadedTabs}} for the nav-tab and {{#each nonLoadedTab}} for the dropdown. Here are what the helpers look like:

      nonLoadedTabs: function(){
          return tabs.find({"loaded":false})
      },
      
    5. I add an event attached to the close button and another to the dropdown select

      'click .closeTab' : function(){
          tabs.update (this._id, {$set: {loaded:false}});
      },
      'click .tab_load_button' : function(){
          tabs.update (this._id, {$set: {loaded:true}});
      }
      
    6. Now I must add with the "active" class to the right tab in order to let bootstrap deal with the tab content display. To do this, I add a few lines to my click events.

      The load event unset the "active" tab item and add it to the current one:

      'click .tab_load_button' : function(){
          //remove the "active" in other tabs
          $(".nav-tabs").each(function() {
              if($(this).find("li.active")) {
                  $(this).find("li.active").removeClass("active");
              }       });
          //update the newly loaded/active tab
          tabs.update (this._id, {$set: {loaded:true, active:true}});
      }
      

      or alternatively using my "active" field in both operations:

      'click .tab_load_button' : function(){
           //remove the "active" in other tabs
           tabs.update ( {active:true}, {$set: {active:false}});
           //update the newly loaded/active tab
           tabs.update (this._id, {$set: {loaded:true, active:true}});
      }
      

    The close button set the "active" class to the first loaded tab found (couldn't find how to get the last):

        'click .closeTab' : function(){
        tabs.update (this._id, {$set: {loaded:false}});
        //if we closed an active tab...
        if (this.active){
            //set the first loaded tab as active
            tabs.update ( {loaded:true}, {$set: {active:true}},{multi:false});
        }
    },