Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changing can.Control.route selectors to match pushstate.js #612

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 10 additions & 7 deletions control/route/route.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,31 @@
steal('can/util','can/route','can/control', function(can){
// ## control/route.js

// ## control/route.js
// _Controller route integration._

can.Control.processors.route = function( el, event, selector, funcName, controller ) {
selector = selector || "";
if ( !can.route.routes[selector] ) {
if (selector[0] == '/') {
selector = selector.substring(1);
};
can.route( selector );
}
var batchNum,
check = function( ev, attr, how ) {
if ( can.route.attr('route') === ( selector ) &&
if ( can.route.attr('route') === ( selector ) &&
( ev.batchNum === undefined || ev.batchNum !== batchNum ) ) {

batchNum = ev.batchNum;

var d = can.route.attr();
delete d.route;
if ( can.isFunction( controller[ funcName ] )) {
controller[funcName]( d );
} else {
controller[controller[funcName]](d);
}

}
};
can.route.bind( 'change', check );
Expand Down
103 changes: 102 additions & 1 deletion route/pushstate/pushstate.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,105 @@ we can specify a root like:
can.route.url({page: "list"}) //-> "/contacts/list.html"

Now, all routes will start with "/contacts/". The default [can.root.route]
is "/".
is "/".

### Using `can.route.pushstate.js` with the `can.Control.route` plugin

The `can.Control.route` plugin is a great way to simplify your code. Not only will it bind the event listeners for routes, but it also automagically prevents clicks on matching links from reloading the entire page.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a ton for the docs! I'm going to have to change some of this text b/c using can.Control.route isn't really "recommended".


Here are some examples of binding to pushstate-style routes in a can.Control using the `can.Control.route` plugin. The first comment in each example is an href for a link that would trigger the route. The second is the contents of can.route.attr(). In each example, the contents of the data variable in the function will be the same as can.route.attr(), but without the route attribute. All of these examples assume that pushstate.root is set to the default of '/':

// Listen to the root route. See above section on pushstate.root
"route": function(data) {
// <a href="/">Go Home!</a>
// {route:""}
},

// A route with a trailing slash
"/files/ route": function(data) {
// <a href="/files/">Pretend this is a folder full of files.</a>
// {route:"files/"}
},

// A route with a file extension
"/files/batman.pdf route": function(data) {
// <a href="/files/batman.pdf">I'm Batman.</a>
// {route:"files/batman.pdf"}
},

// A route without a trailing slash
"/files route": function(data) {
// <a href="/files">The files are in the computer?</a>
// {route:"files"}
},

// A route with a wildcard parameter
"/files/:file_name route": function(data) {
// <a href="/files/robin.pdf">Holy roasted metal!</a>
// {route:"files/robin.pdf", file_name:"robin.pdf"}

// Notice that the :file_name parameter in the route becomes a separate
// attribute of can.route. This "wildcard" enables listening for
// any two-parameter route that begins with 'files'. /files/test.html
// and /files/moose would also route here.
},

// A useless route handler that will never be called.
"/files/joker.pdf route": function(data){
// <a href="/files/joker.pdf">Smile!</a>
// {route:"files/joker.pdf"}

// Why is it useless? Because, while the above href could potentially
// trigger this route event, the directly preceding route with the
// :file_name parameter will respond because it comes first in the code.
},

// Three parameters, one a wildcard.
"/admin/contestants/:id route": function(data){
// <a href="/admin/contestants/1">The price is wrong, Bob.</a>
// {route:"admin/contestants/:id", id:1}
},

// Three parameters, two wildcards.
"/admin/:page/:anchor route": function(data){
// <a href="/admin/testimonials/steve">Steve's Testimonial</a>
// {route:"admin/:page/:anchor", page:"testimonials", anchor:"steve"}

// Technically, if the route just before this one was taken out of the code,
// this route would respond to links like /admin/users/1. In that case the
// route attributes would look like this:

// <a href="/admin/contestants/1">The price is wrong, Bob.</a>
// {route:"admin/:page/:anchor", page:"contestants", anchor:"1"}

// But, because the preceding route exists, this route will respond to all
// three-parameter routes that have the first parameter of admin except for ones
// where the second parameter is users (ones that start with '/admin/users/'),
// which are picked up by the preceding route.
},

## Watch for errors inside route handlers.

Any error inside of a route handler will cause a page refresh before the error is shown. For example:

"/admin/users route": function(data){

// This will cause problems.
console.log(nonExistentVariable);

// This will cause problems
var users = someFunctionWithAnErrorInside();

// This one won't cause problems.
console.log(data);
}

In an error-free route handler, all links matching the route would not result in a page refresh, but instead would result in a pushstate change. The errors in the example will cause the page to refresh. The code will run after the refresh and show the error message.

## Planning route structure

Complications can arise if your route structure mimics the folder structure inside your app's public directory. For example, if you have a folder structure like the one in this url for your admin app...

/admin/users/list.js

... using a route of /admin/users on the same page that uses the list.js file will require the use of a trailing slash on all routes and links. The browser already learned that '/admin/users' is folder. Because folders were originally denoted by a trailing slash in a url, the browser will correct the url to be '/admin/users/'. While it is possible to add the trailing slash in routes and listen for them, any link to the page that omits the trailing slash will not trigger the route handler.