Just wanted to know, what is the proper way of returning to the index in backbone.js? So this is an outline of my code. I have a router, where it creates an instance of a view and passes the current instance of the router.
var AppRouter = Backbone.Router.extend({
callMasterViefw: function(){
MasterView.initialize(this);
},
})
Inside the MasterView, I create an instance of the MasterView and assign the router to it as well. I have a function, called reRouteToIndex, where basically i want to reroute to the index page.
MasterView= Backbone.View.extend({
render: function(){},
reRouteToIndex(){
this.router.navigate("", {trigger: true,replace: true});
},
});
All this works, but the problem is when I redirect to the index I return to something like www.test.com/index.html/#. Where it is important to note the # at the end. I was wondering if there was a way to route to the original path without the # like this www.test.com/index.html?
You could enable pushState in .navigate() (like .navigate({pushState: true, trigger: true}) but you'll need to configure your webserver to work with mod_rewrite (or equivalent).
Related
I have the View containing some button. When that View becomes activated it should take the some URL parameter (in my case -- site id) and set it to the button attribute "data-site_id". There is a router too in the app. But I don't know how to implement it with the best way. Till now I see 3 supposed solutions:
Extract site id from URL hash. URL is build by such a pattern:
"sites/edit/:id(/:tab)": "editSite",
the question is -- may I use here a router itself (and, if yes then how?) or can not, and should parse it with common JS way? Of course, router & view are two different objects and located in different files/scopes.
Save the site_id in model. But I'm not sure how to store it from router. I think I can create an instance of model, set it as variable under router scope and then treat it as usual, something like this:
(function(app, $, config, _) {
var Model = new app.modelName();
var Router = app.Router = Backbone.Router.extend({
routes: {
"": "start",
//....
"sites/edit/:id(/:tab)": "editSite",
//...
},
//....
editSite: function(id, tab){
Model.set('site_id', id);
}
//....
})(window.Application, jQuery, window.chatConfig, _);
after that I can extract the site id from model in any time I want
Assign a data-site_id attribute to the button just from the router. But this doesn't look as a best practice, right?
So what is your advice?
Your second suggested solution makes the most sense, you could then instantiate your view passing that model to the constructor.
See http://backbonejs.org/#View-constructor
This is a simple question, but I am new to routing and haven't been able to find an answer to this.
I have a Marionette Router (if I intimidate you, its really the same thing as a Backbone Router. Very simple).
sys.routes = {
"app/:id": "onAppRoute",
};
sys.Router = new Marionette.AppRouter({
controller: {
onAppRoute: function(route) {
console.log('Called app route!');
},
},
appRoutes: sys.routes,
});
Backbone.history.start({pushState: true})
This works - if you hit the back button my browser, the url will change within my Single Page Application and will call the onAppRoute function.
However, let's say I open a new browser window and paste in my page url to a certain 'app':
http://localhost/app/myApplication
This doesn't call the onAppRoute function. It doesn't even seem like it should, though, but I really don't know.
I want it to.
I don't know if I am doing it wrong, or if I should just manually fire it by grabbing my page url on page load, parsing it, then 'navigating' to that route. Seems hacky.
Contrary to your intuition, backbone's default behaviour is to trigger matching routes on page load! cf. http://backbonejs.org/#Router - look for the option silent: true. You'd have to specify that for the router to IGNORE your matching routes on page load, i.e. not trigger the corresponding callbacks.
So your problem lies somewhere else: your routes do NOT match the url you have stated as an example. Clearly, you require an :id parameter, trailing http://localhost/app/myApplication. Therefore, http://localhost/app/myApplication/213 would cause your callback to be triggered on page load, given you didn't pass silent: true as an option to backbone.history.start().
If you want to match the 'root' url, i.e. no params, you would define the following route:
routes: {
'/': someFunction
}
The :id part is a parameter, which will be extracted by Backbone.Router and sent as an argument to onAppRoute.
But in your URL you don't have any parameters /localhost/app/myApplication
In Backbone, is there any way to trigger a route event handler, without changing the URL?
What I mean is that I want to trigger a route handler, but I don't want to change the URL.
Hence, I don't want to use
router.navigate(route, {trigger: true});
as this will cause the URL to change.
The router itself is connected to a function. The simple answer is to call the function straight away, simply bypassing the route handling.
Example
(function( $, Backbone ) {
var exports = window.app = window.app || {},
Router = Backbone.Router.extend({
// Here you declare what the routes are in your router
// and what functionality they should trigger.
routes: {
"help" : "help",
"search/:query" : "search",
"search/:query/p:page": "search"
},
// Declare route functions.
help : function() {},
search: function( query, page ) {}
});
// Export the router.
exports.router = new Router();
// Just a dummy object for calling the router.
var cookieMonster = {
init: function() {
// Do something on init.
// End with calling the route help function.
exports.router.help();
}
};
}(jQuery, Backbone));
cookieMonster.init() would in this case end with a call to the help function in the router.
A tip is to look at Backbone Marionette where you have a Controller which has the function logic seperated from the routes, one of many things that make Marionette awesome.
For what its worth, Marionette routing is explained extensively here: http://samples.leanpub.com/marionette-gentle-introduction-sample.pdf
The strategy that is discussed is separating URL management from application reactions (e.g. switching sub-applications). This means that you're then free to have your app trigger a handler (using a Marionette event) without modifying the URl fragment.
Have you tried Backbone.history.loadUrl(route);?
If I navigate to a view by clicking on a link such as 127.0.0.1/#/project/1, the correct view gets displayed. However, if I call this url directly in the browser (or hit refresh), the view won't be displayed. What could be the reason for this behaviour?
The way I set up the Router is as follows:
var AppRouter = Backbone.Router.extend({
routes: { },
initialize:function () { }
});
var app = new AppRouter();
and then in every module (I'm using require.js), a route and handler will be added
app.route("project/:id", "showProject");
Could it be that the routes aren't registered yet and thus the callbacks won't be called?
Make sure that you are calling Backbone.history.start() after all of your routers are loaded/instantiated and routes defined: http://backbonejs.org/#History-start
Alternatively, you could stop the history with Backbone.history.stop(), and start it again. Then the added route(s) will be picked up.
BTW, you can test if the history is currently started with the boolean Backbone.History.started (note the capital 'H' is necessary).
I have the following router:
appRouter = Backbone.Router.extend({
routes: {
'': 'inbox',
'inbox': 'inbox',
'discussions_engagement': 'contacts',
},
inbox: function(page) {
console.log('inbox');
var page = page || 1;
engage.app.hydrateInbox(page, engage.app.showInbox);
},
....
};
When I am on http://[...]/#inbox and I call
appRouter.navigate('inbox', {trigger: true});
the inbox action doesn't fire which is what I want to achieve. Now I have looked at the source of Backbone (https://github.com/documentcloud/backbone/blob/master/backbone.js#L1027) and I see that it doesn't support what I'm trying to do but is there some way of accomplishing this?
I would create an event manager in your engage.app object, like this:
var vent = _.extend({}, Backbone.Events);
Then in your router do this for the inbox route:
vent.trigger('inbox:show', page);
And handle that event in the engage.app object, doing the code there that used to be in the route handler.
Now, instead of calling appRouter.navigate you can trigger that same event.
Also, from that handler, you can call appRouter.navigate('inbox'); without passing true. Now you can get your app to the state you want without trying to force the route.
As far as I can tell... As of Backbone 0.9.10 using appRouter.navigate('inbox', {trigger: true}); works as expected.
Another option is just to call the method
appRouter.inbox();