Second execution of templates


#1

Hi,
I have the following templates when implementing file tree for my app. How ever, the templates seem to be getting inserted twice and a flicker of previous tree is wiped out with no data and no tree found the second time. Can anyone throw light on this? if i do not use runOnce in helpers, the method runs twice. Any help is appreciated.

Meteor.startup(function(){
runOnce = 0;
});

Template.fileTreeTemplate.helpers({
treeItems: function() {
    if(runOnce == 0) {
        console.log(" firstItems");
        if(myFolders == null) console.log("Folders is null");
        var items = myFolders.find({parent : 0});
        console.log(" firstItems length=" + items.count());
        runOnce = 1;
        return items;
    }
}
});

Template.levelATemplate.helpers({
hasChildren: function() {
    console.log("there are A children " + myFolders.find({parent: this._id}).count());
    return myFolders.find({parent: this._id}).count() > 0;
},
children: function() {
    console.log("found A children "+ myFolders.find({parent: this._id}).count());
    return myFolders.find({parent: this._id});
}
});

Template.levelBTemplate.helpers({
hasChildren: function() {
    console.log("there are B children " + myFolders.find({parent: this._id}).count());
    return myFolders.find({parent: this._id}).count() > 0;
},
children: function() {
    console.log("found B children "+ myFolders.find({parent: this._id}).count());
    return myFolders.find({parent: this._id});
}
});

<template name="fileTreeTemplate">
<div id="tree" style="height: 200px">
  FileTree
  {{#each treeItems}}
    <li id="{{id}}" title="{{name}}">
           {{name}}
        {{> levelATemplate}}
    </li>
  {{/each }}
  </div>  
</template>

<template name="levelATemplate">
{{#if hasChildren}}
    <ul>
    {{#each children}}
      <li id="{{id}}" title="{{name}}">
          {{name}}
            {{> levelBTemplate}}
      </li>      
    {{/each}}
  </ul>
{{else}}
    {{{nothing}}}
{{/if}}
</template>

<template name="levelBTemplate" >
{{#if hasChildren}}
    <ul>
    {{#each children}}
      <li id="{{id}}" title="{{name}}">
          {{name}}
            {{> levelATemplate}}
      </li>      
    {{/each}}
  </ul>
{{else}}
    {{{nothing}}}
{{/if}}
</template>

<template name="files">
<div id="filesPane">
    <div id="userMsg">FilesMessageBar</div>
    <div>
        <div id="leftTab">
            {{> fileTreeTemplate}}
        </div>
        <div id="centerTab"></div>
        <div id="rightTab"></div>
    </div>
</div>
</template>

#2

Please post a simplified version of your code.
I don’t see any subscribe. Where do you get your data from? What do you want to display until the data has been downloaded from the server?


#3

I have implemented my own routing solution and i can post part of code here so it makes sense. When i click Files menu item, it populates the myFolders collection with three documents.

Template.siteHome.events({
'click .navi': function (e, t) {
    myFolders.insert({name:"first", parent:0});
    var parents = myFolders.find({parent:0});
    parents.forEach(function(item){
        myFolders.insert({name:"second", parent:item._id});
        myFolders.insert({name:"third", parent:item._id});
    });
    Blaze.render(Template.files, $('#swapDiv').get(0));
}
});

<template name="siteHome">
<nav class="navbar navbar-default" role="navigation">
  <div class="container-fluid">
    <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
      <ul class="nav navbar-nav">
        <li id="files" class="navi"><a href="#">Files</a></li>
      </ul>
    </div><!-- /.navbar-collapse -->
  </div><!-- /.container-fluid -->
</nav>
    <div id="swapArea" class="container-fluid">
    </div>
</template>

The Template.Files is as follows:

<template name="files">
    <div id="filesPane">
        <div id="leftTab">
            {{> fileTreeTemplate}}
        </div>
    </div>
</template>

The fileTreeTemplate is as follows:

<template name="fileTreeTemplate">
  <div id="tree" style="height: 200px">
  FileTree
      {{#each treeItems}}
        <li id="{{id}}" title="{{name}}">
               {{name}}
            {{> levelATemplate}}
        </li>
      {{/each}}
  </div>
</template>

The LevelATemplate is badly named but is as follows:

<template name="levelATemplate">
{{#if hasChildren}}
    <ul>
    {{#each children}}
      <li id="{{id}}" title="{{name}}">
          {{name}}
            {{> levelBTemplate}}
      </li>      
    {{/each}}
  </ul>
{{/if}}
</template>

Similarly, the levelBTemplate is badly named but is as follows:

<template name="levelBTemplate" >
{{#if hasChildren}}
    <ul>
    {{#each children}}
      <li id="{{id}}" title="{{name}}">
          {{name}}
            {{> levelATemplate}}
      </li>      
    {{/each}}
  </ul>
{{/if}}
</template>

The Helper methods are as follows:

Template.fileTreeTemplate.helpers({
    treeItems: function() {
            var items = myFolders.find({parent : 0});
            return items;
    }
});

Template.levelATemplate.helpers({
    hasChildren: function() {
        return myFolders.find({parent: this._id}).count() > 0;
    },
    children: function() {
        return myFolders.find({parent: this._id});
    }
});

Template.levelBTemplate.helpers({
    hasChildren: function() {
        return myFolders.find({parent: this._id}).count() > 0;
    },
    children: function() {
        return myFolders.find({parent: this._id});
    }
});

I am a total newbie to meteor and not a good Javascript programmer, so please forgive my mistakes. The Blaze.render way of injecting is to be able to add any number of ‘panes’, as in DIV based templates, to the DOM in swapArea when something is clicked. I wrote other code to hide all other ‘panes’ and show only the clicked one. The homeSite template goes into just main page where it is inserted depending on user is logged in or not.