Meteor: execute jQuery code on every "change" - meteor

I have an app where I want to execute a jQuery equalize() function on some DIV boxes every time my "pages" change. At the moment I have the code inside my main layout's render() function but it is executed only once the user reloads the whole page. I tried to use autorun but this didn't work out either.
Meteor 1.0.3.1 + iron:router
EDIT:
I have different page views with routes (e.g. /home, /about-us, /terms, ...) and once the user navigates to a page (meaning follows a route to another view) the code should be executed.

If you are using iron-router, then try this:
Router.onAfterAction(
function(){
// select divs and apply equalize
},
{
only: ['admin']
// or except: ['routeOne', 'routeTwo']
}
);

Take a look at hooks in IronRouter. Add an onBeforeAction hook to your router configuration to apply it to all routes.
Router.onBeforeAction(function () {
//dostuff
})

Related

With Flow Router how to re-execute a function upon visitng the page?

I have set some functions in the template's onRendered hook like this :
Template.PanelLayout.onRendered(function() {
Tracker.autorun(function() {
if (ready.get()) {
page = Pages.findOne({
slug: 'about'
});
tinymce.init({
selector: "#pageContent",
height: 400
});
tinymce.get('pageContent').setContent(page.content);
}
});
});
If I visit that page directly or reload that page these functions will work. But if I visit it by just clicking a link in the navigation, the functions won't load. How can I fix this?
The short answer is you can't because this is how FlowRouter works:
FlowRouter docs
For a single interaction, the router only runs once. That means, after you've visit a route, first it will call triggers, then subscriptions and finally action. After that happens, none of those methods will be called again for that route visit.
What you are doing seems to be more suited for Meteor's Template helper

Meteor router force rerender

I have the following routs
/product/123
/product/456
the template renders the product data and allows the user to drag things around
when I make a redirect to another product like that
Router.go("product",{_id:"456"});
the template updates the data but does not re-render the html. that means that what the user dragged stays in place. this is good for some cases but not for mine
the only solution that worked for me was to redirect to another page that sets clear template and it redirects to the product page
my router function:
Router.route('product/:_id/', {
name:"product",
data:function(){
var data = {product: Products.findOne({_id:objectId(this.params._id)})}
return data;
},
waitOn:function(){
return Meteor.subscribe('Products',this.params._id);
},
yieldTemplates: {'product': {to: 'mainArea'}},
});
I need a way to tell the router or template to reset the html
One solution is to set up an autorun in the template's onRendered function that looks for changes to the URL parameters and the resets the template as needed. Something like this:
Template.myTemplate.onRendered(function() {
var controller = Router.current()
this.autorun(function() {
var params = controller.getParams() // Reactive
// Clear up your drag interface here
});
});
By accessing controller.getParams() (the route controllers reactive parameter list) the outrun will be called when you move between routes on the same template.

How do I get onRendered to run a second time when the route changes but the template remains the same?

I have an iron-router route for updating the data of a specific project:
Router.route('/project/:key/update', {
...
});
Each time the user navigates to an "edit project page" I want to focus the project-name input.
template.onRendered(function() {
this.$('form input[name="project_name"]').focus();
});
This works great when navigating from the Dashboard to any given edit project page. However, navigating to/from one project page to another the onRendered function doesn't rerun and consequently the input is not focused.
You can force onRendered to reevaluate after a context change by adding a check for currentData inside of an autorun like this:
Template.myTemplate.onRendered(function() {
var self = this;
this.autorun(function() {
// hack to force the autorun to reevaluate
Template.currentData();
// insert onRendered code here
self.$('form input[name="project_name"]').focus();
});
});
For more details, see the end of this issue.

Template empty initially but renders properly on changing and coming back to route

I have a template named profile which contains three other templates. One of these templates is {{> postlist}}
and the helper function for this template is
Template.postlist.helpers({
posts: function() {
return Posts.find({rph: {$in : postsArr}});
}
});
The problem is on going to the route, postlist template is empty, since postsArr is calculated later after the dom has loaded on the basis of other two templates. But, if I click on other route and come back to this route, the template renders properly.
What should I do that template renders properly initially itself?
The easiest way would be to us Session, though it's probably the worst option:
Template.postlist.helpers({
posts: function() {
return Posts.find({rph: {$in : Session.get('postsArr') }});
}
});
If you now call Session.set('postArr', ...) anywhere in your code the posts helper will update automatically. The second option is to use a shared reactive variable:
var postsArr = new ReactiveVar();
and then inside your helper:
return Posts.find({rph: {$in : posts.Arr.get() }});
Now you can do postsArr.set(...) and everything should work fine. Just remember to meteor add reactive-var do your project.
One last doubt is: where to put that reactive variable declaration? In most cases you can do away with putting in a single "controller" file. It will work as long as:
- you only have one instance of your template a time
- the code which sets ad gets the value of you reactive variable may be put in the same file
If one of the above conditions does not hold, then the only option to go, which is BTW the best possible, is to put your state variable in your template's scope. This is how you do it:
Template.postsList.created = function () {
this.postsArr = new ReactiveVar();
};
Template.postlist.helpers({
posts: function() {
return Posts.find({rph: {$in : Template.instance().postsArr.get() }});
}
});
From helpers you can always access postsArr using the Template.instance() routine which always return the current template instance, for which the helper was called. From event handlers, note that the second argument of your handler is always the template instance, which you're interested in.
If you need to access it from another templates, then you should probably put your state variable on the corresponding route controller. Assuming you're using iron-router, that would be:
Iron.controller().state.get('postsArr');
The Iron.controller routine grants you access to the current route controller. Read this for more details.

how to properly handle dom ready for Meteor

I am currently using iron-router and this is my very first attempt to try out the Meteor platform. I has been running into issues where most of the jquery libraries failed to initialized properly because the of the way Meteor renders html, $(document).ready() fires before any templates are rendered. I am wondering is there any callbacks from Meteor/iron-router that allows me to replace the jQuery's dom ready?
Also, how should I (easily and properly) handle the live update of the dom elements if some of them are customized by jQuery/javascript?
This is what i am currently doing, i feel like it is very hackish and probably would run into issues if the elements got updated after the initialization.
var jsInitalized = false;
Router.map(function () {
this.route('', {
path: '/',
layoutTemplate: 'default',
after: function(){
if(!jsInitalized){
setTimeout(function(){
$(document).ready( function() { $$$(); });
}, 0);
jsInitalized = true;
}
}
});
}
With Meteor you generally want to think about when a template is ready, not when the dom is ready.
For example, let's say you want to use the jQuery DataTables plugin to add sorting to a table element that's created by a template. You would listen to the template's rendered event and bind the plugin to the dom:
HTML:
<template name="data_table">
<table class="table table-striped" id="tblData">
</table>
</template>
JavaScript:
Template.data_table.rendered = function () {
$('#tblData').dataTable();
};
Now anytime the template is re-rendered (for example, if the data changes), your handler will be called and you can bind the jQuery plugin to the dom again.
This is the general approach. For a complete example (that includes populating the table with rows) see this answer.
Try making a separate .js file, call it rendered.js if you'd like. and then;
Template.layout.rendered = function ()
{
$(document).ready(function(){console.log('ready')});
}
I use template layout, but you can do Template.default.rendered. I hope that helps.
Also take a look at this part of documentation, especially the Template.events; http://docs.meteor.com/#templates_api
I use Meteor v0.8.0 with Iron Router (under Windows 7) and here is how I handle 'DOM ready':
When I want to modify the DOM after a specific template has been rendered:
I use Template.myTemplateName.rendered on the client side :
Template.blog.rendered = function()
{
$('#addPost').click(function()
{
...
});
}
When I want to modify the DOM after any new path has been rendered:
I use Router.onAfterAction, but there seems to be a trick:
Router.onAfterAction(function()
{
setTimeout(function()
{
$('.clickable').click(function()
{
...
});
}, 0);
});
Notice the setTimeout(..., 0), it doesn't work for me otherwise (DOM empty).
Notice that you can use onAfterAction on specific path, but most of the time I think it is redundant with the Template.myTemplateName.rendered method above.
What seems to be missing:
A way to modify the DOM after any template has been rendered.

Resources