canjs - Routing Conventions in Can.js -
so i’m looking make routes within super cool can.js application. aiming this…
#!claims claimscontroller - lists claims #!claims/:id claimcontroller - views single claim #!claims/new claimcontroller - creates new claim #!claims/:id/pdf - nothing, claimcontroller handle #!admin admincontroller - loads administrative panel menu #!admin/users - nothing, admincontroller handle #!admin/settings - nothing, admincontroller handle
so how might this?
“claims route”: function() { load('claimscontroller'); }, “claims/:id route”: function() { load('claimcontroller'); }, “admin”: function() { load(‘admincontroller’); },
cool beans, we’re off. if sends link like...
http://myapp#!claims/1/pdf
nothing happens! ok, let’s add route.
“claims/:id/pdf route”: function() { load('claimcontroller'); },
great. link works. here, router’s job load controller. controller recognize pdf action wanted, , show correct view.
so pretend i’ve loaded claim claims/:id
, edit 1 or 2 things. click print preview button view pdf , change route claims/:id/pdf
.
what should happen… claim controller watching route , shows pdf view.
what happens… router sees change, matches claims/:id/pdf
route added, , reloads claim controller, displaying fresh version of claim pulled server/cache, losing changes.
to try , define problem, need router identify when route changes, controller route belongs to, , if controller loaded, ignore it. hard!
claims // claims/:id // different controllers! claims/:id // claims/:id/pdf // same controller!
we bind on "controller" change. defining routes can.route(':controller')
, binding on :controller
.
{can.route} controller // or can.route.bind('controller', function() {...})
but clicking on claim (changing claimscontroller claimcontroller) won't trigger, first token claim
same in both cases.
is there convention can lean on? should specifying every single route in app , checking if controller loaded? preferred route urls not working?
the following how setup routing in complex canjs applications. can see example of here.
first, not use can.control routes. it's anti-pattern , removed in 3.0 ideas in this issue.
instead setup routing app
module imports , sets modules convention similar this used here.
i explain how setup routing app
module in moment. first, it's important understand how can.route
different how used thinking of routing. difference makes difficult understand @ first, once it; you'll see how powerful , perfect client-side routing.
instead of thinking of urls, think of can.route's data. in can.route.attr()
. example, urls seem have data like:
- page - primary area dealing with
- subpage - optional secondary area within page
- id - id of type
for example, admin/users
might want can.route.attr()
return:
{page: "admin", subpage: "users"}
and, claims/5
might translate into:
{page: "claims", id: "5"}
when start building application, use urls #!page=admin&subpage=users
, ignore pretty routing until later. build application around state first , foremost.
once have mental picture of can.route.attr()
data encapsulates application's state, build routing app
module listens changes in can.route
, sets right controls or components. yours might like:
can.route.bind("change", throttle(function(){ if( can.route.attr("page") == "admin" ) { load("admincontroller") } else if(can.route.attr("page") === "claims" && can.route.attr("id") { load("claimcontroller") } else if ( ... ) { ... } else { // convention, load controller whatever page load(can.capitalize(can.route.attr("page")+"controller") } }) );
finally, after setting of up, make pretty routes map expected can.route.attr()
values:
can.route(":page"); // #!claims, #!admin can.route("claims/new", {page: "claims", subpage: "new"}); can.route("claims/:id", {page: "claims"}); can.route("admin/:subpage",{page: "admin"});
by doing way, keep routes independent of rest of application. listens changes in can.route's attributes. routing rules maintained in 1 place.
Comments
Post a Comment