How can i force a reload instead of a transition in Ember.Route
For example inside this function:
File: play_route.js
actions: {
willTransition: function(transition, route) {
transition.abort();
transition.refresh();
// maybe
// window.location.href = route;
}
}
How can i force a reload inside Ember.Controller
For example inside this function:
File: play_controller.js
actions: {
reloadPage: function() {
// reload baby
}
}
This should do the trick:
window.location.reload(true);
So according to you guys I've solved my both problems as follows,
acknowledge if this is the proper way to do this.
In controller i refresh the page:
window.location.reload(true);
In route i transition to specific route:
actions: {
willTransition: function(transition, route) {
transition.abort();
window.location.href = '/' + transition.targetName;
}
}
Related
My router.js file is like this:
this.route('cards', function() {
this.route('all');
this.route('card', {path: '/:card_id'}, function() {
this.route('edit');
});
this.route('new');
});
In all.js, I've:
model() {
return this.store.findAll('card');
}
In cards.js, I've:
beforeModel() {
this.transitionTo('cards.all');
},
model() {
return this.store.findAll('card');
}
As you can see that I'm making 2 requests which, IMO, is not necessary. So, if I remove the call from cards.js, the new.js doesn't work properly.
When I create a new card from new.js, after creation, it should go to /cards/1 and show the proper data. But, when I remove that line from cards.js, after creation of a card, it goes to /cards/1 but the data is not saved.
Link to repo: https://github.com/ghoshnirmalya/hub-client
If I refresh a meteor page that is using a data query in the iron-router setup, the page loads the template but with no data, then shows the loading template, then shows the page with the data. I want to avoid the page flicker that is happening. This is my router code:
this.route('/stories/:_id', function () {
if (!Meteor.user() && !Meteor.loggingIn()) {
Router.go('home');
} else {
var story = Stories.findOne({ _id: this.params._id });
this.render('showStory', { data: story });
}
});
I've also tried this setup and moved the logged in validation to an onBeforeAction.
this.route('showStory', {
path: '/stories/:_id',
data: function () {
return Stories.findOne({ _id: this.params._id });
}
});
When I refresh the page with this setup, I see my 404 page, then the loading template, then the correct template with data.
Try with this.
Router.map(function () {
this.route('showStories', {
path: '/stories/:_id',
waitOn: function(){
return Meteor.subscribe("Stories"); //we make de subscription here
},
data: function(){
if(! Meteor.user()){
this.render('/') //or sign-up template whatever template you want if user its not loged in
}else{
return Stories.findOne({_id: this.params._id});
}
}
});
});
Already Tested and its working
Ref to the question Trying to Migrate to Iron-Router from Router. I still dont understand how to migrate meteor router to iron-router.
I am using router in my meteor project. The router file is like followings:
Meteor.Router.add({
"/settings": function() {
if (!Roles.userIsInRole(Meteor.user(), ['admin'])) {
return false;
}
return 'site_settings';
},
"/new_page": function() {
if (!Roles.userIsInRole(Meteor.user(), ['admin'])) {
return false;
}
return 'new_page';
},
"/navigation": function() {
if (!Roles.userIsInRole(Meteor.user(), ['admin'])) {
return false;
}
return 'navigation';
},
"/login": function() {
return 'loginButtonsFullPage';
},
"/users": function() {
if (!Roles.userIsInRole(Meteor.user(), ['admin'])) {
return false;
}
return 'admin_users';
}
});
If someone knows how to use an iron-router to replace the return template in the right way. Much appreciate.
I meet a little bit complicated router function, and I have no idea how to solve it. the code is like:
"/": function() {
// Don't render until we have our data
if (!GroundDB.ready()) {
//if (!Offline.subscriptionLoaded('pages') || !Offline.subscriptionLoaded('settings')) {
return 'loadingpage';
} else {
var page_slug = utils.getSetting('indexPage');
var page = Pages.findOne({slug: page_slug});
if(!page) {
page = Pages.findOne();
// if pages dont have any public pages
if (!page) {
var isIndexPageInNav=Navigation.findOne({"location":"header_active","pages.slug":page_slug});
// if index page slug in navigation that means the user dont have right to view this slides or the index page not exist
if(isIndexPageInNav)
return 'loginButtonsFullPage';
else
return '404';
}
else {
page_slug = page.slug;
}
}
Session.set("page-slug", page_slug);
return page.template;
}
}
As you know the iron-router need give a template at the begining. but with router I can return dynamic templates. How does iron-router implement this idea.
Router.map(function() {
//site_settings being the name of the template
this.route('site_settings', {
path: '/settings',
action: function() {
if (!Roles.userIsInRole(Meteor.user(), ['admin'])) {
//if the conditional fails render a access_denied template
this.render('access_denied');
} else {
//else continue normally rendering, in this case the 'site_settings'
//template
this.render();
}
}
});
this.route('loginButtonsFullPage', {
path: '/login'
});
});
Note since you will be doing that if user is admin conditional a lot you can wrap that logic inside a controller and link it to all the relevant routes such as:
Router.map(function() {
this.route('site_settings', {
path: '/settings',
controller: 'AdminController'
});
this.route('new_page', {
path: '/new_page',
controller: 'AdminController'
});
this.route('navigation', {
path: '/navigation',
controller: 'AdminController'
});
//etc...
//don't need to add the controller for this one
//since all users have access
this.route('loginHuttonsFullPage', {
path: '/login'
});
});
AdminController = RouteController.extend({
action: function() {
if (!Roles.userIsInRole(Meteor.user(), ['admin'])) {
this.render('access_denied');
} else {
this.render();
}
}
});
A couple of other things you will want to check out in iron-router are layouts with {{> yield}} and waitOn which is indispensable.
The docs at https://github.com/EventedMind/iron-router will do a better job of explaining those concepts then I can here.
Here is my attempt at your more complicated route. It may not work right away because I may be misunderstanding what you are doing but the key things are to substitute the returns with this.render(template_name); waitOn instead of checking if something is ready(), adding all the required subscriptions to the waitOn and then finally adding all your logic to an action
//note: index is the name of the route, you do not actually need a template called index.
//in the previous examples where no template to render was returned then iron-router will
//look for a template with the same name as the route but in this route we will be providing
//it with a specific route name in all cases
this.route('index', {
path: '/',
//assuming GroundDB is a subscription e.g. GroundDB = Meteor.subscribe('groundDB');
//I don't know what your page and nav subscriptions are called but you should wait on them too.
//if you haven't assigned them to a variable do something like
//pageSubscription = Meteor.subscribe('pages');
waitOn: [GroundDB, pageSubscription, navigationSub],
//the template to load while the subscriptions in waitOn aren't ready.
//note: this can be defined globally if your loading template will be the same
//for all pages
loadingTemplate: 'loadingpage',
//here we evaluate the logic on which page to load assuming everything has loaded
action: function() {
var page_slug = utils.getSetting('indexPage');
var page = Pages.findOne({slug: page_slug});
if (!page) {
var isIndexPageInNav = Navigation.findOne({"location":"header_active","pages.slug":page_slug});
if(isIndexPageInNav)
this.render('loginButtonsFullPage');
else
this.render('404');
} else {
page_slug = page.slug;
}
Session.set("page-slug", page_slug);
this.render(page.template);
}
});
in my app I need that when I visit the root, it redirects to the view of the most recent model that in this case is always the firstObject in the collection.
App.Router.map(function() {
this.resource('threads', { path: '/' }, function() {
this.route('view', { path: ':thread_id' });
});
});
App.ThreadsRoute = Ember.Route.extend({
model: function() {
return this.store.find('thread');
},
afterModel: function(threads) {
this.transitionTo('threads.view', threads.get('firstObject'));
}
});
This is working without problems, but wheter I directly go to the root url or the view one 2 identical requests to /threads are made. As soon I comment the afterModel section the redirection obviously doesn't work anymore but the requests are back to 1.
Any help is gladly accepted!
Since Threads/View are nested routes, the ThreadsRoute will be also called on the View route.
I think you should just call the ThreadsRoute -> ThreadsIndexRoute or separate model and afterModel hooks this way:
(Not tested code)
App.ThreadsRoute = Ember.Route.extend({
model: function() {
// console.log('in model);
return this.store.find('thread');
}
});
App.ThreadsIndexRoute = Ember.Route.extend({
afterModel: function(threads) {
// console.log('in afterModel);
this.transitionTo('threads.view', threads.get('firstObject'));
}
});
Your example is identical to this one:
App.Router.map(function() {
this.resource('threads', { path: '/' }, function() {
this.route('view', { path: ':thread_id' });
});
});
App.ThreadsRoute = Ember.Route.extend({
model: function() {
return this.store.find('thread');
}
});
App.ThreadsIndexRoute = Ember.Route.extend({
model: function() {
return this.store.find('thread');
}
});
If you check the inspector for which route you're in when you visit '/', you'll see that you're inside of
threads.index, having transitioned into each of them in turn, which is why you're seeing the call to find twice.
You can fix this by only having the model hook in ThreadsIndexRoute (e.g. rename your ThreadsRoute to ThreadsIndexRoute)
I'm going through examples with routing from David Sulc's book Backbone.Marionette.js: A Gentle Introduction
https://leanpub.com/marionette-gentle-introduction
ContactManager.navigate = function (route, options) {
options || (options = {});
Backbone.history.navigate(route, options);
};
ContactManager.getCurrentRoute = function () {
return Backbone.history.fragment;
};
ContactManager.on("initialize:after", function () {
if (Backbone.history) {
Backbone.history.start();
if (this.getCurrentRoute() === "") {
ContactManager.trigger("contacts:list");
}
}
As you can see if the history fragment is empty, it will trigger the contacts:list event which will render the list of contacts. However, it doesn't redirect at all, and I've found out that fragment is preset to "contacts" somehow, so the event doesn't get fired at all. It also happened to me once that initially the fragment was empty and got everything rendered, and url changed properly, but upon refresh fragment was still "contacts" and again nothing was rendered.
ContactsApp.Router = Marionette.AppRouter.extend({
AppRoutes: {
"contacts": "listContacts"
}
});
ContactManager.on("contacts:list", function () {
ContactManager.navigate("contacts");
API.listContacts();
});
This is the code that handles the event. What seems to be the problem? Thanks.
I think there is some missing code. I would expect to find something like this in the router:
var myController = {
listContacts: function () {
ContactManager.trigger("contacts:list");
}
};
ContactsApp.Router = Marionette.AppRouter.extend({
controller: myController,
appRoutes: {
"contacts": "listContacts"
}
});
Note that appRoutes starts with a lowercase a.
Now the route contacts will call the controller's listContacts method and trigger the ContactManager.on("contacts:list"... callback, running the appropriate API method.