As I am currently starting my company (http://linads.com), some parts of the app I am building need to be highly dynamic. At the core of the app is a planning management that is pretty complex because it needs:
- To be active (users should be able to not only view the planning, but also create new bookings from there)
- To start from a yearly view (by month) but go into details at the daily level (showing all day of the years on one view is ugly and not usable, showing days within just one month is not enough as bookings might be longer than that)
- To show all current bids from customers on each possible item at any given time.
If you want something like this to be simple to use and browse through, you can’t show everything at once but need to let the user view more details where he needs to without ever leaving the page.
In this post I’ll try to explain how I use Symfony and a handful of JS libraries together to make this work.
Symfony and the templates
- Model: this will probably be similar to your symfony models
- View: controls a specific HTML element on the page
- Collection: a list of models
- Event: allows to create custom events on Models, Collections and Views.
Setting up backbone.js
First let’s see how to install Backbone. Backbone requires a few other JS libraries in order to work, and uses jQuery (or others) for DOM manipulation. So you need all those files. Personally I put them in /web/js/vendors/ directory. Requiring this many JS files will mean longer page loads, but but but… doesn’t Symfony2 come with an awesome tool called Assetic to help us with that? It does. Assetic can (among other things) help you combine all those files together for a production environment.
This goes in my base template layout. On a dev environment, each file is served as its own (though through a slightly different name). On a prod environment they’ll all be combined together. Also note it would be better to apply a filter here to use YUI compressor or Google Closure Compiler to minify the final script but I haven’t been able to make this work so far.
Also you can see that I use many JS libs. Most of them are required by Backbone. /plugins/* loads all the jQuery plugins I want. Then moment.js is something I need to deal with dates and time issues. ICanHaz.js will come in handy later, I’ll explain why.
I’m not gonna create a full backbone.js tutorial here, there’s more than one available around and I just want to focus on how I integrate all of these together and keep things organized inside a symfony2 project.
Say you have created your backbone models, views and collections as you need to. Usually you will have a model view and collection for each component and a general Application View that will define the global behavior of your app.
As an example, for booking my media, I could have the following media specific code:
As you see the main view should be initialized with some JSON data. The ‘initialize’ function is not the constructor but is called by the constructor. The constructor has saved the arguments under ‘this.options’. In this case, the constructor should be called with a JSON list of media. Each media will contain an id, a code, and a list of bookings. Then while instantiating a media, a list of bookings will be created in much the same way.
Feeding Backbone initial data
What you could do is just have this, and then use Backbone’s ajax capabilities to retrieve all the required data by calling the server again. However since we’re rendering the page once already, we can feed initial data at the same time.
This can be done while we render the symfony template by just adding this:
Here I render another template which returns all my needed data as JSON. I keep this in a separate controller as I might want to update this data from the client at some point and therefore need a real action / controller / url for this job.
That’s it, the initial data is there.
Some additional sweetness
I have a few issues with this:
- I don’t like to have half of my templates in Twig and half of them in some JS files
- JS can’t have multi-line strings and templates become impossible to read
There are many template engines for JS out there. There’s even an effort to reproduce Twig syntax for JS templates (I haven’t checked it yet).
In twig this goes like:
Perfect! And we’re almost done!
Keeping it organized
Very briefly to use modules, you start by creating a variable, your namespace that will contain all your code, and give it a method to return a module:
Then each of your module is defined in a self executing function:
That’s a good start, now let’s split our files and have them organized. I put all my JS in the bundle they’re related to:
Now that everything is more clear, a bit of assetic magic and we’ll be done:
It took me a little while to figure out how to make all these things. At first you don’t have the need to organize much, then your script gets bigger and you get lost as to where are your models / views etc…
I hope this helps some of you try it and not just for sample TODO list applications but real life apps!