Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Meteor Iron-Router Layout Rendering

We have implemented a layout where the main content resides in dynamic sidebars. We defined following layoutTemplate:

<template name="layout">
  {{> content}}

  {{> leftbar}}

  {{> rightbar}}

  <nav class="navigation">
      {{#if currentUser}}
          {{> navigation_logged_in}}
      {{else}}
          {{> navigation_logged_out}}
      {{/if}}
  </nav>
</template>

We include e.g. the rightbar template in the layout template.

<template name="rightbar">
  <aside class="rightbar">
      <button id="closeRightBar" class="close-cross"></button>

      {{yield 'rightbar'}}
  </aside>
</template>

The rightbar template includes the rightbar yield where we yield the specific content into.

We have implemented following RouteController:

UserShowRouter = RouteController.extend({

  before: function() {
      var username = this.params.username;
      if(App.subs.user) {
          App.subs.user.stop();
      }
      App.subs.user = Meteor.subscribe('user', username);
  },

  waitOn: function () {
    return Meteor.subscribe('user');
  },

  data: function() {
      return Meteor.users.findOne({'profile.username': this.params.username});
  },

  action: function() {
      this.render('profile', {to: 'rightbar'});
  }

});

What we wanted to achieve is that for example the profile template is yielded into the rightbar yield and get's updated and re-rendered as the data changes.

The problem is now that the sidebars are dynamically animated, shown and hidden. Now every time the profile template gets re-rendered also the layout template gets re-rendered. Why is that? We thought one of the purposes of yield regions is that the whole site doesn`t need to be re-renderd. Now when the layout gets re-rendered the whole css of the animations are set back to the original values.

We now have tried several different approaches, but none of them seems to be a good and clean solution. Is there a way to keep the layout template from being re-rendered and just keep the yield region and template up-dated? Any suggestions or alternatives would be highly appreciated.

like image 232
Michael Birsak Avatar asked Nov 11 '13 15:11

Michael Birsak


2 Answers

As I understand it, the behavior in which re-rendering of your templates "bubbles up" and causes re-rendering of their parent templates is not particular to iron-router or the way your code is implemented, but is inherent in Spark. Iron-router's {{yield}} pattern does not alter this behavior, as far as I can tell from its documentation.

The good news is that Spark is set to be replaced imminently with a newer, more fine-grained rendering engine, currently codenamed "Spacebars," which should alleviate the concern.

Here is a preview of the new rendering system:

https://github.com/meteor/meteor/wiki/New-Template-Engine-Preview

This talk from a week ago is also excellent at describing the benefits coming through the new rendering engine (while fairly long, an overview is given in the first 5 minutes):

https://www.youtube.com/watch?v=aPf0LMQHIqk

As for your options today, you can:

a) Use the {{#constant}} and {{#isolate}} parameters to try to limit re-rendering.

b) Work from a development branch as described in the link above:

You can play with the current work-in-progress version of the code using the template-engine-preview-4 release tag (run your app with meteor --release template-engine-preview-4), or by checking out the shark branch (it's an internal codename).

c) Best of all if the timeframe of your project allows is to allow the re-rendering to continue until Meteor 1.0 hits and "Spacebars" resides on the main branch - it sounds like this is 1-3 months away.

like image 51
Jeremy S. Avatar answered Nov 15 '22 09:11

Jeremy S.


I think that the reason your layout template gets rerendered is because the data hook you implemented uses a reactive data source. If the current user object changes, the router probably decides to rerender the whole page because there is no simple way to decide which parts exactly depend on your reactive data.

If I'm right, a simple solution to your problem is to create a user helper that will fetch the necessary data only where they're actually needed, e.g.

Template.profile.user = function () {
    return Meteor.users.findOne({/*...*/});
}

Then you can use it in your profile template along with the with helper (sic!), i.e.

{{#with user}}
    ...
{{/with}}

to prevent multiple calls to the Template.profile.user function.

Also, if I were you, I would use the data hook only for data which is required by templates in my layout.

like image 23
Tomasz Lenarcik Avatar answered Nov 15 '22 07:11

Tomasz Lenarcik