FlowRouter & FlowLayout - setting data scope/context

I might be overlooking it, but I can’t seem to find how to set the data scope/context for templates & routes… ?

If I want to load a document to be used as the context for a template, I have no idea how to do it unless I use a helper and wrap the template with {{with}}

Use helpers.

If you do something like

Template.myTemplate.helpers({
  article: function () {
    return Articles.findOne()
  }
});

you can call it with {{article.title}} and {{article.text}} etc without using {{#with}}

1 Like

Ahh I didn’t think of doing that.

In my hack I set a global helper to do what you’ve got there… so I just need to reference it like you’ve suggested with the dots :smiley:.

Hehe, whatever works man.

Check out https://meteorhacks.com/flow-router-and-subscription-management as well

1 Like

Yeah I had a read of that before, but nothing jumped out at me.
Thanks again for the tip :smile:

Yeah so thinking about this some more, there are many more advantages to having a data context for the template.
You can retrieve the context through helpers and events etc…
Isn’t that completely missing now?

How do you mean? the data-option in iron:router?

I think the data() hook of Iron Router is the exact equivalent of {{#with templateHelper}}. So I am not sure what you are missing here…

I would have thought he’s missing Iron Router, isn’t he? (given the topic name)

I think using {{#with templateHelper}} is actually the way to go if you’re going to be using a lot of pieces of info from the data context (in this case, a single document from the Articles collection). Using a helper like

Template.myTemplate.helpers({
  article: function () {
    return Articles.findOne({some:"condition"})
  }
});

is okay if you’re happy to do a findOne every time you want something from the data context in your template, but if the Articles collection has a large number of documents on the client and you’re doing findOne repeatedly to supply your template with little bits of data, this can lead to slow down in rendering. Using with you’re just doing the findOne once.

If you’re just subscribed to the one document from the Articles collection, then nothing to worry about – either approach will be nice and snappy.

Sorry my post could have been 100000x clearer if I explained myself better!

With iron router you can set the data context for a route using:

Router.route('/post/:_id', function () {
  this.render('Post', {
    data: function () {
      return Posts.findOne({_id: this.params._id});
    }
  });
});

Which is nice and simple.
With flow router it doesn’t have that same shortcut…
So templates themselves don’t get their data context set by the router, you need to wrap them with {{#with datacontext}} before you insert the template.

1 Like

Exactly.
Which, in my opinion, is nicer and simpler than using yet another Iron Router unpredictable hook :- )

Yeah the only thing that is a bit annoying about that is, then you need to have two templates… One for the router to reference, and then you need to nest another within the {{#with}} if you want to have the context recognised against the template as a whole…

I could be missing something simple, I’ve been using iron-router since day 1 and I am sure I have just not learned the proper way to do some things…

example:

// this is the one, which your router points to...
<template name="outertemplate">
    {{#with dataContext}}
    {{> innerTemplate}}
    {{/with}}
</template>

<template name="innertemplate">
   This template can make use of the data context...
   As can all the helpers, events and functions for `innertemplate` ...
</template>

Obviously you are troubled, but I still cannot see the reason. Taking your code above, let’s put it this way:

// this is the one, which your router points to...
<template name="outertemplate">
    {{> innerTemplate}}
</template>

<template name="innertemplate">
    {{#with dataContext}}
    ...
    {{/with}}
</template>

And finally this way:

// this is the one, which your router points to...
<template name="mytemplate">
    {{#with dataContext}}
    ...
    {{/with}}
</template>

One template only!

1 Like

I might have missed something…

So are you able to use that data context within:

Template.mytemplate.helpers({
   example: function() {
       console.log(this); // <-- will `this` be the `dataContext` object/document??
   }
});

// Likewise with:

Template.mytemplate.events();
Template.mytemplate.onCreated();
and, etc...

For Template.mytempate.onCreated, no this.data won’t be the data context you want. But for the helpers and events, presumably they’re all going to be used/triggered by elements inside the #with block, so this will be the data context you’re after.

1 Like

Thanks for putting up with my posts… I am pretty sure I get it now.
Will have a go at this in a couple hours.

Despite this being such a basic concept I was clearly very confused :worried: haha.

1 Like