Backbone.js - Routers, view rendering and general conceptualizations - backbone.js

I've done a fair bit of introductory tutorial reading (including Absolute Beginners, Learn it Completely, and large parts of the 2 Code School Backbone courses) and I can completely see the potential that Backbone offers. But the comprehension light bulb hasn't quite turned on yet...I think the vast majority of examples being simple todo apps makes it seem a lot more trivial than it actually is when working on more complex projects.
My experiments have gone ok to a point - but I think getting answers or feedback about the following series of scattershot questions now might save me a lot of frustration and move me up the learning curve towards where I'd like to be. I've tried to include relevant snippets for examples that are of a detailed nature.
1) Routers are awesome, but are / are not the place for any heavy lifting?
The following router works to move user from initial page load into a specific route (search) which has its SearchBoxView instantiated in the last js loaded similar to app.js in the TodoMVC example. However trying to setup the views in router as shown for SummaryResultsView generates an 'is not a constructor' error.
var Workspace = Backbone.Router.extend({
routes: {
'': 'default',
'search': 'searchBox',
'summary': 'summary',
'detail': 'detail',
},
default: function() {
console.log("Router: Default");
track.Router.navigate("#search", {
trigger: true,
replace: true
});
},
searchBox: function () {
console.log("Router: Search");
},
summary: function () {
console.log("Router: Summary");
new track.SummaryResultsView({ el: $("#summary #results")});
},
I JUST found https://github.com/thomasdavis/backbonetutorials/blob/gh-pages/examples/modular-backbone/js/router.js which seems to have the router initialize behaving in a similar fashion to what I'd expect. Will try that approach next.
2) Do you have to a main page view that builds a lot of state logic in render?
What I was aiming for with the router above is that each route will have a number of views that show / hide or change their presentation based on results in the collection. Setting up what views to render on state change seemed like a good place. The TodoMVC example has the app.js view render function does a lot of the equivalent logic.
3) Underscore Templates in external files w/o require.js
I'm pretty sure I'll get to including require.js eventually - but to simplify part of the learning curve wanted to start without it. Also b/c the templates will be pulling field titles from a separate CMS and not (yet) sure how nice it will play with AMD.
4) Can it help reduce plugin dependencies like colorbox and datatables?
One of the proof of concept items I'm working towards with Backbone is a smedium-sized app that has a fair amount of presentation code written explicitly to work with these jQuery plugins. It isn't bad persay, but it seems like writing similar functionality in backbone structure would be a bit more maintainable or at least legible to understand what it is doing. Mind you, I found backbone tablesorter (out of links for post) in my travels and can't (yet) tell if it would result in any more or less tightly coupled code w.r.t plugin.
Thanks!

Routers
Sure they can be used for heavy lifting - I am sure you've heard it before, but Backbone just provides the bare-bones to built on-top of as you choose.
I would set the SummaryResultsView to a variable on the Workspace router. Otherwise whenever you call Workspace.summary() you will have ghost views hanging around.
I am not sure what you are doing with track.Router.navigate as it looks like it shares the same route #search as that defined in your Workspace router, which would cause both routes to be called.
You could always create multiple routers to help you divide your code up between different sections of your application. Starting with a main router and having child routers is usually what I try and aim for.
Main Page Views
Again, some people like doing it this way and others like to kick things off from a router. If you find you have a massive main view, try splitting it into smaller views so that you Don't Repeat Yourself.
Caching views can be useful - so on a main view that is only created once (on your application start) you could do:
var MyView = Backbone.View.extend({
childView: null,
toggleChildView: function() {
if (this.childView) {
this.childView.toggle(); //Toggle show/hide
} else {
this.childView = new ChildView({model: someModel});
}
}
});
Underscore Templates
I actually found that using require.js helped me learn. It certainly helps when the application starts to grow in size - there is a require.js implementation of the TodoMVC app - if you didn't already know.
You won't be able to use external templates without the require.js (text plugin) as it uses an AJAX call to grab the template files. Unless of course you design your own AJAX call to pull in the template files but it seems like a rather long-winded way to go about it.
Template files are static - I don't fully understand how you mean pulling from a separate CMS?
Just for a side note - if you use the require.js optimization it actually in-lines your templates so they are included in one fat JS file.
Porting code
If you figure out a very generic Backbone model that works with the jQuery plugins (I have one for a jQuery UI date picker) you can pretty easily port it between applications without too much fuss. This is sped up if using require.js as its already in a separate file (copy and paste FTW).
Hope this helps!

Related

When and where to use multiple controllers/directives/services/factories in angularjs?

I am very new to angularJs.I understood the some concepts but still a lot of things are not clear.I am looking for your help to understand me the following scenarios with some demonstration for clear understanding.
When should I use more than one Directive/Controllers/Factories/Services etc.
Whether I should go for more than one directive or more than one controller.
Similarly whether I should go for more than one factory or more than one directive ... or more than one controller.
Any help is appreciated.
Thanks
I will give you a very simple account of what you can do with them.
Controllers are for handling operations related to a specific view. If you have Students Area and Teachers Area in the same markup and are operated in their own territories, you should probably go for two controllers to manage them.
controller('students', function($scope) {
//Load all students
$scope.allStudents = getAllStudents()
//Setup preferences
$scope.showAll = false;
});
Factories and Services are a great ways to break your code up in to different segments. Let's say you have lot of functions for Student Profiles and Student Scores. You can have two factories to organize them better.
studentProfiles.registerStudent(name, class);
studentProfiles.assignClass(id, class);
studentScores.getAllScores(id);
studentScores.saveScores('science', 97);
You should go for directives when you need to manipulate DOM. Angular directives are complex and have a very broad view. Things you can do with these are so much. Let's say you need to attach the image of each student in a view where their names are shown.
<div student-name id="255">
directive('studentName', function(studentProfiles){
link: function(ele, attr) {
//This line is for pseudo meaning only
ele.append('<img src="' + studentProfiles.getStudentPicture(attr.id) + ">');
}
})
There are ample of beginners guides available in the internet. Follow them and take time to do your own practice projects.
All your questions are pretty the same thing i.e. whether to put all the code in one place or in many. I'd say that in almost every applications you should have many controllers, factories, services or directives (if they are used). Why?
Mainly because it makes the code more readable. For example in the case of a simple shopping application you will have controllers responsible for registration of users (RegisterUserCtrl), showing the list of items to buy (ItemsCtrl) and so one. Everyone who will see a name RegisterUserCtrl will know what it does.
It also makes working with code easier. One big controller/factory/service doing everything will quickly have hundreds or thousands lines of code. And it will be difficult to find anything there and maintain this code. I also think that modular code is easier to test.
All, I've written is true not only for AngularJS but also for other technologies.

Best open-source grid with smooth, infinite scrolling

When I started working on my current project I was given quite an arduous task - to build something that in essence suppose to replace big spreadsheet people use internally in my company.
That's why we I thought a paginated table would never work, and quite honestly I think pagination is stupid. Displaying dynamically changing data on a paginated table is lame. Say an item on page #2 with next data update can land on page whatever.
So we needed to build a grid with nice infinite scroll. Don't get me wrong, I've tried many different solutions. First, I built vanilla ng-repeat thing and tried using ng-infinite-scroll, and then ng-scroll from UI.Utils. That quickly get me to the point where scrolling became painfully slow, and I haven't even had used any crazy stuff like complicated cell templates, ng-ifs or filters. Very soon performance became my biggest pain. When I started adding stuff like resizable columns and custom cell templates, no browser could handle all those bindings anymore.
Then I tried ng-grid, and at first I kinda liked it - easy to use, it has a few nice features I needed, but soon I realized - ng-grid is awful. Current version stuffed with bugs, all contributors stopped fixing those and switched to work on a next version. And only God knows when that will be ready to use. ng-grid turned out to be pretty much worse than even vanilla ng-repeat.
I kept trying to find something better. trNgGrid looked good, but way too simplistic and doesn't offer features I was looking for out of the box.
ng-table didn't look much different from ng-grid, probably it would've caused me same performance issues.
And of course I needed to find a way to optimize bindings. Tried bind-once - wasn't satisfied, grid was still laggy. (upd: angular 1.3 offers {{::foo}} syntax for one-time binding)
Then I tried React. Initial experiment looked promising, but in order to build something more complicated I need to learn React specifics, besides that thing feels kinda non-anguleresque and who knows how to test directives built with angular+react. All my efforts to build nice automated testing failed - I couldn't find a way to make React and PhanthomJS to like each other (which is probably more Phantom's problem. is there better headless browser) Also React doesn't solve "appending to DOM" problem - when you push new elements into the data array, for a few milliseconds browser blocks the UI thread. That of course is completely different type of problem.
My colleague (who's working on server-side of things) after seeing my struggles, grumbled to me that I already spent too much, trying to solve performance problems. He made me to try SlickGrid, telling me stories how this is freakin zee best grid widget. I honestly tried it, and quickly wanted to burn my computer. That thing completely depends on jQuery and bunch of jQueryUI plugins and I refuse to suddenly drop to medieval times of web-development and lose all angular goodness. No, thank you.
Then I came by ux-angularjs-datagrid, and I really, really, really liked it. It uses some smart bad-ass algorithm to keep things very responsive. Project is young, yet looks very promising. I was able to build some basic grid with lots of rows (I mean huge number of rows) without straying too much from the way of angular zen and scrolling still smooth. Unfortunately it's not a complete grid widget solution - you won't have resizable columns and other things out of the box, documentation is somewhat lacking, etc.
Also I found this article, and had mixed feelings about it, these guys applied a few non-documented hacks to angular and most probably those would breaks with feature versions of angular.
Of course there are at least couple of paid options like Wijmo and Kendo UI. Those are compatible with angular, however examples shown are quite simple paginated tables and I'm not sure if it is worth even trying them. I might end-up having same performance issues. Also you can't selectively pay just for the grid widget, you have to buy entire suite - full of shit I probably never use.
So, finally to my question - is there good, guaranteed, less painful way to have nice grid with infinite scrolling? Can someone point to good examples, projects or web-pages? Is it safe to use ux-angularjs-datagrid or better to build my own thing using angular and react? Anybody ever tried Kendo or Wijmo grids?
Please! Don't vote for closing this question, I know there are a lot of similar questions on stackoverflow, and I read through almost every single one of them, yet the question remains open.
Maybe the problem is not with the existing widgets but more with the way you use it.
You have to understand that over 2000 bindings angular digest cycles can take too long for the UI to render smoothly. In the same idea the more html nodes you have on your page, the more memory you will use and you might reach the browser capacity to render so many nodes in a smooth way. This is one of the reason why people use this "lame" pagination.
At the end what you need to achieve to get something "smooth" is to limit the amount of displayed data on the page. To make it transparent you can do pagination on scroll.
This plunker shows you the idea, with smart-table. When scrolling down, the next page is loaded (you will have to implement the previous page when scrolling up). And at any time the maximum amount of rows is 40.
function getData(tableState) {
//here you could create a query string from tableState
//fake ajax call
$scope.isLoading = true;
$timeout(function () {
//if we reset (like after a search or an order)
if (tableState.pagination.start === 0) {
$scope.rowCollection = getAPage();
} else {
//we load more
$scope.rowCollection = $scope.rowCollection.concat(getAPage());
//remove first nodes if needed
if (lastStart < tableState.pagination.start && $scope.rowCollection.length > maxNodes) {
//remove the first nodes
$scope.rowCollection.splice(0, 20);
}
}
lastStart = tableState.pagination.start;
$scope.isLoading = false;
}, 1000);
}
This function is called whenever the user scroll down and reach a threshold (with throttle of course for performance reason)
but the important part is where you remove the first entries in the model if you have loaded more than a given amount of data.
I'd like to bring your attention towards Angular Grid. I had the exactly same problems as you said, so ended up writing (and sharing) my own grid widget. It can handle very large datasets and it has excellent scrolling.

AngularJS : "Deep" application vs. "wide" application? AKA many components/directives vs. many controllers

Which is better: to split up an application into many different directives/components or into many different controllers?
Splitting up the application into many different directives/components creates a "deep" application. There are more files in a "deep" application, but is inherently more modular. Advantages: working in a team environment, there is less chance that two people's efforts will bump into each other (causing painful merges). It's easy to share code between projects. Disadvantages: if you want to look into an issue, you have to follow a chain of code to get to where you need to be. Example: there is an issue with a radio directive. You must first go to the template, figure out which component the radio directive is probably in, look in there to see the directive definition, then finally go to the directive file.
Extreme example: imagine a form with 10 questions. Each question is a directive. The form itself is a component. The form is loaded into a visual section, which the section is a component. The various sections that make up the page are loaded into the template. If you were new to the project, and there was a problem with form question 7, you must "dig" from the template down to find the directive.
Splitting up the application into many different controllers creates a "wide" application. There are less files in a "wide" application, but each controller is in charge of one aspect of the template. Advantages: you can easily look in the template and find everything defined. Each area of responsibility is taken over by a controller. Disadvantages: in a team environment, multiple people will be working in the same file. Sharing code with projects is more involved.
Extreme example: imagine a form with 10 questions. Each question has a controller (for validation). The form has a controller (to check when all questions are valid). The form resides in a section, which has a controller. If you were new to the project, and there was a problem with form question 7, you would have to find the controller that controls.
So which do you think is better and why? A "deep" application or a "wide" application?
Vocabulary (as I understand it, and please feel free to correct me)
Directive: comprised of an HTML template and a javascript directive file. You put your DOM manipulation logic in here, or any other complicated logic. Example: a drop-down, a datepicker, anything from jQuery UI.
Component: a reusable piece of code meant to abstract commonalities. You can do this visually; imagine a comic book page. There are many frames separated by gutters. Each frame is a component, meant to hold a piece of art.
Template: brings together all partials, components, and directives. The template will be rendered by angular into the view.
Partial: a piece of static HTML that is meant to be pulled into a template.
View: the compiled version of the template. The view doesn't exist until angular compiles it.
I vote for "deep" variant. Code reuse is a very important thing.
You must first go to the template, figure out which component the
radio directive is probably in
Why? Just look at name of the directive and open corresponding file. Create predictable folder structure when you can find any necessary file by name of directive or controller or service.
For example, your directive named acme-radio where acme is your vendor-prefix, so file should be in folder vendor/acme/directives/radio.js.
Other directive is exclusive for some app and named acme-appName-radio - file should be in appName/directives/radio.js.
It's just rough example.

D3 with Backbone / D3 with Angular / D3 with Ember?

I'm working on a medium sized application that is going to include a lot of D3 charts / interactions in it. I'm wondering if anyone has tried to use Backbone, Angular, or Ember with D3, and if so, which one seems like the best fit for a front end MV* framework. The application won't be doing a whole lot of CRUD operations, mainly interactive charts and widgets to manipulate them.
Any comments appreciated!
We used d3 with Backbone pretty extensively on a project that consisted of multiple "scenes". Each scene contained a set of different charts, and a user has the ability navigate from one scene to another. These scenes and their content all needed to be highly configurable (e.g. label colors and formatting, or indicating which data params should be plotted on a given axis).
D3 (rightfully) doesn't provide a view management system, which is where Backbone took over. Backbone Views served as wrappers for d3 charts. Predictably, Backbone Models served as the carriers of the d3-plotted data. But more interestingly, we also found that they served well as a means of controlling the appearance and behavior of the d3 code contained within the Backbone Views; essentially they served as view models. Since d3 promotes passing functions as arguments into other functions, these Backbone Models-as-view-models ended up holding many functions in them.
The following is a simplistic example, but picture doing this with dozens of properties. Using coffeescript here, because it's shorter (and better).
First, there's the model, which we instantiate inside (for example) a router's event handler. We populate this model with functions that will be applied to d3 selectors.
barChartModel = new Backbone.Model
barColor: (d, i) -> if d.profits < 0 then "red" else "green"
barLengthVal: (d, i) -> return bar.profits #// profits will be the prop we graph
onClick: (d, i) ->
console.log "We are", if d.profits <= 0 then "losing" else "making", "money"
data: someJsonWeLoaded
We pass this model into a new view:
barChartView = new BarChartView
el: "#the_bar_chart"
model: barChartModel
A view might be implemented like this:
class BarChartView extends Backbone.View
render: ->
bars = d3.select(#el)
.selectAll('.bar')
.data(#model.get 'data') # <---- THIS
bars.enter()
.attr('class', 'bar')
.attr('fill', #model.get 'barColor') # <---- THIS
.attr('height', (d, i) ->
#barLengthScale #model.get('barLengthVal')(d, i) # <---- AND THIS
)
.on('click', #model.get 'onClick') # <---- INTERACTIVITY TOO
initialize: ->
#barLengthScale = d3.scale.linear()
.domain([-100, 100]) # <---- THIS COULD ALSO COME FROM MODEL
.range([0, #$el.height()])
#render()
I have used D3 with Angular on a few dashboards, and it worked very well. I have never really used Backbone, and not with D3, so I cannot compare the two. I chose Angular to complement D3 because it appeared to me that lately the D3 community has been using D3 with Angular the most of the three options you mentioned, so there were great resources available. There has recently been an entire book dedicated to using D3 and Angular together. I had also used Angular a bit before, and was aware of directives. Directives (in Angular it is a way to extend html tags) are great for meshing with D3. Each chart can become a directive, and then makes it extremely easy to reuse charts, changing only the $scope data. These are some resources I found helpful when combining the two:
https://www.youtube.com/watch?v=aqHBLS_6gF8
https://leanpub.com/d3angularjs
http://plnkr.co/edit/WnoCtNPV9azj0oPwv9kM?p=preview
http://vicapow.github.io/angular-d3-talk/slides/demos/a-donut-chart-editor/index.html#/
I recently gave a talk on this very topic, here are some links: Video · Code · Slides
I've done some smaller projects using similar methods to meetamit, but have recently started exploring Ember + D3. I haven't done much yet, but I think Ember has a lot to offer that could simplify building these types of app. Some things that come to mind:
Computed properties: you'll often be displaying aggregates, so slicing your data using computed properties means you just have to call your chart's update function whenever the data changes, and you're good to go. No more worrying about sending off an event to every view that will change when one specific part of your data changes. Plus, these will probably be properties on your controllers, instead of being calculated within a specific chart or view, which will make reuse much easier.
Storing state: I had a tough time figuring out the best way to store state in Backbone. I started out trying to coordinate everything via events, but in the end landed on having a separate State model which acted as the brains of the whole system.
I didn't get around to using Backbone's router much, but Ember's router + focus on state has made this design challenge easier for me so far. If you build within the system, you can click around your filters and controls, and everything just works. It may be possible to do exactly the same thing in Backbone, but there's something to be said for seriously reducing your cognitive load. You can also explicitly use a StateManager object - there may be some really interesting solutions here, though I haven't explored them yet.
Again, my experience with this combo is shallow, but if my instinct is right there are going to be many gains from building visualizations within Ember's conventions.
If you haven't already come across this, Square put up an article briefly covering their experience building an interactive dashboard with Ember + D3.
Keep us up to date on your progress + any insights you come across, and good luck!
My group has used both angular and backbone with d3, and we like both for different reasons.
Backbone
Backbone is a bit less opinionated about the way you construct your application, which is nice if you need to customize the way data is getting handled for performance. You generally integrate d3 with a backbone view.
One challenge of working with Backbone is memory management for complex views, but using marionette helps with that. Also Marionette's event aggregator (and specifically using request-response) is a good fit for centralized data sources for coordinated views if you want to use something like crossfilter or lunr.
Angular
Angular is more structured, and it is allows you to build up cool features very quickly. It has a steep learning curve, but I've found now that I'm understanding angular (having using it to develop an application for the past ~4 weeks), I've found that I can accomplish many of the same things I can in backbone without resorting to anything too hackish.
Like the request-response object in backbone marionette, using angular services allows you to build up complex views quickly. You'll need to avoid using angular's dirty checking on $scope data for complex data visualizations to keep your application from bogging down, so the code you write for working with your data in angular is going to end up looking a lot like the code you would write in backbone.
I had resisted angular's "magic" for a while, but I'm starting to get won over by the speed of development you can achieve because of all the built in directives, scope checking, and other goodies. Angular still allows you to poke around in its internals to speed up your code when that's required. This "digging" may take more time than in backbone (because the code base is more complex), but I've found that time lost in this phase is usually recouped by time saved avoiding common bugs like memory leaks in view code and writing boilerplate code like view rendering and data binding.
In summary
Backbone is a good choice if you need extensive control and customization
Angular is excellent if you really like data binding
Ember is probably fine too, if for no other reason than Square uses (used?) it, and Mike Bostocks worked for Square.
In any framework the "hard" data intensive parts of your app are probably going to look similar if you write them well (i.e. get the data transformations into services and put a clean simple interface around your view code)
D3 on Angular
I use D3 on Angular since one year and I love the combination of both. Angular uses directives to create new and reusable HTML elements. When you have this knowlegde, you can encapsule a D3 visualization in an Angular directive without having D3 in your controllers or somewhere else. After that you can reuse the directive everywhere in your application to visualize your data. When working in a team of multiple Angular developers, the rest of your team doesn't need to know anything about D3, because your D3 code exists only in the directive.
Directives in Angular give you a flexible way of dealing with data. You can choose whether your data persists in your directive (then you will have a static reusable visualizaiton) or you make a data binding to a controller in your Angular application (then you will have a dynamic reusable visualization). The latter can be achieved by setting a scope in your directive
scope: { data: '=' /* bi-directional binding */ },
setting the data in your controller
$scope.data = [23,44,22];
and join both in your HTML element instance
<div your-new-d3-element data="data"></div>.
Thats it!
Furthermore you can use watcher in your directive to watch changing data in your controller. A nice example of reusable d3 directives in Angular gives this example: http://bl.ocks.org/biovisualize/5372077
Moreover you can find an easy D3 on Angular setup in this article: http://goo.gl/hNS8k1
On this site you find further introductions how to use d3-plugins like the fisheye plugin in your Angular application or how to implement more complex d3 visualizations in Angular.
I have worked with Backbone+d3 and with Angular+d3 a little bit.
Backbone suffer with memory leaks problem and if you use backbone you should be accurate with garbage collection. However as mentioned before marionet or chaplin can easily solve this problem. If you want to have light and fast application I recommend you to use react engine for views and backbone models for other needs.
As to Angular it has more strict structure. However, I believe that it will be almost the same logic as Backbone. Angular takes care about architecture and everything what is needed just write code by refs and it will be maintable. Unlike backbone, where structure is your option.
I recommend you to compare routing, bindings, models to select right framework, but not views.
I always choose backbone + smths, often React. Because it is flexible and easy to manage application views. F.e. when we found react we moved from backbone to react to fix our mremory leak problems. However applicarion had about 50 views with different data visualisation tools with many controls. And we moved views step by step in two month.
It is difficult to do same thing with same efforts in angular.
D3 on Angular.js
I think these types of questions don't really have a right answer IMO, it's like asking someone whether they should choose a Subaru or a Toyota, when all they need to do is get from a to b :) Anyway, using AngularJS and D3 at the moment, so far so good :) There is a nice AngularJS directive for D3 and NVD3, if you do choose to go with AngularJS.
Also, check out this excellent post on combining D3 with AngularJS.
Happy exploring!

Preferred way of creating links with backbone.js

I'm trying to wrap my head around backbone.js but I'm finding it hard due to the lack of (IMO) good examples.
First of all, what is the best way of getting a link to an object.
If I want to get the edit url of an Album model I could do album.url() + '/edit', is this really the best way?
Also, I'm trying to make my application work 100% without javascript so I don't want my URLs/links to say /albums/#1/edit, I want it to be /albums/1/edit and override this in JS.
I'm thinking I create normal URLs and use jQuery.live to call router.navigate in backbone.js
I never got this to work however, when I call router.navigate('/albums/2', true) the URL changes but my show action is never called. If I refresh it's called so the route is matched.
What am I missing?
The basic answer, which is kind of frustrating, is "there is no preferred way!". Backbone.js doesn't tell you how to set up links, you can do it any way you like. I found this flexibility just as annoying as you do, at least at first.
So here's the way I'm approaching this on my current project, with the (big) caveat that this is just one of many ways to do things in Backbone:
For the most part, I don't use actual links. There's no explicit reason not to, but it means you have to keep track of a bunch of URL strings that have to be consistent. I would rather stick all the URL formatting in my routers and not deal with it elsewhere.
To open a new "top-level" view, like an editing screen, I set something that fires an event. In the application I'm currently working on, I have a global State model, and to open a new view I call state.set({ topview: MyTopView }). This causes the state object to trigger change:topview.
Any piece of the UI that needs to change when the top-level view changes has an update method bound to change:topview. When the event fires, they look at state.get('topview') and update as necessary.
I treat my routers as only marginally specialized parts of the UI - they're essentially views that render in the browser address bar, rather than the window. Like other views, they update the state object on UI events (i.e. a new URL), and like other views, they listen to the state object for changes that cause them to update. The logic that the editing screen has the URL albums/<albumid>/edit is fully encapsulated in the router, and I don't refer to it anywhere else.
This works well for me, but it adds an entirely new pattern, the global State object, to the Backbone structure, so I can hardly call this the "preferred" approach.
Update: Also note that .url(), in the Backbone idiom, refers to the model's URL in the back-end API, not the front-end URL (it's not like Django's get_absolute_url). There is no method in the default Backbone setup that gives you a user-facing URL for your model - you'd have to write this yourself.
Also, I'm trying to make my application work 100% without javascript; so I don't want my URLs/links to say /albums/#1/edit, I want it to be /albums/1/edit and override this in JS.
you can do exactly this w/ pushState. just enable it in your Backbone.history.start call:
Backbone.history.start({pushState: true})
this tells Backbone to use the HTML5 History API (a.k.a. "PushState"), which uses full URLs exactly like you're wanting.
read up on the history api here: http://diveintohtml5.ep.io/history.html
and I wrote up a 2 part series on using pushstate w/ the second part focusing on progressive enhancement in backbone, to do what you're needing:
http://lostechies.com/derickbailey/2011/09/26/seo-and-accessibility-with-html5-pushstate-part-1-introducing-pushstate/
and
http://lostechies.com/derickbailey/2011/09/26/seo-and-accessibility-with-html5-pushstate-part-2-progressive-enhancement-with-backbone-js/
hope that helps :)

Resources