Structure: Using a library like Backbone guides you to structuring your code in loosely a MVC design pattern. Coupled with a templating framework, this ends up producing code that’s much easier to follow and maintain. Before Phonegap, I’d already started using Backbone in traditional Symfony2 projects just to get the benefit of better structured code.
It’s familiar: This is a personal preference, but compared to declarative frameworks like AngularJS, Backbone/Marionette apps “look” like regular HTML/JS. Primarily because of the regular HTML templates and use of jQuery, the learning curve for Backbone isn’t very steep. A team member without Backbone experience can quickly grok how things work and make changes quickly.
“There’s more than one way to do it”: Although flexibility is good, having a generally “well recommended” way usually helps decrease confusion and frustration. With Backbone/Marionette, there doesn’t seem to be much consensus on how to do “standard” things like message passing or even structuring the app as a whole. There’s dozens of StackOverflow answers debating the “best” way to approach things, often with outright conflicting viewpoints. In contrast, Symfony2 and Rails typically have “best practices” for approaching common tasks, even if they’re not appropriate in every circumstance.
Documentation: The documentation for Marionette, and to a lesser degree Backbone, is pretty lacking. The Marionette documentation explains how the individual components work but they didn’t provide much insight to the “big picture”. The docs were also missing some explanation into the “why”, which of course lead to StackOverflow answers and then differing viewpoints. Marionette is also short example apps which Backbone does have. The Backbone documentation is thorough, its just a bit hard to navigate and purposefully introduces the “There’s more than one way to do it” mantra.
Anyway, on the whole using Backbone with Marionette to build a Phonegap app was a positive experience. Unfortunately, our clients’ own the code so we can’t release it. That said, we’ll do our best to build something in-house that we can share.
Over the weekend, I was looking for a good way to randomly browse GitHub. I hopped over to the GitHub search page but unfortunately there isn’t anyway to randomly search the repositories.
Just for fun, I decided to throw together a random repository browser. Check it out over at http://v3.setfive.com/adatta02_gitstumble/
Posted In: Demo
Here is the “source” string that is passed into “new Function”:
That is the dynamic function generated for the following template:
Since its looking for the “template” function in the global scope it looks like everything should work fine. To test it, I decide to take the Fibonacci sequence and generate boxes for each of the numbers in the sequence up to some N.
Theres a live demo running at http://twitlabs.net/us/ and a Gist of the code is replicated below:
Just for fun, you can also change how the boxes are arranged by toggling between “Stacked” and “Cascaded”.
Anyway, fair warning – I imagine there are some performance implications regarding doing this as well as computational limits. You could potentially cause a stack overflow by consuming your entire stack via the recursion.
As always, questions, comments, concerns welcome!
Anyway, one of the core concepts of Backbone is that client side models will be automatically synced with their server side counterparts via RESTful AJAX calls. Stripping away the buzzword bingo, what that means is that when a Backbone model is created in the UI a AJAX POST request is initiated to create that model, updates trigger a PUT, and destroying a model will cause a DELETE.
Conceptually, this system makes a lot of sense and it fits nicely with how data is structured in most apps. Unfortunately, it falls apart when there isn’t a one to one correspondence between frontend Backbone models and your backend persistence layer.
For example, say on the frontend you wanted to allow a user to enter and edit the various languages she spoke. Naturally, you could define a Backbone “Language” model, managed by a “LanguageList” Collection, and finally drawn with a “LanguageView” View. This would work great but unfortunately on the backend you’re storing the list of languages the user speaks in a single row – say as a CSV list for arguments sake. At this point, you’d be stuck because Backbone would be pushing AJAX requests per model and your backend would have no way to combine the languages into a CSV list.
In this instance it seems like you really want “JSON over REST”, in the sense that you want to push update events for several models on a single request. The Backbone FAQ mentions this technique but unfortunately doesn’t elaborate on specifically how to achieve this behavior.
Batch operations on Models are common, but often best handled differently depending on your server-side setup. Some folks don’t mind making individual Ajax requests. Others create explicit resources for RESTful batch operations: /notes/batch/destroy?ids=1,2,3,4. Others tunnel REST over JSON, with the creation of “changeset” requests:
Google’ing around I stumbled across this StackOverflow answer – http://stackoverflow.com/questions/11298152/how-to-do-batch-operations-in-backbone-js-via-tunneling-rest-over-json which seems to have been removed. The answer basically suggested embedding a Collection within a Model so that Backbone effectively passed a JSON array to your REST endpoint.
Unfortunately, the answer didn’t provide a concrete example either so here is a stripped down version of what I ended up using.
Basically, “Language” is the “real” model which is managed by the “LanguageList” collection. Then, “LanguageCollection” is the container model which holds a single “LanguageList” collection and is subsequently managed by the “LanguageCollectionList”.
If you look through the code, basically the Views are bound to events on ‘LanguagesCollection.at(0).get(“languages”)’ which is a LanguageList object.
The other thing to note is that Language.destroy() function is updated to not make an AJAX DELETE call but instead trigger a save on the collection.
Also, LanguageCollection.parse() is defined as an empty function because ‘LanguagesCollection.at(0).get(“languages”)’ needs to remain a Backbone object and not be converted into the regular JSON which would come back from the server. The caveat here is that if you need to set an ID after a POST, you’ll need to update parse() to process the JSON and then update the corresponding models within the collection.
Anyway, I’m still a Backbone novice so any input or insight is more than welcome. I’d also love to know if theres a more straightforward way to address this. A couple of posts mentioned overriding Backbone.sync but that wasn’t feasible for me because I had other Backbone models on the page which needed to update using the regular REST pattern.
As pointed out by Aria below, it’s actually possible to override the “sync” method per model to achieve this JSON over REST behavior. Overall, its probably a cleaner solution since it avoids introducing the complexity of collections contained in models simply to get the JSON over REST behavior.
Here’s an example implementation of a sync function that produces the desired results:
NOTE: Almost all of that code is copied directly out of Backbone.js, the exception is the following block which collects up all the models in the current model’s collection and then adds it into the “data” field: