Comments (13)
I've been using History.js for my Aura routing. I tried augmenting Backbone's built-in routing, but it turned into kind of a rabbit hole I didn't want to dive down at the time.
I think if we could get that to work with Aura, it would be ideal, so I may sit down again and see if I can get it up and running.
from aura.
@dustinboston In order for routes to publish events, wouldn't we have to either generalize the routing to outside a framework or only implement this in the backbone-aura extension? Did you have a POC that describes this concept better in mind that you might be able to share?
from aura.
Better fit as an extension or use of a routing lib directly IMHO.
from aura.
@addyosmani Would it not make more sense to treat routes as another widget? This prevents the use case of two widgets implementing the same route potentially as well as centralizing all routing. You also get the described feature of Routes having events.
from aura.
So what are routers in front end js.
Let's be good scholars and dig in :D
- They monitor hashchange.
var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7));
if (oldIE) {
this.iframe = $('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo('body')[0].contentWindow;
this.navigate(fragment); // ancient ie just navigates to fragments.
}
// cross-browser events against window's popstate and hashchange
if (this._hasPushState) {
$(window).bind('popstate', this.checkUrl);
} else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE) {
$(window).bind('hashchange', this.checkUrl);
} else if (this._wantsHashChange) {
this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
}
Insight: Backbone.History
doesn't store a collection of previous hashes, instead it lets the browser handle back and forward between hashes.
- Routing
This is where it gets complicated.
We have 3 components:
Backbone.History
, which is often seen as Backbone.history
. Adding a route to a new Backbone.Router
will start up Backbone.history
automatically.
Backbone.history handles the hash changes.
// cross-browser events against window's popstate and hashchange
if (this._hasPushState) {
$(window).bind('popstate', this.checkUrl);
} else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE) {
$(window).bind('hashchange', this.checkUrl);
}
and poll with window.setInterval
:
else if (this._wantsHashChange) {
this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
}
Backbone.history
will checkUrl
:
checkUrl: function(e) {
var current = this.getFragment();
if (current == this.fragment && this.iframe) current = this.getFragment(this.getHash(this.iframe));
if (current == this.fragment) return false;
if (this.iframe) this.navigate(current);
this.loadUrl() || this.loadUrl(this.getHash());
},
Backbone.history.checkUrl
finds the route changed from this.getFragment()
, Backbone.history.loadUrl
is ran:
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); // it's hitting a callback function
return true;
}
});
return matched;
},
this.handlers
(of Backbone.history.handlers
) is from Backbone.Router.prototype.route
. It's ran against every route when you do a normal router initialization:
Where does the Router come in to play?
var Workspace = Backbone.Router.extend({
routes: {
"help": "help", // #help
"search/:query": "search", // #search/kiwis
"search/:query/p:page": "search" // #search/kiwis/p7
},
help: function() {
...
}
search: function(query, page) {
...
}
Backbone.Router
sifts through this.routes
with Backbone.Router.prototype._bindRoutes
and pumps it to Backbone.Router.prototype.route
instance one by one. Here's what happens:
route: function(route, name, callback) {
Backbone.history || (Backbone.history = new History);
if (!_.isRegExp(route)) route = this._routeToRegExp(route);
if (!callback) callback = this[name];
Backbone.history.route(route, _.bind(function(fragment) {
var args = this._extractParameters(route, fragment);
callback && callback.apply(this, args);
this.trigger.apply(this, ['route:' + name].concat(args));
Backbone.history.trigger('route', this, name, args);
}, this));
return this;
},
So as of Backbone 0.9.2, the router verifies initialization of Backbone.History into Backbone.history. If it's not initialized, it does it now.
Then it will use underscore method _.isRegExp to see if the route is a RegExp object.
The !callback
confuses me, as this[name]
and the argument from _bindRoutes
's iterator passes in the same thing, this.route(routes[i][0], routes[i][1], this[routes[i][1]])
. I thought it may been being like Marionette's AppRouter and perhaps allowing a more complex routing possibility but nah.
It will use Backbone.history.route
which accepts the RegExp
of the route and an anonymous function, let's zoom in:
_.bind(function(fragment) {
var args = this._extractParameters(route, fragment);
callback && callback.apply(this, args);
this.trigger.apply(this, ['route:' + name].concat(args));
Backbone.history.trigger('route', this, name, args);
}, this)
This dance is wrapping the callback to accept the parameter arguments and trigger a history event. And making sure to bind it against Backbone.Router's instance context - as it's being accessed from Backbone.history. With the context binded,_extractParameters can be utilized against the reference to fragment
, which is just Backbone.history.getFragment()
.
Backbone.history.route
adds this to this.handlers
, being sure to pass callback
in the hash for loadUrl()
.
route: function(route, callback) {
this.handlers.unshift({route: route, callback: callback});
},
So when Backbone.history detects a hashchange, with all of the parameters extracted as an argument, which are then passed in via callback.apply
.
passes out
edit: fixes.
from aura.
hands glass of water to Tony
Are you better?
Awesome post.
from aura.
POC for routing in branch https://github.com/tony/aura/tree/history.
#view/month
is calendar:changeView:basicWeek
Trigger this.calendar.fullCalendar
and pass changeView
and basicWeek
in as arguments.
Above: #view/:year/:month/:day
to calendar:gotoDate
.
this.calendar.fullCalendar
must pass gotoDate
as an action. This case must accept parameters.
The widget is called router. It has no DOM object on the page being used, but one is being passed to prevent error.
The lambda in Backbone.Router.prototype.route
is reused. It will only accept a route with a controller endpoint and have extracted args ready.
sandbox.publish('router', name, args);
publishes what would normally be a function prototype being extended into Router
. Instead of using a callback function, the router triggers sandbox.publish
.
The Calendar widget subscribes
and then does stuff
.
#view/:year/:month
and #view/:year
will default to current date arguments when not filled. Entering a date takes you to a date view.
from aura.
I can't believe I almost missed this. That's really awesome work @tony :) I also really appreciate all of the research work you put into figuring out a good routing strategy.
If we could add a routing support example for the Todo widget as well (e.g https://github.com/addyosmani/todomvc/tree/gh-pages/architecture-examples/backbone) I'd be happy with us merging your POC in :)
from aura.
thank you @addyosmani . sounds like a plan.
from aura.
@addyosmani just a pulse, router poc is alive using router pattern from that repo. will pr tomorrow when todo is wired in.
https://github.com/tony/aura/tree/history
from aura.
Awesome! :)
from aura.
@tony is there anything else we're waiting on for this issue or is it good to close? :)
from aura.
Closing due to age and relevance to direction in master.
from aura.
Related Issues (20)
- Doubt about duplicate element and maintain the associated events HOT 3
- Framework design flawed! Removing dependencies jQuery and Underscore. HOT 12
- Requirejs repair Tons of issues. HOT 1
- Mediator dependency removal Event Emitter HOT 3
- Support for loading of individually optimized components? HOT 15
- Asynchronous/dynamic loading of components? HOT 3
- Does Aurajs compatible with IE6? If not, how should I do to make it support?
- Error when manually loading a component
- Data management HOT 4
- ideas or plans about aura's job in relation with polymerjs HOT 5
- Can't go past a Grunt Task referring component initialize
- hi guys did you abandon the aura project? HOT 2
- Access to parent(super) methods within component HOT 1
- how to Concatenate the files of the decoupled modules HOT 4
- External links not working with Android webview HOT 1
- [BUSINESS CRITICAL] aurajs.com - github pages site is inaccessible HOT 6
- How to use jQuery and Flot with AuraJS ?
- Lightening component built upon aura js
- The project's domain is advertising some pocker stuff :)
- Aura
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from aura.