I have a helper for a 'userLayout' template, in which I've defined a current user function. It works fine when I navigate to the template (i'm using flow router with subscriptions in the route). However, when I press 'back' in the browser, the helper fires again.
Why is the helper firing for the template I'm leaving when I press 'back'?
My code for one of the offending helpers is here - I suspect the 'context' attribute:
// Return a specific user
findUser: function(context) {
var id = context.user;
return Potential_users.find({_id: id});
}
EDIT
The view template itself looks like this:
<template name="userLayoutView">
{{#each findUser context}}
...
{{/each}}
</template>
And that view is getting called dynamically like so:
<template name="userLayout">
<div class="row">
<div class="col-xs-12">
{{#if currentUser context}}
{{> userLayoutEditCreate context=context}}
{{else}}
{{> userLayoutView context=context}}
{{/if}}
</div>
</div>
</template>
Related
Template.onRendered :
Callbacks added with this method are called once when an instance of Template.myTemplate is rendered into DOM nodes and put into the document for the first time.
Is there any way to call something after the DOM changed?
For example, a navbar(header) with login/logout button is rendered after user open the homepage, and the navbar is changed after the user logged in(logout button).
I need to do something after the navbar has been changed.
You can refactor your code by creating new templates to introduce finer grained lifecycle events on child templates.
HTML
<template name="navbar">
<div class="navbar">
{{#if currentUser}}
{{> logoutButton}}
{{else}}
{{> loginButton}}
{{/if}}
</div>
</template>
<template name="loginButton">
<button class="login">Login</button>
</template>
<template name="logoutButton">
<button class="logout">Logout</button>
</template>
JS
Template.loginButton.onRendered(function(){
// will print Login after user logged out
console.log(this.$("button").text());
});
Template.logoutButton.onRendered(function(){
// will print Logout after user logged in
console.log(this.$("button").text());
});
Alternatively, you can use an autorun inside Template.navbar.onRendered to listen to user login/logout and perform actions after DOM has been modified using Tracker.afterFlush.
HTML
<template name="navbar">
<div class="navbar">
{{#if currentUser}}
<button class="logout">Logout</button>
{{else}}
<button class="login">Login</button>
{{/if}}
</div>
</template>
JS
Template.navbar.onRendered(function(){
// declare a new reactive computation
// (rerun when the reactive data source is modified)
this.autorun(function(){
// listen to the same reactive data source as in the template helper
// => currentUser
var user=Meteor.user();
// this code will run after every other reactive computations depending
// on the same data source being modified
Tracker.afterFlush(function(){
// will print Logout after user logged in
// will print Login after user logged out
console.log(this.$("button").text());
}.bind(this));
}.bind(this));
});
I´m just starting with meteor coming from ember. What i have is a menu and the items get rendered into the maincontent layout. Now i would like to have a second menu in the maincontent layout.
Example: I click on people in the navigation and get a list of people. Now i click on a person and i get the details of that person. The navigation is still visible. This is what i have so working so far.
Now i would like to have another menu in the person template with items like todo, events.
Router.configure({
layoutTemplate: 'layout'
});
<template name="person">
//shows the details of that one person
</template>
<template name="events">
//shows the events of that one person
</template>
<template name="todos">
//shows the todos of that one person
</template>
<template name="personlayout">
persondetails
todos
events
</template>
The 3 links obove should always be visible as long a the person template is shown. Like when navigating to localhost:3000/person/5403789845ef834ed58ae745
So how can i render the person or todos or events template in the personlayout template?
First you need to define yield in personLayout.
<template name="personLayout">
{{yield}}
{{yield "persons"}}
{{yield "todos"}}
{{yield "events"}}
</template>
Now you can use this layout:
Using Routes
Router.route('/post/:_id', function () {
this.layout('personLayut');
// render the Post template into the "main" region
// {{> yield}}
this.render('Post');
// render the person template into the yield region named "person"
// {{> yield "persons"}}
this.render('person', {to: 'person'});
// render the todos template into the yield region named "todos"
// {{> yield "todos"}}
this.render('todos', {to: 'todos'});
});
Using contentFor
<template name="Page">
<p>
EVerything from here is going to `personLayout` {{> yield}}
</p>
{{> contentFor region="person" template="person"}}
{{> contentFor region="todos" template="todos"}}
{{> contentFor region="todos" template="events"}}
</template>
Read IronRouter docs
i would like to trigger the visibility of a block in my handlebars template from an onclick function. i can use sessions and a helper function to get this to work but it seems overkill.
<template name="eventlist">
{{#each eventcollection}}
<div class="eventcontent">
name: {{name}} <br>
{{#if showdetail}}
detail: {{detail}}
{{/if}}
</div>
{{/each}}
</template>
could it be possible to make it work somehow like this?
Template.eventlist.events = {
'click .eventcontent': function() { this.showdetail = true}
}
meteor would just need to check if any attribute of this changed after the event completed and then rerender the template
Why bother Meteor? Such things were easy to achieve in the ancient Javascript days:
<template name="eventList">
{{#each eventCollection}}
<div class="eventContent">
name ...
<span class="eventHidden" style="display: none;">
detail ...
</span>
</div>
{{/each}}
</template>
Template.eventList.events({
'click .eventContent': function(e) {
$(e.target).find('.eventHidden').toggle();
},
});
I have this Template:
<template name="body">
{{#if key}}
{{> mite}}
{{else}}
{{> settings}}
{{/if}}
</template>
and
<template name="settings">
<h1>The settings</h1>
<form class="form-inline">
<input id='apiKey' type='text' name='apiKey' placeholder='your API-Key'>
<button id='saveSettings' type='submit' class='btn'>save</button>
</form>
</template>
<template name="mite">
<div>
<h3>...here with key</h3>
<p>
<a id="optout" href="#">not your key?</a>
</p>
</div>
</template>
When I show the settings-form where the user can set the key needed to show the 'mite' template. Now when i 'submit' the form the page get reloaded and the 'mite' template is shown.
On the mite template I'd like to have that link 'not your key?' or something that deletes the key and then shows the settings-form again. It works with a reload... but can't I do this without all the reloading in Meteor? How can i 'call' the template part with the #if in the body template?
-- Renato
You need to bind an event handler to your form and use preventDefault() to stop it submitting. e.g
client side js
Template.settings.events({
'submit':function(event,template) {
event.preventDefault();
var apiKey = template.find('input[name=apiKey]').value;
//..rest of logic to handle submit event
Session.set("key",true);
}
});
You can then use a template helper with Session.get("showthistemplate") to decide whether to show another template or not: (this is a universal helper since you're putting it in and not a template:
Handlebars.registerHelper('key',function() {
return Session.set("key",true);
});
I have three simple Templates in Meteor, and a Collection on the server with any combination of their names. I want to be able to render these templates dynamically based on which of their names are in the Collection.
Currently I am trying to accomplish this by using the client to subscribe to the Collection, and access the names through a template function. Unfortunately, if I try to run ">" on the names, Meteor attempts to render the variable name instead of the Template pointed to by its value.
So instead of rendering the html in template1, template2, and template3, the output is merely their names on the page: "template1 template2 template3".
Here is the code I've been using, I hope there's a way to solve my issue without having to run Meteor.render manually.
Server js:
TemplatesToRender = new Meteor.Collection("templatesToRender");
TemplatesToRender.insert({templateName: "template3"});
TemplatesToRender.insert({templateName: "template2"});
Client html:
<body>
{{#each templatesToRender}}
{{> templateName}} // meteor trying to render a template
// called "templateName" instead of the
// variable inside templateName.
{{/each}}
</body>
<template name="template1">
<span>Template 1</span>
</template>
<template name="template2">
<span>Template 2</span>
</template>
<template name="template3">
<span>Template 3</span>
</template>
You can make a render helper:
Handlebars.registerHelper('render', function(name, options) {
if (Template[name])
return new Handlebars.SafeString(Template[name]());
});
And use it with
{{render templateName}}
You might want to try this
in your html
<body>
{{> templateToRender}}
</body>
<template name="templateToRender">
{{! use below to detect which template to render}}
{{#if templateName "template1"}}
{{> template1}}
{{/if}}
{{#if templateName "template2"}}
{{> template3}}
{{/if}}
{{#if templateName "template3"}}
{{> template3}}
{{/if}}
</template
<template name="template1">
<p>this is template1</p>
</template>
<template name="template2">
<p>this is template2</p>
</template>
<template name="template3">
<p>this is template3</p>
</template>
in your script
Template.templateToRender.templateName = (which) ->
# if user have a field like templateName you can do things like
tmplName = Meteor.user().templateName
# Session.equals will cause a template render if condition is true.
Session.equals which, tmplName
Meteor 1.0 just came out today, and I just want to update this for 2014 :)
https://docs.meteor.com/#/full/template_dynamic
{{> Template.dynamic template=template [data=data] }}
Sample Usage:
{{#each kitten}}
{{> Template.dynamic template=kitten_type data=this }}
{{/each}}