So I have a bunch of templates that will be iterated with {{#each game}} showing the following template:
<template name="game">
{{#if condition}}
<div class="box">
Page 1
</div>
{{else}}
<div class="box">
Page 2
</div>
{{/if}}
</template>
I want to display "Page 2" when the "Page 1" box is clicked, so I have the following:
Template.game.events({
'click .box': function(e) {
Session.set("condition", true);
}
});
But I do not want all of the other game templates to transition to Page 2, just the one that was clicked. How do I accomplish this?
EDIT: The change should only affect the current user, not all users.
Assuming your games are stored in a Meteor.Collection, and condition is a property on the documents that should reflect for all users, not just the current one, you can do something like this:
Template.game.events({
'click .box': function(event, template) {
Games.update(
{_id: template.data._id},
{$set: {condition: !template.data.condition}}
);
}
});
If it should only affect the current user, you can use a template-instance specific session variable and return it with a helper function called condition:
Template.game.events({
'click .box': function(event, template) {
Session.set("condition-" + template.data._id, true);
}
});
Template.game.condition = function() {
return Session.get("condition-" + this._id);
};
You could achieve similar functionality with a local collection.
Don't use Session variables! The very reason is the problem you have, they're equivalent of the old global variables. Use template's data instead, it's local and can be used to control the behavior like you want in this case.
For the template in your example:
Template.game.created = function() {
this.data.conditionValue = 'something';
this.data.conditionDep = new Deps.Dependency();
};
Template.game.condition = function() {
this.conditionDep.depend();
return this.conditionValue;
};
Template.game.events({
'click .box': function(e, t) {
t.data.conditionValue = 'somethingElse';
t.data.conditionDep.changed();
},
});
I also feel using a session with id doesn't sound like the best idea, and found this answer which seems to be better than using session: Using Meteor sessions to toggle templates
Related
I am trying to display different sets of data based on a variable, without changing the route in meteor.js.
it looks like this:
<template name="somename">
{{#if form_submitted }}
display some data
{{else}}
display other data
{{/if}}
</template>
I am trying to do this with a helper:
Template.somename.helpers({
form_submitted = false;
});
However, when I run this, I get an error.
Also, I would like the variable to change to true when the button is clicked (and then refresh to false after a certain amount of time)
Any ideas?
You'll want to use a combination of template helpers and reactive variables for this:
Template.somename.onCreated( function() {
Template.instance().isFormClicked = new ReactiveVar( false );
});
Template.somename.helpers({
form_submitted: function () {
return Template.instance().isFormClicked.get();
}
});
Template.somename.events({
'click button': function( event, template ) {
template.isFormClicked.set( true );
Meteor.setTimeout( function() {
template.isFormClicked.set( false );
}, 10000); // Reset after 10 seconds.
};
});
Helpers a functions that return a value.
In your specific case it would be:
Template.somename.helpers({
form_submitted: function () {
return true;
}
});
Perhaps you could check the Meteor documentation about helpers http://docs.meteor.com/#/full/template_helpers
I'm trying to get a div to fade out and then change a session variable which is being used in the template. The session variable is being successfully changed in the callback function but the template is not reactively updating.
The following does not reactively update the template. (These are trigger)
$(event.target.parentNode).find(subclass)
.fadeOut("slow", function() {
Session.set(this.valueOf() + "_show_exercise_fields", set_show_exercise_fields);
The following does reactively update the template.
Session.set(this.valueOf() + "_show_exercise_fields", set_show_exercise_fields);
$(event.target.parentNode).find(subclass)
.fadeOut("slow", function() {
// do nothing
});
Is there a way to force the template to re render or a better way to do what I am trying to do. Thanks
EDIT 1
Below is the entire function
Template.exercise.events({
'click .exercise-name': function(event) {
var subclass = ".exercise-fields-container";
var set_show_exercise_fields = false;
if (!Session.get(this.valueOf() + "_show_exercise_fields")) {
var subclass = ".exercise-options-container";
var set_show_exercise_fields = true;
}
// find the subclass (either the fields container or the options
// container) and fade out
$(event.target.parentNode).find(subclass)
.fadeOut("slow", function() {
Session.set(this.valueOf() + "_show_exercise_fields", set_show_exercise_fields);
});
}
});
Template.exercise.helpers({
show_fields: function() {
Session.setDefault(this.valueOf() + "_show_exercise_fields", true);
return Session.get(this.valueOf() + "_show_exercise_fields");
}
});
Below is the template
<template name="exercise">
<div class="exercise-name">
{{this.name}}
</div>
{{#if show_fields}}
Fields
{{else}}
Options
{{/if}}
</template>
Event handlers aren't reactive contexts. You can create a reactive context using Tracker.autorun().
If you use a session variable within the function you pass to autorun, the entire function will rerun whenever the session variable is changed. In this context you could fade in or out as you desire.
I had a scenario where a collection was being updated, so I had to re-build my select element using Materialize Select
Here's what my on rendered function looks like. The autorun knows that Channels is a reactive data source and re-runs the autorun function when this data source changes.
Channels = new Mongo.Collection("channels");
Template.channelSelectController.onRendered(function(){
var self = this;
this.autorun(function(){
var count = Channels.find().count();
self.$('select').material_select();
});
});
I read and tried a lots of solution but i wasn't able to force the Template.dynamic to render again.
In html >>
<body>
{{> Template.dynamic template=Template}}
</body>
In Meteor.isClient >>
Template.body.helpers({
'Template': function() {
return page.template;
}
});
I have a function on hashchange event which will change the value of page.template, the event works fine and value will changed every time, but i can't force the Template.dynamic to render again.
page.template is string
I have a function page.getTemplate() > return page.template just to try all options
I'm using the last version of Meteor 1.1.0.2
I am not sure how your app is organized but this should be an easy task. Just use a ReactiveVar to save your active template-name you wish to have selected.
I made a simple MeteorPad for you. Hopefully this is what you are looking for.
http://meteorpad.com/pad/oPhK4KqjiSztRSa9K/SimpleDynamicTemplateSwitch
Cheers
Tom
Before start , i changed some objects , page.template is now object and page.template.get() will return string, but i don't use it, i pass the template name in Sessions, and this is my page.template.set()
page.template.set = function(name) {
Session.set('template', name);
};
Well i found the answer, you need to set a dependency to Sessions, i have done this so far
Template.body.helpers({
'Template': function() {
return Session.get('template');
}
});
Edited
Because of client hack i decided to changed something (you can change the session in console, and i want my router decide to which template should be shown)
page.template.set = function(name) {
page.template.name = name;
Session.set('template', name);
};
page.template.get = function() {
return page.template.name;
};
Template.body.helpers({
'Template': function() {
return Session.get('template') ? page.template.get() : page.template.get();
}
});
I want an Action event (on="") to trigger when there is a transition to a new Route.
I've seen the list of Action event handlers and closest I could find is attaching the action to the largest HTML element on the page and triggering it with 'Mousemove". This is a terribly flawed away of going about what I want to do.
So just to draw it out.
<div {{action 'displayEitherHtml1or2'}} class="largestDOMelement">
{{#if showHtml1}}
// html 1 inside
{{/if}}
{{#if showHtml2}}
// html 2 inside
{{/if}}
</div>
'/objects' is a list of objects and clicking one leads to 'object/somenumber'. The action should automatically trigger when I enter the 'object/somenumber' page.
UPDATE: I've taken the contents from the previous update and dumped them into my DocRoute, but nothing it being triggered when I transition to 'doc' through {{#link-to 'doc' this.docID}} {{docTitle}}{{/link-to}}
VpcYeoman.DocRoute = Ember.Route.extend(VpcYeoman.Authenticated,{
toggleLetterSwitch: false,
togglePermitSwitch: false,
activate: function () {
var docTemplateID = this.get('docTemplateID');
if ( docTemplateID == 2) {
this.set('toggleLetterSwitch', true);
this.set('togglePermitSwitch', false);
console.log('docTemplateID equals 2');
} else {
this.set('toggleLetterSwitch', false);
this.set('togglePermitSwitch', true);
}
}
});
UPDATE DOS: setDocID is set in the DocsController to 1. Here's the whole thing.
VpcYeoman.DocsController = Ember.ArrayController.extend({
tempDocId: 1,
actions: {
addDoc: function (params) {
var docTitle = this.get('docTitle');
var docTemplateID = 1;
var docTemplateID = this.get('tempDocId');
console.log(this.get('tempDocId'));
var store = this.store;
var current_object = this;
var doc = current_object.store.createRecord('doc', {
docTitle:docTitle,
docTemplateID:docTemplateID
});
doc.save();
return true;
},
setDocId: function (param) {
this.set('tempDocId', param);
console.log(this.get('tempDocId'))
},
}
});
As #fanta commented, it seems like you're looking for the activate hook within your Route. This gets called when you enter the route where you define it. If you want to call it on every transition, you might consider defining a base route for your application and extending that instead of Em.Route:
App.BaseRoute = Em.Route.extend(
activate: function () {
// Do your thing
}
);
App.YourRoutes = App.BaseRoute.extend()
It's possible that there's a more appropriate place/time to do this, but without knowing quite what your action does, this is probably the best guess.
ETA: Looking at your edit, you won't want all your routes to extend App.BaseRoute the way I did it above; you should probably just include that activate hook explicitly in the routes which need it.
I am building a chat application and on my "new chats" page I have a list of contacts, which you can select one by one by tapping them (upon which I apply a CSS selected class and push the user id into an array called 'newChatters'.
I want to make this array available to a helper method so I can display a reactive list of names, with all users who have been added to the chat.
The template that I want to display the reactive list in:
<template name="newChatDetails">
<div class="contactHeader">
<h2 class="newChatHeader">{{newChatters}}</h2>
</div>
</template>
The click contactItem event triggered whenever a contact is selected:
Template.contactsLayout.events({
'click #contactItem': function (e) {
e.preventDefault();
$(e.target).toggleClass('selected');
newChatters.push(this.username);
...
The newChatters array is getting updated correctly so up to this point all is working fine. Now I need to make {{newChatters}} update reactively. Here's what I've tried but it's not right and isn't working:
Template.newChatDetails.helpers({
newChatters: function() {
return newChatters;
}
});
How and where do I use Deps.autorun() to make this work? Do I even need it, as I thought that helper methods auto update on invalidation anyway?
1) Define Tracker.Dependency in the same place where you define your object:
var newChatters = [];
var newChattersDep = new Tracker.Dependency();
2) Use depend() before you read from the object:
Template.newChatDetails.newChatters = function() {
newChattersDep.depend();
return newChatters;
};
3) Use changed() after you write:
Template.contactsLayout.events({
'click #contactItem': function(e, t) {
...
newChatters.push(...);
newChattersDep.changed();
},
});
You should use the Session object for this.
Template.contactsLayout.events({
'click #contactItem': function (e) {
//...
newChatters.push(this.username);
Session.set('newChatters', newChatters);
}
});
and then
Template.newChatDetails.helpers({
newChatters: function() {
return Session.get('newChatters');
}
});
You could use a local Meteor.Collection cursor as a reactive data source:
var NewChatters = new Meteor.Collection("null");
Template:
<template name="newChatDetails">
<ul>
{{#each newChatters}}
<li>{{username}}</li>
{{/each}}
</ul>
</template>
Event:
Template.contactsLayout.events({
'click #contactItem': function (e) {
NewChatters.insert({username: this.username});
}
});
Helper:
Template.newChatDetails.helpers({
newChatters: function() { return NewChatters.find(); }
});
To mimick the behaviour of Session without polluting the Session, use a ReactiveVar:
Template.contactsLayout.created = function() {
this.data.newChatters = new ReactiveVar([]);
}
Template.contactsLayout.events({
'click #contactItem': function (event, template) {
...
template.data.newChatters.set(
template.data.newChatters.get().push(this.username)
);
...
Then, in the inner template, use the parent reactive data source:
Template.newChatDetails.helpers({
newChatters: function() {
return Template.parentData(1).newChatters.get();
}
});
for people who is looking for a workaround for this in the year 2015+ (since the post is of 2014).
I'm implementing a posts wizard pw_module where I need to update data reactively depending on the route parameters:
Router.route('/new-post/:pw_module', function(){
var pwModule = this.params.pw_module;
this.render('post_new', {
data: function(){
switch (true) {
case (pwModule == 'basic-info'):
return {
title: 'Basic info'
};
break;
case (pwModule == 'itinerary'):
return {
title: 'Itinerary'
};
break;
default:
}
}
});
}, {
name: 'post.new'
});
Later in the template just do a:
<h1>{{title}}</h1>
Changing routes
The navigation that updates the URL looks like this:
<nav>
Basic info
Itinerary
</nav>
Hope it still helps someone.