Meteor: Forcing rerendering whole template after collection update with Blaze
Asked Answered
Z

5

8

I have a template in which the DOM is changed, and I would like to rerender the template when saving to database. Before Blaze, Meteor would have rerendered the whole template if there was a reactive variable somewhere in the template, but now how can I do this ?

I have a collection of clips set up in an Iron router route :

ClipsController = RouteController.extend({
    data: function() {
      clips = Clips.find({}, {sort: {created: 1}});
      return {clips: clips};
    }
});

And a template for clips :

<template name="clips">
  {{#each clips}}
    {{> clip}}
  {{/each}}
</template>

Then, I have a template for clip :

<template name="clip">
  <article class="clip" id="{{_id}}">
    {{{content}}}
    <ul class="tags">
      {{#each tags}}
        <li><a href="/#{{this}}">#{{this}}</a></li>
      {{/each}}
    </ul>
  </article>
</template>

And a script for this template which changes the DOM and then saves the clip :

Template.clip.events({
  'click .edit': function(event, template) {
    template.$('.tags li').each(function() {
      $(this).text($(this).text().replace(/^#(.*)/, "$1"));
    });
  },

  'click .save': function(event, template) {
    var data = {
      //...
    };

    Clips.update({_id: this._id}, data);

    // How to rerender the template ?
  }
});
Zoochemistry answered 29/4, 2014 at 5:3 Comment(0)
H
13

I don't believe that Blaze provides any way to rerender the entire template as the point of Blaze is to have fine grained updates.

A quick and dirty way to achieve this might be to use Session, a template helper, and an {{#unless}} block that wraps the whole template and then just set the Session key to true before the update and false after causing everything in the {{#unless}} block to rerender.

Template.clips.noRender = function(){
  return Session.get("noRender");
}

Template.clip.events({
  'click .edit': function(event, template) {
    template.$('.tags li').each(function() {
      $(this).text($(this).text().replace(/^#(.*)/, "$1"));
    });
  },

  'click .save': function(event, template) {
    var data = {
      //...
    };

    Session.set("noRender", true);

    Clips.update({_id: this._id}, data, function(){
      Session.set("noRender", false);
    });

    // How to rerender the template ?
  }
});

<template name="clips">
  {{#unless noRender}}
    {{#each clips}}
      {{> clip}}
    {{/each}}
  {{/unless}}
</template>
Hymanhymen answered 1/5, 2014 at 1:8 Comment(3)
That's clever ! In my own case, using a slightly different template for editing / viewing and dynamically switching the template did the trick, but this is a good trick.Zoochemistry
Clever, terrible, but so damn useful. :)Elora
What @AdamMoisa said. Clever, terrible, but so damn useful.Cathartic
S
2

I think this might be a better solution also the meteor way.

../clips.js

Template.clips.onRendered(function(){

   this.autorun(function(){
     Template.currentData();
   });

});

template.autorun(runFunc)

You can use this.autorun from an onCreated or onRendered callback to reactively update the DOM or the template instance. You can use Template.currentData() inside of this callback to access reactive data context of the template instance.

http://docs.meteor.com/#/full/template_autorun

Sweetbrier answered 30/1, 2016 at 18:19 Comment(0)
R
1

Blaze provides an easy way to do this:

var template = Template.instance();
var parentDom = /*where to put your Template*/;
Blaze.remove(template.view);
Blaze.render(Template.clips, parentDom);

What it does is it removes your invalid Template and renders a new one as child. http://docs.meteor.com/#/full/blaze_remove
http://docs.meteor.com/#/full/blaze_render

Reuben answered 15/1, 2016 at 14:54 Comment(0)
B
0

iron-router data action is reactive default.

   clips = Clips.find({}, {sort: {created: 1}});

replace to

  clips = Clips.find({}, {sort: {created: 1}}).fetch();
Bass answered 29/4, 2014 at 9:49 Comment(3)
Both seem to work the same, or am I missing something ?Zoochemistry
The first one returns a cursor (which is a Meteor object), the other gives you an array with results.Rodin
I'm aware of that, but why would I return an array instead of a cursor in that case ?Zoochemistry
M
0

I think a better way is to use Tracker.afterFlush.

For example:

Tracker.autorun ->
    Tracker.afterFlush ->
        # DOM is updated, why don't you do something here?
Mullis answered 12/6, 2015 at 17:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.