Iron-router is preventing my template from rendering a new page because it seems to believe it is already there.
The routes that I am dealing with are these:
Router.route('/', {
name: 'landingpage',
template: 'landingpage',
onBeforeAction: function() {
this.next();
}
});
Router.route('/chapter/:pathSlug/:chapterSlug', {
name: 'chaptershow',
template: 'chaptershow',
//waitOn: function() {
//return [Meteor.subscribe('users'),
//Meteor.subscribe('ChapterCollection')];
//},
onBeforeAction: function() {
Session.set('currentRoute', 'chapter');
this.next();
}
});
Let's say I have two chapters I want to display:
/chapter/voyage/somestories
/chapter/voyage/someotherstories
From the console I can easily go from the landingpage to either of the voyage pages or vice versa with
Router.go('landingpage');
Router.go('/chapter/voyage/somestories');
However, if I am on /chapter/voyage/somestories and try to go to /chapter/voyage/someotherstories using either
Router.go('/chapter/voyage/someotherstories');
Router.go('chaptershow', {pathSlug: 'voyage', chapterSlug: 'someotherstories'});
the URL in the location bar changes to /chapter/voyage/someotherstories but the new context doesn't load.
How do I get my new chapter to render?
Related
I'm building a little CRUD app in Backbone, and I'm stuck a little with a need to redirect from one view to another. My app consists of a layout view, in which other views are rendered, and a router. Here it is:
var router = Backbone.Router.extend({
routes: {
'': 'home',
'resumes/:id': 'showResume'
},
home: function () {
// renders a index view with my collection
this.layout.render(new ResumeList({collection: resumes});
},
showResume: function () {
if (!this.fullResume) {
this.fullResume = new FullResume({model: new Resume()});
}
// allowing to navigate via url with model id
this.fullResume.model.set('id', id).fetch({
context: this,
success: function () {
this.layout.render(this.fullResume);
}
});
}
});
Then, in my FullResume view I've got a delete event, which destroys the model. Here it goes:
var FullResume = Backbone.View.extend({
// tagName and other stuff
events: {
// other events
'click #delete': 'deleteResume'
},
// initialize, render and other functions
deleteResume: function () {
this.model.destroy({
success: function (res) {
console.log('DELETE model' + res.toJSON().id);
},
error: function () {
console.log('Failed to DELETE');
}
});
}
});
The function above works perfectly and deletes the model, but after deleting the model it still remains on it's view until I navigate somewhere manually. I read a bit and tried to manage how to render the main view after this event or redirecting to it, but didn't succeed a much.
You are looking for the http://backbonejs.org/#Router-navigate function with the trigger option set to true.
Here's an example: http://jsfiddle.net/x3t7u5p0/
Clicking on "Home" or "About" links will change the view, however I've added a delayed programmatic view change, when the About view renders, it will switch back to Home after the delay
render: function () {
this.$el.html(this.template);
_.delay(function() {
appRouter.navigate('home', {trigger: true});
}, 500);
}
I'm doing something wrong while setting Session variables and handling the Router
main.js:
Template.global.onCreated(function(){
Session.setDefault("musicFilteredCategory", "latest")
});
router.js:
Router.route("/music/:category?", {
name: "music",
template: "music",
beforeAction: function () {
var category = this.params.category;
Session.set("musicFilteredCategory", category);
}
});
but when I open page "/music/latin-radio" and I check Session.get("musicFilteredCategory") I get "latest" instead of "latin-radio"
later I changed Session.setDefault("musicFilteredCategory", "latest") to outside the Template.global.onCreated({}) and the result is still the same.
What should be the best practice to do this?
I also want to add this feature once this is fixed:
when the user goes to "/music" to be redirected to "/music/:defaultMusicCategory"
PS: I'm using Meteor 1.2.0.1 & Iron Router 1.0.9
As #Kyll pointed out I should use onBeforeAction for the function to run.
This solved part of my problem, but the categories were not being changed when accessing the different routes.
Here's what I had to do:
Router.route("/music/:category?", {
name: "music",
template: "music",
onBeforeAction: function () {
var category = this.params.category;
if (category !== "undefined") {
Session.set("musicFilteredCategory", category);
}
this.render("music");
}
});
This doesn't cover the route "/music" (without the slash) so I also had to add this route, I placed it before the code above
Router.route("/music", {
name: "music",
template: "music"
});
To resolve this I had to move the Session.setDefault() outside the templates scope as they were overriding the Session established on the router, so I had to put them inside a Meteor.startup function
Meteor.startup(function () {
Session.setDefault("musicFilteredCategory", "latest");
});
I've set up two routes in Iron-Router: 'home' (a paged list of all post) and 'doc' (a detail view). The home page loads just fine, but the detail view can only be loaded if the home page has been viewed previously. Otherwise it will render empty – and it can't be used as a permalink.
This will always load:
http://localhost:3000/
This will only load if 'home' has been viewed before:
http://localhost:3000/doc/tZFawq8cgf43hZBaJ
the routes:
Router.map(function() {
this.route('home', {
path: '/'
});
this.route('doc', {
path: '/doc/:_id',
data: function() {
return MyPix.findOne({_id: this.params._id});
}
});
});
the doc template:
<template name="doc">
<h1>{{this.name}}</h1>
<img src="{{ this.url store='OriginalRetinaPix' }}" width="{{ this.metadata.width }}" height="{{ this.metadata.height }}" />
</template>
publish/subscribe:
Meteor.publish('MyPix', function(cursor) {
Counts.publish(this, 'numberOfPosts', MyPix.find(), { noReady: true });
return MyPix.find({}, {sort: {uploadedAt: -1}, limit: 4, skip: cursor});
});
if(Meteor.isClient) {
Session.setDefault('docCursor', 0);
console.log('docCursor: ' + Session.get('docCursor'));
Meteor.autorun(function(){
Meteor.subscribe('MyPix', Session.get('docCursor'));
})
}
btw: the project on GitHub
On your "doc" route, you should use the waitOn in order to have the data ready on page load. Add a loading template in the Router.configure as well
I recommend you to upgrade to the new iron:router routes declarations and also add meteorhacks:subs-manager for better cache on the subscriptions.
This is an example that should work in your case
var subs = new SubsManager();
Router.route('/doc/:_id', {
name: 'doc',
template: 'doc',
waitOn: function() {
return subs.subscribe('aPix', this.params._id);
},
data: function() {
return {
apix: MyPix.findOne({
_id: this.params._id
})
};
}
});
and on the server side create a publications.js
Meteor.publish('aPix', function(id) {
check(id, String);
return MyPix.find(id);
});
Use this.
Router.map(function() {
this.route('home', {
path: '/'
});
this.route('doc', {
path: '/doc/:_id',
waitOn: function(){
return Meteor.subscribe('MyPix');
},
data: function() {
return MyPix.findOne({_id: this.params._id});
}
});
});
Also you subscription should look like this.
Meteor.publish('MyPix', function(cursor) {
//Counts.publish(this, 'numberOfPosts', MyPix.find(), { noReady: true });
return MyPix.find({});
});
Also Add, meteor add sacha:spin, because when you have a lot of people, the subscription will be have a little delay.
Add this to each route.
loadingTemplate: "loading"
<template name="loading">
{{> spinner}}
</template>
Router.onBeforeAction("loading");
Just in case you are showing 100+ images on 'home' and someone enter and have a slow connection, he will think that the page load empty, or something.
You only subscribe to a subset of all the documents. If you directly go to /doc/tZFawq8cgf43hZBaJ, the document with the id tZFawq8cgf43hZBaJ may not be part of the subset of documents you receive on the client.
Note: if this answer is correct, you should be able to directly go to /doc/<id> for those documents showing up first on the home page (on the first page, when the session variable docCursor is 0).
I'd like to nest resources in Ember, but to be able to access them with a short URL.
For example: mysite.com/admin will open the route: /routes/profiles/settings/admin
Is it possible to do something like that using Ember?
I'm currently using Ember 1.7 with Ember App Kit.
I tried the following but it doesn't work:
var Router = Ember.Router.extend();
Router.map(function () {
this.resource('profile', function () {
this.resource('profile.settings', { path: '/settings' }, function () {
this.resource('profile.settings.admin', { path: '/admin' });
);
});
Thanks.
Your code doesn't work because your inner most resource is inheriting the /profile path from the outer most resource and /settings from the middle resource. If you want it to be just plain /admin, you'd have to do something like this:
this.resource('profile', { path: '' }, function() {
this.resource('profile.settings', { path: '' }, function() {
this.resource('profile.settings.admin', { path: '/admin' });
});
});
However, this is going to get pretty hairy when you have more routes that each want top-level paths. You might find it easier to just declare a admin route at the top level, then redirect using the redirect hook in the route.
My routes looks like this:
App.Router.map(function () {
this.resource('index', { path: '/' }, function() {
this.resource('label', { path: '/label' }, function() {
this.route('notes', { path: '/:label_id' });
});
this.route('manage', { path: '/manage' });
});
});
Users should only visit label.notes and manage routes. I'm trying to find solution how to implement redirection from index for example to label.notes. One of methods described in documentation is:
App.IndexRoute = Ember.Route.extend({
redirect: function() {
this.transitionTo('label.notes', 0);
}
});
Here is jsbin with full example http://jsbin.com/UnasOse/1/edit
This works if user navigates by clicking links, but if manage opened by url, or page updated user will be redirected to notes.
So, how to implement redirection only then user opens root url (index)?
Using the your current router mapping, you have the routes index.manage and label.notes.
When the page is refreshed in the index.manage, first it will transition to the parent route, in that case the index, and after to manage. But in you index you have the redirect, so the manage isn't processed.
Just remove of your mapping the resource('index') and update your manage route to reflect the new configuration, so link-to index.manage will become manage, and data-template-name=index/manage to manage etc.
The updated route mapping is the following:
App.Router.map(function () {
// this.route('index', { path: '/' }); generated by ember
this.resource('label', { path: '/label' }, function() {
this.route('notes', { path: '/:label_id' });
});
this.route('manage', { path: '/manage' });
});
You can keep your IndexRoute, because ember create by default a this.route('index', { path: '/' }). So your IndexRoute will execute just when the user go to http://yoursite.com/
You can see that sample in action in this jsbin http://jsbin.com/ucanam/1024/edit