I am trying to redirect route to another before route callback is executed. I have following piece of code:
console.log("file loaded");
(function (History) {
var _navigate = History.prototype.navigate;
_.extend(History.prototype, {
navigate: function (fragment, opts) {
alert("adad");
return _navigate.call(this, fragment, opts);
}
});
})(Backbone.History);
This code wraps Backbone.History.navigate
method, and showing alert on the method call. But this alert never shows up when I am changing routes.
The console.log
line is just to be sure that file has been loaded after backbone.js.
What is wrong with this code?
An important part of "routing" is handling redirects. Redirects usually happen when you want to preserve an old link and send all the traffic bound for that destination to some new URL so you don't end up with broken links.
When the application start, it navigates to the empty route by default. We can configure the router to redirect to a named route by default. So, a redirect route translates the initial relative URL (”) to the desired default path.
replace() method to redirect to an external url in React, e.g. window. location. replace('https://google.com') . If a certain condition is met, you can programmatically replace the current resource with the provided URL by calling the replace() method.
I think you're overriding the wrong thing: that navigate
isn't used the way you think it is.
Let us look at part of Backbone.history.start
:
// Start the hash change handling, returning `true` if the current URL matches
// an existing route, and `false` otherwise.
start: function(options) {
//...
if (this._hasPushState) {
Backbone.$(window).on('popstate', this.checkUrl);
} else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE) {
Backbone.$(window).on('hashchange', this.checkUrl);
} else if (this._wantsHashChange) {
this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
}
You'll see that all the various ways of handling routing in Backbone go through checkUrl
rather than navigate
. The checkUrl
method does a bit of busy work and calls loadUrl
; one part of the busy work is this:
if (this.iframe) this.navigate(current);
so navigate
will be called but only when an <iframe>
is being used to simulate hashchange
and popstate
events and AFAIK that only happens when you're using an older version of IE.
Back to the usual path through the code. We've seen that checkUrl
does some busy work and calls loadUrl
so what does that do? loadUrl
does this:
loadUrl: function(fragmentOverride) {
var fragment = this.fragment = this.getFragment(fragmentOverride);
var matched = _.any(this.handlers, function(handler) {
if (handler.route.test(fragment)) {
handler.callback(fragment);
return true;
}
});
return matched;
}
If you look at the route
method in History
and the route
method in Route
you'll see that handler.callback
is what calls the route handler from one of your routers and triggers the routing event.
The navigate
method that you're replacing is pretty much only used by Router
's navigate
:
navigate: function(fragment, options) {
Backbone.history.navigate(fragment, options);
return this;
}
If you want to redirect before the route handler is called, you could replace loadUrl
with something like this:
(function(History) {
var _loadUrl = History.prototype.loadUrl;
_.extend(History.prototype, {
loadUrl: function() {
var args = [].slice.apply(arguments);
args[0] = this.getFragment(args[0]);
// If args[0] is the fragment that you want to
// redirect then replace it here or do whatever
// needs to be done.
return _loadUrl.apply(this, args);
}
});
})(Backbone.History);
Demo: http://jsfiddle.net/ambiguous/e4KYK/
Overall I think you'd be better off handling the redirect in a normal route handler: when the offending route is called, just call navigate
on whatever router is handy.
Keep in mind that Backbone.History
isn't documented beyond the start
method so everything here is subject to change.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With