Backbone.js history 'on route change' event? - backbone.js

Is there a general event that fires every time we navigate to a different URL?
window.App =
Models: {}
Collections: {}
Views: {}
Routers: {}
init: ->
# Initialize Routers
new App.Routers.Main()
# Initialize History
Backbone.history.start(pushState: true)
# BIND VIEW CHANGE?
$(#).on 'changeOfRoute', ->
console.log "Different Page"
$(document).ready ->
App.init()
Doing this per view is possible, but I'm looking for a general solution.

There is the "route" event on the Router:
http://backbonejs.org/#Events-catalog
"route" (router, route, params) — Fired by history (or router) when any route has been matched.
This allows you to bind to specific routes.
If you want to fire a handler after any route, bind to "route", and the route will be the first argument:
myRouter.on("route", function(route, params) {
console.log("Different Page: " + route);
});
This will only trigger events for your explicitly defined routes. If you want to trigger events for routes that are not explicitly defined, then add a 'splat' route as per How to detect invalid route and trigger function in Backbone.Controller

From the Backbone docs
This method is called internally within the router, whenever a route matches and its corresponding callback is about to be executed. Override it to perform custom parsing or wrapping of your routes, for example, to parse query strings before handing them to your route callback, like so:
var Router = Backbone.Router.extend({
execute: function(callback, args) {
args.push(parseQueryString(args.pop()));
if (callback) callback.apply(this, args);
}
});
This site has some useful code for redefining the Router to support 'before' and 'after' hooks, though it would require updating with each version-change of Backbone.

#TTT: Unfortunately Backbone doesn't give us a before/after event, so you will need to overwrite or extend the Router.route. You can find the way to do that in this answer: https://stackoverflow.com/a/16298966/2330244

May be this extension would be useful for you:
https://github.com/zelibobla/Backbone.RewindableRoute/blob/master/backbone.rewindableRoute.js

Related

What is the Angular2 equivalent to an AngularJS $routeChangeStart?

In AngularJS we were able to specify route change event to observe changes in route object using the $routeChangeStart/End event of the $rootScope. What is the equivalent of the route change event in Angular2?
how can we do this exact functionality of below code in Angular2
$scope.$on('$routeChangeStart', function (scope, next, current) {
//do what you want
});
I got some disucussions here, But it don't have more details, So I asked a new question.
angular2 $routeChangeStart , $routeChangeSuccess ,$routeChangeError
You can listen the events of the router by doing the following:
import {
Router, ActivatedRoute,
NavigationEnd, NavigationStart,
NavigationError, NavigationCancel,
} from '#angular/router';
// constructor method of some angular element
constructor(
private _router: Router,
) {
this._router.events
.filter(event => event instanceof NavigationStart)
.subscribe(event => {
console.log("New route");
});
}
EDIT: Im not completely sure is that is actually what you need, after taking a closer look to the angularjs docs seems like those events are more related to the resolution/result of a guard in angular2

Restore backbone state after navigating away and then back

I have a Backbone Marionette app which allows users to search using various criteria. From the search results they can click on a link which navigates them away from the backbone app to a standard static page.
How can I set things up so that when they click back in their browser, the backbone search page is restored back to their previous state (with search criteria and results intact)?
Thanks
You could use backbone router for your search page and save state in location.hash, so all population/rendering will be managed by router or views which will listen to router events:
"route:[name]" (params) — Fired by the router when a specific route is matched.
"route" (route, params) — Fired by the router when any route has been matched.
For example #search/query/nuggets will trigger this route:
'search/query/:query-string': function(query) {
yourCollection.fetch({data: {query: query}})
}
and in your view
initialize: function() {
this.listenTo(yourCollection, 'sync', this.render)
}
so then user click/or hit enter in your search field you just should trigger route change: yourRouter.navigate("search/query/"+yourQuery, {trigger: true})

initial route not executed when going back through history

I have a router defined somewhat similar to the following (greatly simplified for demo purposes here):
var MyRouter = Backbone.Router.extend({
routes: {
'': 'search',
'directions': 'directions',
'map': 'map'
},
search: function () {
// do something
},
directions: function () {
// do something
},
map: function () {
// do something
},
initialize: function () {
this.listenTo(myModel, 'change', this.updateNavigation);
Backbone.history.start({ pushState:true });
},
updateNavigation: function () {
var selected = myModel.get('selected');
this.navigate(selected);
}
});
The history entries are all getting created properly by the updateNavigation call, and when I hit the back-button to go back through the history I've generated, the routes fire for each of the entries, that is until I get to the initial entry. At that point, even though the url has updated with that history entry, the route that should interpret the url at that point does not fire. Any idea what might be going on here? Am I making some bad assumptions about how history works?
EDIT:
It seems I get inconsistent results - it's not always just the initial entry that doesn't execute, it's sometimes anything after the first time I've went back one through history. That is, I click the back-button once, the url changes, the routes fire properly. I hit it again, the url changes, the routes don't fire. It smacks of me doing something wrong, but I haven't a clue.
Don't ask me why, but my browser back button doesn't seem to function properly when I don't trigger: true on #navigate.
My very brief assumption is that Backbone.history.start({ pushState:true }); used in wrong place.
As far as I know, backbone history start should be after the router instance is created. Like,
var router = new MyRouter();
Backbone.history.start({ pushState:true });
I've discovered the problem. I was using a querystring and updating the querystring based on actions within the application. Each time I modified the querystring, I added another history entry, but the actual route parts of the history entry didn't always change. Backbone won't do do anything different based on the same route but with different querystring, so I had to abandon using the querystring and just make restful urls instead. Once I did that, the history worked fine.

Backbonejs - should a change in the model cause the route to change, or should all changes be through the route first?

When a model is changed, I update the route (it has a url that contains the application's current state).
When a url is visited (or back is pressed) I update the model from the route.
This creates circular logic problems for me that I can't get my head around. Things are being changed twice for no reason.
Is it normal to base everything on the route, and use that to update the model?
Is it normal to have two models?
What is normal?
Any help or advice would be appreciated. Thanks
I wouldn't advise using Router the way you do. In general, the route action should not change model state. In general, HTTP GET operations should not have side-effects.
Routers should be used for navigation between different pages of a single-page application. Model changes should be triggered directly from the view code that handles user input. Let's say you have a model User, and view UserView, the view could work something like this:
var UserView = Backbone.View.extend({
events: {
"click #save", "save"
},
initialize: function(options) {
this.model = options.model;
},
render: function() {
//your render code here
},
save: function() {
var fields = {
name: this.$("#name").val();
email: this.$("#email").val();
};
this.model.save(fields , {
//after save go back to users page, or whatever
success: function() { window.location.hash = "/users"; },
error: this.displayError
});
}
});
Backbone isn't really an MVC framework, so the Router shouldn't be treated as a pure controller. And even if you did, changing state in a route action would be equivalent to changing state in a MVC controller GET endpoint - bad, bad idea.
If you want to adhere to a pure MVC pattern, you should implement your own controller layer, or look at another layer besides Backbone.

Execute a function before changing route in Backbone.js

How can I get notified before a Backbone router call the specific routing function?
I'd like to have a generic "reset" function before rendering every page.
Is there any event I can bind?
Update: the solutions I found are based on extending the router or the history in order to trigger the event.
It looks like the 1.1.x release of Backbone has what you want with the Router.execute method:
MyRouter = Backbone.Router.extend({
routes: {},
// fired before every route.
execute: function(callback, args) {
// ...
}
});
if execute function is present it will be called before every route change but you must pass the arguments in callback to properly execute other matching routes.
MyRouter = Backbone.Router.extend({
routes: {},
// fired before every route.
execute: function(callback, args, name) {
//your logic
if (callback) callback.apply(this, args); //this must be called to pass to next route
},
});
This plugin does what you want. It works with 0.5.3. I'm not certain if it works with 0.9.1 yet or not.
https://github.com/angelo0000/backbone_filters
I' am using this in the constructor and it's working fine
this.bind( "all", this.ACL );
Here ACL is a function

Resources