-
Notifications
You must be signed in to change notification settings - Fork 4
Description
tldr; We propose a guide that teaches how to setup can-route to handle common use cases. We will survey common problems and design a guide or a series of small examples addressing them.
This was discussed on a recent live stream (35:49)
Problems
The following lists different problems we would like to see addressed:
- Values with delimiters (ex:
/) - Conflicting routes
- Nested routing
- Testing Routing Rules
- Preventing history changes
- Mounting pushState
- Alternate routing (turning off routing, 404s, etc)
- Switching between "page components" using convention
- Trailing slash routing
- Validating routes
- Using
can.route.datavs passing down your data. - AppVM data that shouldn't be on the route.
Please let us know in the comments below which are most important to you or others you would like to see.
Values with delimiters (ex: /)
Sometimes, people want values with / to show up as / in the url.
What you want:
route("{page}/{id}")
route.param({page: "edit", id:"c2/a1"}) //-> "edit/c2%2Fa1" NOT "edit/c2/a1"This is also related to nested routing where you would want something like:
route.deparam("folder1/folder2/folder3/fileA/meta") //-> {path: "folder1/folder2/folder3/fileA", action: "meta"}Conflicted routes:
Sometimes one routes rules might "swallow" another routing rule. For example:
route("{page}/{id}");
route("items/{itemId}");
route.deparam("items/5") -> {page: "items", id: "5", route: "{page}/{id}"}I've seen the following rules also desired:
top -> {category: "all", sort: "top"}
sports -> {category: "sports", sort: "top"}
sports/latest -> {category: "sports", sort: "latest"}The guide should cover how to handle these situations.
Nested routing and/or composite routing
Is there a good pattern to take multiple "little" apps, each with their own routing rules, and compose them?
var loginRules = [
"{user}/{action}"
];
var recipeRules = [
"{recipe}/{id}"
]
route("login/{user}/{action}");
route("recipe/{recipe}/{id}");Testing Routing Rules
Lets detail how you can test your routing rules to make sure they work.
// routes.js
import route from "can-route";
route( ... )
route( ... )
// test.js
import route from "can-route";
import "./routes"
assert.deepEqual( route.deparam("foo/bar"), {page: "foo", action: "bar"})
assert.deepEqual( route.param({page: "foo", action: "bar"}, "foo/bar" );Preventing History Changes
With pushstate, it's possible to prevent a history entry when someone navigates to recipe/5/view to recipe/6/edit. Using replaceStateOn, replaceStateOnce, replaceStateOff. We should explain how.
Mounting pushState
can-route-pushstate defaults its mounting to /. It's possible to change this to /where/my/app/belongs. So only routes within /where/my/app/belongs will use pushState. Lets show how to do this.
Alternate Routing Scenarios
There are a few scenarios that would be good to demonstrate:
- When the application is loading with the url
/user/secrets, but the user is not logged in, we might want to show them the login page, but keep the url/user/secrets. - If the user goes to a page that is unavailable or broken, how do we send them a 404?
- How do we let people go to a page that would normally be
pushState-d? For example, a route like{page}, but we want the specialcheckoutpage to be loaded from the server.
Switching between "page components" using convention
Its very common to have some sort of convention to align a page property to similarly named component. For example, Bitballs does this. We should show how to do this. Bonus points if we can also show how to animate it.
Trailing slash routing
Often folks want /foo and /foo/ to route to the same page. Lets show how to do that.
Validating routes
If a user is on /user/2 and wants to go to /user/3/secrets with:
route.data.update({
page: "user",
id: 3,
action: "secrets"
})How can you check that this is an ok page transition?
Using can.route.data vs passing down your data
For connivence, many components use the global route.data to interact with the route.
For example:
VM = {
saveAndReturnToView(){
this.data.save().then(() => {
route.data.page = "view";
})
}
}Alternatively, the route's data can be passed to the component:
<my-component page:bind="appViewModel.page"/>
VM = {
saveAndReturnToView(){
this.data.save().then(() => {
this.page = "view";
})
}
}Which pattern should you use and why? If you do use the first pattern, how can you test it without breaking your tests. How can you make demo pages?
Preventing AppVM data from being on your route
When connecting a VM to the route, it's common for the VM to have properties that should not be serialized for the route.
DefineMap.extend({
someData: {serialize: false} //-> will not be sent to the url
})