Spacebars-generated dynamic links do not trigger Iron Router in Meteor? - meteor

I've got this in my routes:
Router.route('/videos/:id', {
name: 'VideoPage',
data: function(){
return Videos.findOne(this.params.id);
}
})
This template shows up at the route above:
Template.VideoPage.helpers({
'videoIds': function(){
var myVideoIds = [
"23456",
"h5e45t",
"f4e4w",
"g6h4h"
];
return myVideoIds;
}
});
HTML:
<template name="VideoPage">
{{videoTitle}}
<p>Click the links below to get to a new video page</p>
{{#each videoIds}}
<a href="/videos/" + {{this}}>
{{/each}}
</template>
When I click on a link, the URL in the browser changes from something like /videos/23456 to something like /videos/f4e4w, but the request never actually goes through Iron Router and the Router.route function. I put a debugger before Router.route and it triggers on initial page load but does NOT trigger when the links are clicked.
I understand that Iron Router's default behavior is NOT to re-render a template the user is currently on, but this is the same template with different url params that are used to change the data in the template, so IMO it should still re-render.

Ok, false alarm. It appears that Router.route DOES fire and updates the data context every time the params._id changes. I was placing the debugger outside of the Route function when I should have been placing it inside of the data context function.
The example that I gave in this answer was also a highy, highly simplified example. It wasn't working in my real-life project due to something else (a complex video iframe generator) that was being refreshed improperly.
But rest assured that going from /videos/f4e4w to /videos/23456 by clicking a link DOES still go through Iron Router and the params does get read and the data does get updated.

Related

FlowRouter without page reload

I am following this example https://kadira.io/academy/meteor-routing-guide/content/rendering-blaze-templates
When I click on my links the whole page is being reloaded. Is there any way to load only the template part that is needed and not the whole page?
Edit: Also I noted another problem. Everything that is outside {{> Template.dynamic}} is being rendered twice.
Here is my project sample. https://github.com/hayk94/UbMvp/tree/routing
EDIT: Putting the contents in the mainLayout template and starting the rendering from there fixed the double render problems. However the reload problems happen because of this code
Template.mainLayout.events({
"click *": function(event, template){
event.stopPropagation();
console.log('body all click log');
// console.log(c0nnIp);
var clickedOne = $(event.target).html().toString();
console.log('This click ' + clickedOne);
//getting the connID
var clientIp = null // headers.getClientIP(); // no need for this anymore
var clientConnId = Meteor.connection._lastSessionId;
console.log(clientIp);
console.log(clientConnId);
Meteor.call("updateDB", {clientIp,clientConnId,clickedOne}, function(error, result){
if(error){
console.log("error", error);
}
if(result){
}
});
}, // click *
});//events
Without this event attached to the template the routing works without any reloads, however as soon as I attach it the problem persists.
Do you have any ideas why this code causes such problems?
EDIT 2 following question Rev 3:
event.stopPropagation() on "click *" event probably prevents the router from intercepting the click on link.
Then your browser performs the default behaviour, i.e. navigates to that link, reloading the whole page.
EDIT following question Rev 2:
Not sure you can directly use your body as BlazeLayout target layout.
Notice in the first code sample of BlazeLayout Usage that they use an actual template as layout (<template name="layout1">), targeted in JS as BlazeLayout.render('layout1', {});.
In the tutorial you mention, they similarly use <template name="mainLayout">.
That layout template is then appended to your page's body and filled accordingly. You can also change the placeholder for that layout with BlazeLayout.setRoot() by the way.
But strange things may happen if you try to directly target the body? In particular, that may explain why you have content rendered twice.
Original answer:
If your page is actually reloaded, then your router might not be configured properly, as your link is not being intercepted and your browser makes you actually navigate to that page. In that case, we would need to see your actual code if you need further help.
In case your page does not actually reload, but only your whole content is changed (whereas you wanted to change just a part of it), then you should make sure you properly point your dynamic templates.
You can refer to kadira:blaze-layout package doc to see how you set up different dynamic template targets in your layout, and how you can change each of them separately (or several of them simultaneously).
You should have something similar in case you use kadira:react-layout package.

only refresh region of page with iron router + meteor (is it possible?)

I recently started creating a app with meteor, and i run into an issue where i am stuck.
What i want to achieve is to have a app with 2 yield regions.
1 yield region is a left sidebar, the other region the main content of the side.
I am using Iron-Router to create routes.
There should be routes where both regions should refresh / update. This is no problem and i got this working.
What i fail to achieve is that on some routes, it should only rerender /refresh 1 of the regions, not both.
After trying with different routing settings, i am not really sure if what i want is possible at all.
TL;DR:
Is it possible to have 2 yield regions in layout, but to have a route where only 1 of this regions gets refreshed ?
iron:router already provides what you need. You just need to name the other yield regions inside templates like this:
//template that loads to the main {{>yield}}
<template name="someTemplate">
{{> yield 'second-yield'}}
</template>
Router.route('/pathYouDesire', function () {
this.render('anotherTemplate', {
to:'second-yield',
data: function () {
//your data
}
})
},{
name: 'singlePost'
});

Update count for external link

I have a Meteor app for storing my bookmarks. To do that there is a Links collection with a count attribute. Every time I click the bookmark, the external site must be visited, but also the count must be increased with 1, so I can sort the bookmarks with the most visited at the top.
So now I have a link with the info in it:
{{title}}
Should I use a template instead, update the count and do a Router.go to the external site?
A little modification:
{{title}}
Then you could use:
Template.body.events({
'click a.tracked' : function(e) {
var href = $(e.currentTarget).attr('href');
ClickedLinks.insert({href: href, when: new Date()});
}
});
Where ClickedLinks is a collection. The main idea is that we track all click events on meteor body as a catch-all since everything is rendered in the body anyway even if it's in another template.. everything still winds up getting rendered there. Then we try to depend on events propagation to do our magic.
Here it is in action:
http://meteorpad.com/pad/Wtz6autqgCDEaJTLw/Leaderboard

how to keep a subscription open between routes?

How do i keep a subscription open between different calls to the IronRouter routes?
I have an app that has a hierarchy like a magazine, issue/page
content/:issue/:page
so this would be:
content/may/page1
content/may/page2
content/may/page3
I would like to load all the content for "May" issue within the router, and when the pages are changed NOT do an unsubscribe. I am seeing some flicker with the app which I think is caused by delay as the data is being reconnected to.
I currently have a simple Content.find({}) but there is an apparent delay seeming to be caused by the unsub/pub/sub handshake - even though the content is not changing.
Update: I moved the subscribe outside of IronRouter routes entirely and now it seems "sticky". However i imagine subscriptions are getting unsubscribed somewhere, so I'm not sure if this is the best solution. It is also now a global subscribe" whereas really i want to be able to control pub/unsub only if the :issue parameter has changed on that route.
Handling subscriptions on a template level is far superior to handeling it in the router.
Because when you handle it in the router the page only gets loaded after the subscription is ready. Which makes your application feel less responsive.
Template:
<template name="example">
{{#with data=getData}}
{{#if $not data.ready}}
{{> spinner}} Loading...
{{/if}}
{{/with}}
</template>
Template helper:
Template.example.getData = function() {
var ready = Meteor.subscribe('someSubscription', this.issueId).ready();
var data = collections.example.find();
return {
ready: ready,
data: data
};
};
This results in a more responsively feeling application. It is always better to avoid a slow/bad/nonresponsive design, before resorting to something like caching to fix a problem with the used design.

Iron Router shows my Not Found template before loading with WaitOn: Meteor

I put my subscribe inside a WaitOn function in a controller with Iron Router / Meteor, and while the subscribe is populating the browser shows my notFoundTemplate: 'notFound'.
How to get around this? I thought WaitOn would actually, you know... wait?
My path is dependant on the subscribe containing the URL. i.e.
www.myapp.com/Fred
this.route('userShow', {
path: '/:owner_name',
controller: 'UserShowController'
});
waitOn should actually wait, if the controller is written correctly.
Things to check:
Are you publishing the collection on the server?
Did you pass the data correctly to the template? Your data function in the UserShowController should look something like data: function () {return People.findOne({name: this.params.owner_name});},
Are you navigating your browser to a valid :owner_name?
Hope this helps. Good luck!

Resources