Show specific menu only on one page - meteor

I've navigation menu and I would like to display the helper menu button only when the user is on specific page and be hided on others.
I've tried this way, but that doest worked
{{#if Store}}
Filters
{{/if}}
Can you please suggest how achieve this function?

in your template helper, you can lookup the route name with
Router.current().route.getName()
then you can set a helper variable to lookup if you are on this page.
Template.mytemplate.helpers({
'Store': function() {
return Router.current().route.getName() == 'Store'; //the Route name
}
});
then use the Store variable in your template as you did.

Related

Meteor: Using If condition to conditionally display templates when user clicks a navigation link

I have some templates corresponding to different places. I am using a navigation bar which has links to different places(Manali). I want the corresponding template to be displayed when a particular link is being clicked. I tried assigning id to each anchor link and use it inside the #if loop of the main file. Like below.
{{#if equals id 'badrinath'}}
{{> Manali}}
{{/if}
I created a helper function also for the comparison purpose.
UI.registerHelper('equals', function(a, b) {
return a == b;
});
But it isn't working. Can anyone suggest a solution. What property of the link can I capture and use it to display the template accordingly.
You sound to be looking for "routing" functionality.
You might be interested in Iron Router or Flow Router.
You can still implement your functionality without router, as it sounds still a simple situation as described. You are probably just lacking some event listeners to set your id variable to the correct value.
Probably something like:
<a data-role="changetemplate" href="targetTemplate">To Target Template</a>
var id = new ReactiveVar(); // add the reactive-var package
Template.myTemplate.helpers({
id: function () {
return id.get();
}
});
Template.myTemplate.events({
"click a[data-role='changetemplate']": function (event) {
event.preventDefault();
id.set(event.currentTarget.href);
}
});

Can I pass the this._id value from one template helper to another with Meteor?

I have the following templates (.html) with their respected managers (.js files):
adminManageCategories
adminAddCategory
adminUpdateCategory
Consider the following:
<template name="adminManageCategories">
{{#each category}}
<div class="clickme">{{title}}</div>
{{/each}}
{{> adminUpdateCategory}}
</template>
Notice the {{> adminUpdateCategory}} is outside of the iteration. This is also a form, and I want to keep it on the same page.
And admin_manage_categories.js
Template.adminManageCategories.events({
"click .clickme": function(event) {
event.preventDefault();
console.log(this._id);
}
});
Notice the console.log() function, which works, as the template manager is smart enough to know the ID of the item that was clicked.
What I want to do is load this items values into the form when clicked. My example above is slim, but in my real data I have a title, sort order, among other things.
So my question is, what is the proper way to pass the _id from the adminManageCategories template to the adminUpdateCategory template, which is the form?
I can hack at this with JavaScript and make things happen, but I think I'm missing a "Meteor way" of doing things.
You need to use a ReactiveVar to store the currently clicked item.
First you need to run meteor add reactive-var, as it's not a package added by default in a standard meteor web app.
JS:
Template.adminManageCategories.created=function(){
// instantiate the reactive-var in the created callback
// we store it as a property of the template instance
this.currentItemId=new ReactiveVar(null);
};
Template.adminManageCategories.helpers({
// this helper reactively returns the currently clicked item
currentItem:function(){
// retrieve the reactive-var from the template instance...
var currentItemId=Template.instance().currentItemId.get();
// ...to fetch the correct collection document
return Items.findOne(currentItemId);
}
});
Template.adminManageCategories.events({
"click .clickme": function(event,template) {
event.preventDefault();
// assign the correct item id to the reactive-var attached to this template instance
template.currentItemId.set(this._id);
}
});
HTML:
<template name="adminManageCategories">
{{#each category}}
<div class="clickme">{{title}}</div>
{{/each}}
<p>Current item title is : {{currentItem.title}}</p>
{{! pass the currentItem as a parameter to your child template this will be
accessible as {{item}} in the HTML and "this.item" in JS helpers or
"this.data.item" in created/rendered/destroyed callbacks}}
{{> adminUpdateCategory item=currentItem}}
</template>
EDIT:
When I initialize the reactive-var in the created callback, I set it to null, this means that until one item is clicked, the helper will return null too and when you'll try to access this.item._id in the adminUpdateCategory this will fail.
The simplest way to solve this issue is maybe to not initialize the variable to null but to the first item in the collection.
Template.adminManageCategories.created=function(){
var firstItem=Items.findOne({},{
sort:{
sortedField:1
}
});
this.currentItemId=new ReactiveVar(firstItem && firstItem._id);
};
There may still be a case when you have 0 items in the collection, so you'll probably end up having to guard against the existence of the item in the JS.
Template.adminUpdateCategory.helpers({
itemProperty:function(){
return this.item && this.item.property;
}
});

Turning a plain JS Object into a reactive one

I am working on an edit form that has two paths. One is when the user clicks a "New" button, the other is when they click "Edit".
When they click "New", the code sets a form_id Session var to null and a client_id session variable to null, then does a Router.go('formEdit') to load the formEdit template/route.
In the formEdit.js, I do a reactive Template helper (I think that's what they are called, but anyway) like so:
Template.formEdit.form = function() {
var form;
if (Session.equals('form_id', null)) {
// Create empty form
form = {
title: null,
client_id: Session.get('client_id'),
header_fields: [],
form_fields: []
};
} else {
// Load form
form = Forms.findOne({_id: Session.get('form_id')});
}
return form;
}
Basically I check if the form_id was set or not, if so I load it from the Forms collection, if not I create a blank one. I thought this would be pretty simple, really.
The problem is that the created/found form object does not behave in a "reactive" way. If I add header_fields or form_fields the subsequent template code never updates. Both are in a {{#each}} like so:
<template name="formEdit">
...
{{#each header_fields}}
{{> headerFieldOutput}}
{{/each}}
...
{{#each form_fields}}
{{> formFieldOutput}}
{{/each}}
</template>
How do I make it such that I can push header_fields and form_fields onto the form and have the underlying template reactively update the {{#each}}'s?
I think you're going about it a little differently than what the reactive programming methodology in Meteor is expecting.
You're putting the 'display' logic in your template helper, rather than using the template scaffolding itself to do it.
So, declare a very simple template helper, something like this:
Template.formEdit.form = function () {
return forms.findOne(Session.get("form_id"));
};
And then, in your template scaffolding have something like this:
{{#if form}}
{{#with form}}
{{#each header_fields}}
etc...
{{/with}}
{{#else}}
[[insert your blank form scaffolding in here]]...
{{/if}}
Then, as you set your Session form_id variable, you can set it to null to invoke the {{#else}} portion.
There are more details than this (logic in the form submit click handler to identify if you are performing an update or an insert, for example) but hopefully you get the gist of it from this.
You should try to gain a better understanding about how cursors and reactive computations work, as it will help you better understand how to best use the reactive methodology. A good starting place is the parties example (watch the video and walk through the code manually). It's similar to what you're doing, and shows a good way of building your templates for when you don't have a 'selected' object.
Hope this helps!

meteor app: how to properly use a button to influence the route

I'm working on a survey/wizard type of meteor application.
The interface will only have two navigation buttons, who's caption/value will be determined dynamically based on whatever step a given user is currently at.
My question is: what markup syntax should I use within each of these two button's definitions in order to direct the Iron Router to change the route. Another words, where in the button definition should I put this: this.redirect('/anotherpath') ?
If you have a button in your template. If you are using a hrefs check answer from f3rland.
html:
<button #id="mybutton>m<Button</button>
you can catch the buttonpress event with javascript
js
Template.myTemplate.events({
'click #myButton': function(event, template) {
event.preventDefault();
Router.go('anotherpath');
}
});
The router should look like:
Router.map(function() {
this.route('anotherpath', {
path: '/',
layoutTemplate: 'myLayout',
controller: myController
});
});
I suggest you to use Iron-Router pathFor helper in your template
{{buttonText}}
That will redirect the user to the corresponding page/template.
You should also take a look at new blaze pattern to define custom block helper
Edit:
You could also use a custom helper for dynamic route as mentioned here
UI.registerHelper("_foo", function fooHelper() {
var templateName = figureOutNameDynamically(this.context.criticalInfo);
return Template[templateName];
});
<template name="foo">
{{> _foo context=.. atts=this}}
</template>
you can do this/change the route by using the action option which will automatically cal this.render().
you can do it yourself by calling the action function but I guess it is better to use onBeforeAction/after hooks

What is the proper way to manipulate template instance in Meteor framework?

I am new to Meteor and wondering how to solve what seems to me is a common problem.
Let's say I have a handlebars template listing restaurants:
<template name="Restaurants">
{{#each Restaurant}}
{{name}}
{{/each}}
</template>
Now when user clicks on a restaurant template I want to display a menu for that restaurant.
I added a subtemplate named "menuItems" that contains all menu items for a given restaurant:
<template name="Restaurants">
{{#each Restaurant}}
{{name}}
{{> menuItems}}
{{/each}}
</template>
I want to render only one instance of menuItems subtemplate when user clicks anywhere on Restaurant template (render only the menu items for the selected restaurant).
It should go something like:
Template.Restaurants.events({
'click' : function (e) {
// This is where I need help - what's the right way to display only one subtemplate instance?
}
});
My question is - how I can select and display only the correct menuItems template instance?
Also I would like to place menuItems template instance in DOM only after the click and not before (having all the menu items for all restaurants and only hiding those divs is not an option because of high number of those items in db).
If you think I should approach the solution in some other way please let me know, thanks!
You should use {{#if}} and Session. Like this:
<template name="Restaurants">
{{#each Restaurant}}
{{name}}
{{#if restaurantSelected}}
{{> menuItems}}
{{/if}}
{{/each}}
</template>
By using Session, a reactive data source, you can set a global flag indicating whether a restaurant is selected.
Template.Restaurants.restaurantSelected = function() {
// check whether this restaurant is selected. "this" refers to the current
// context, eg. the current restaurant in the loop
return Session.equals("restaurantSelected", this._id);
}
Whenever you change that session key, the value will update and the template will be redrawn. So, you can toggle it when clicking a restaurant:
Template.Restaurants.events({
'click' : function (e) {
// store the current restaurant ID
// make sure the event selector is correct!
Session.set("restaurantSelected", this._id);
}
});
Edit For clarity's sake I created a complete example that you can copy into your project and try out.
I almost always avoid Session. I think it pollutes the global scope. Also it prevents you from running multiple instances of the template. I recommend using a reactiveVar or reactiveDict scoped to the template instance. Thanks to Rahul for starting a demo project. I took his example and modified it to show my recommended approach.
attach a reactiveDict to the template instance onCreate. Use this to store state instead of global Session var!
Template.Restaurants.onCreated(function() {
this.state = new ReactiveDict;
this.state.set('currentRestaurant', null); // could set a init value here
});
this event handler will set the state of the reactiveDict on click
'click': function(e, t) {
t.state.set('currentRestaurant', this._id);
}
this helper is used to show/hide the menu template
currentRestaurant: function() {
// check whether this restaurant is selected. "this" refers to the current
// context, eg. the current restaurant in the loop
return Template.instance().state.equals("currentRestaurant", this._id);
},
menu template receives the selected id from data context instead of from Session
<template name="Restaurants">
<ul>
{{#each Restaurant}}
<li>
{{name}}
{{#if currentRestaurant}}
{{> menuItems restaurant=_id}}
{{/if}}
</li>
{{/each}}
</ul>
</template>
<template name="menuItems">
<ul>
<li class="menu">I'm a menu for {{restaurantName}}!</li>
</ul>
</template>
added this helper just to show we really got the id
Template.menuItems.helpers({
restaurantName: function() {
var restaurantMenu = Restaurants.findOne(this.restaurant);
return restaurantMenu.name;
},
})
Posted a fully working project to github.
https://github.com/white-rabbit-japan/scopedReactivityDemo
App is hosted on meteor.com
http://scopedreactitivydemo.meteor.com/

Resources