Compressing and combining files with JavaScriptMVC

This is the third article on JavaScriptMVC, so if you’re interested in more these are my previous posts on the subject:

In these previous posts I’ve shown you the MVC capabilities of the framework, now I would like to look into its combining and compressing features. By now you should be familiar with the js.bat command file which comes with JavaScriptMVC. If this doesn’t ring a bell, please read my previous posts or go to the JavaScriptMVC website.

Justin, one of the co-authors of JavaScriptMVC, mentioned in the comments of my previous posts that reducing HTTP requests is the number one performance enhancement recommendation by the Yahoo performance team. They even have a list of best practices for speeding up your website. JavaScriptMVC can help you combining your javascript files, external files as well as files generated by the framework. It’s actually very easy to do. To reference your JavaScriptMVC project in your HTML page you use the following code:

<script language="javascript" type="text/javascript" src="../../jmvc/include.js?tab_manager,development"></script>

At this moment JavaScriptMVC is running in development mode, which means no combined files, no compressing. It loads up the files in your browser just as you created them. This can be easily checked with Firebug. Load up your page which references the javascript in Firefox and enable the Firebug Script tag. If you open up the list of script files you’ll get something like this:

Picture 1

All files should be in this list: controllers, external resources, … This comes in very handy when developing and debugging. But lots of different files are loaded so performance wise this is not the way to go. Fortunately we have JavaScriptMVC to help us. You can load the production version of your code by using the following HTML code:

<script language="javascript" type="text/javascript" src="../../jmvc/include.js?tab_manager,production"></script>

Notice that the ‘development’ parameter has been changed to ‘production’. That’s pretty easy huh? Now let’s reload the webpage in Firefox and see what the result is.

Picture 4

Quite a surprise! We went from twenty or more javascript file to only two files being loaded: index.js and production.js, both are provided by JavaScriptMVC. But how and when is the production.js file created? It is done manually using the js.bat command file once again. You can compress and combine all your files using this command:

js apps/{application_name}/compress.js

So if we take the example of the previous post, to generate the production file for our Tab Manager:

js apps/tab_manager/compress.js

This will combine and compress all your files referenced by JavaScriptMVC into the production.js file. Whether it’s a controller, a model or an external resource it doesn’t matter. Even jquery itself is combined into this file when referenced as a resource in your JavaScriptMVC application. It doesn’t matter if the original file already has been minified, this all just works.

As you can see the framework offers you a great way to enhance the performance of your web application without much effort.


The MVC in JavaScriptMVC

DISCLAIMER: I recently started using JavaScriptMVC and got to like it a lot. These blogposts are a way for me to document my learning process of the framework. There is the possibility that I misinterpreted certain principles or abusing the framework at some points. So don’t be afraid to ask questions or set things straight in the comments.

In my last post I outed my love for JavaScriptMVC. I got the remark of James that a library that consolidates javascript files doesn’t make it MVC and that is absolutely correct. But JavaScriptMVC is much more then just javascript file consolidation. In this post I would like to show the MVC capabilities of the JavaScript framework and how a typical application built with JavaScriptMVC is structured.

When you download the framework and unzip it to the folder of your choice you get the following file structure:

Picture 1

We will touch some of the folders and files in this structure. The js.bat is a very important one because we will be generating a lot of the files via this command file. As an exercise I will build a fairly simple tabbed interface using JavaScriptMVC. I’ve put the result of this tutoria online. The initial mockup of the application looks like this:

 Picture 2

Before we can start writing code, we have to create an application. You can do this by navigating in a command prompt to the folder where you unzipped the JavaScriptMVC bytes and executing the following command:

js jmvc\generate\app tab_manager

The batch command has generated a couple of application files. This batch file will also be used to generate models, controllers, views and much more. Before we go any further let’s digg into how JavaSciptMVC uses the MVC pattern. From their website we get the following explanation for models, views and controllers:

Model
wrap an application’s data layer, this is done in two ways:
- request data from and interacting with services.
- Wrap service data with a domain-specific representation

Controller
event delegation that helps logically organize your event handlers

View
Is used as a templating library, it builds html strings from JSON

While using the framework I took the liberty to use parts a little different. Controllers I use as defined for event delegation. But models I don’t use solely for requesting data from a service. I try to make my models as fat as possible and also do things like UI manipulation. Because I use JavaScriptMVC in combination with ASP.NET my usage of the View has been limited. I will be mainly speaking about the Models and Controllers given that my *.aspx (or *.ascx) page is my actual view.

When generating the application, JavaScriptMVC generated an index.html page for us which automatically includes the necessary javascript. We’ll be using that page to create our tab control. I changed the HTML a bit, this is the end result:

<html> <head></head> <script language="javascript" type="text/javascript" src="../../jmvc/include.js?tab_manager,development"></script> <style type="text/css"> li { border:solid 1px #000; float:left; margin-right:5px; padding:10px; } li.selected { background-color:#000; } li.selected a { color:#fff; } p, ul { margin:0; width:300px; } p { border:solid 1px #000; height:200px; padding:10px; } ul { list-style-type:none; height:41px; padding:0; width:300px; } </style> <body> <ul id="tab_manager"> <li class="selected"><a href="#tab-1">Tab 1</a></li> <li><a href="#tab-2">Tab 2</a></li> <li><a href="#tab-3">Tab 3</a></li> </ul> <p id="tab-1">Tab 1 selected</p> <p id="tab-2" style="display:none;">Tab 2 selected</p> <p id="tab-3" style="display:none;">Tab 3 selected</p> </body> </html>

Some basic CSS rules and HTML to represent the tabbed control. I think this code speaks for itself, let’s create the javascript that is needed to make this control work. In order to respond to events that occur we first need a controller that will do the event delegation. So we use the js.bat command batch to generate a controller, this is the command:

js jmvc/generate/controller tab_manager

In our controllers folder we now have a tab_manager_controller.js which we will use to hook into the events that occur on our html page. We can hook into different sort of events and all the important ones are supported. So in order to respond to a click on one of the tabs we add the following method to the controller.

TabManagerController = MVC.Controller.extend('tab_manager', /* @Static */ {}, /* @Prototype */ { 'li click': function(params) { new Tab().select(params.element); params.event.preventDefault(); } } );

Let’s reflect over this code. This code defines a TabManagerController class which controls an element that has the id ‘tab_manager’, the id that our ul-tag has. There is one function in the controller that will respond to a click event on a li-tag. Notice how they use CSS selectors to define the event handlers. No real rocket science here for anyone who already is familiar with JavaScript and CSS selectors. Now we could write all necessary code in the controller, but in order to keep my JavaScript code maintainable I would like to use the controllers as a delegation mechanism to my models. This is somewhat different from what the guys of JavaScriptMVC are recommending to use models for. I try to get my models to reflect the different concepts in my application. So we want to generate a Tab model to show and hide the different tabs. Again we use the batch we are already familiar with to generate the model:

js jmvc/generate/model ajax Tab

This will generate a Tab.js file under the models directory. Now we can add the necessary methods to this class in order to manipulate a certain tab. The nice thing about this is that it resides in its own class which has a name that reflects the actual UI object it will manipulate. You might have noticed the ‘ajax’ parameter we have provided. This is simply because a model has to be generated with a certain data type (json_p, ajax, xml_rest, …). We will not be using one of the types in our code so this can be ignored for now. This is how the implementation of the Tab model looks like:

/** * */ Tab = MVC.Model.Ajax.extend('Tab', /* @Static */ { }, /* @Prototype */ { getTabContentSelector: function($tab) { return $tab.find('a').attr('href'); }, hideTabContent: function(selector) { $(selector).css('display', 'none'); }, showTabContent: function(selector) { $(selector).css('display', 'block'); }, select: function(tabToShow) { var $currentSelectedTab = $('li.selected'); this.hideTabContent(this.getTabContentSelector($currentSelectedTab)); $currentSelectedTab.removeClass('selected'); var $tabToShow = $(tabToShow); $tabToShow.addClass('selected'); this.showTabContent(this.getTabContentSelector($tabToShow)); } } );

Notice that I use jQuery in the mix. jQuery and JavaScriptMVC are actually very compatible. You do have to include jQuery as a resource in order to be able to use it, more on that later. There are four functions in the Tab model, the most imporant one is the select function which takes a tab (which is actually an li-element) as argument. The content to show is currently hidden in the page, each tab has a corresponding p-tag which holds the data for that tab, but this could be replaced by an Ajax call in order to request some data for a specific tab.

The last thing I have to mention is the tab_manager.js file in the app folder. That file looks like this:

include.resources('jquery-1.3.2.min'); include.engines(); include.plugins( 'controller','controller/scaffold', 'view','view/helpers', 'dom/element', 'io/ajax', 'model/json_rest','model/xml_rest' ); include(function(){ //runs after prior includes are loaded include.models('Tab'); include.controllers('tab_manager'); include.views(); });

This is actually the main file of our application which determines what resources, plugins, models and controllers are loaded. As you can see the jquery file, the tab_manager controller and the Tab model are present in this file. Don’t forget to add new models and controllers to this file, otherwise they will not be loaded and executed.

Because this post is already rather lengthy I will leave it here and give you some room to expirement with the code. I know there are a lot of concepts that are left unexplained but I’m planning on writing a few more posts to go into further detail into certain concepts of the framework. As always if you have any remarks the comments are still open and free.

To finish would like to end with a brief overview  of the important files and folders so you have a nice overview of where to find everything we used in this tutorial.

apps tab_manager.js general application file to load models, controllers and resources index.html file which holds the necessary html code, used for testing purposes controllers tab_manager_controller.js controller which responds on events coming from the tab manager models Tab.js model which represent a tab resources jquery-1.3.2.min.js jquery file

Source code of this article
Result of this tutorial

Tags from Technorati: ,


Book review: jQuery in Action

jQuery-in-Action I started reading this book about 6 months ago. After reading it half way through I stopped and start reading a newly purchased book. The reason that I stopped reading was because I was excited and impatient to start reading the new book, it's a problem I have every time I purchase a new book. After finishing some books I realized that jQuery in Action was still lying around, and because the new project I'm working on depends heavily on jQuery, I decided to pick up the book where I left off and finish it.

If you use jQuery in your day job or you are interested in JavaScript development in general this book is really for you. I read this book after several months of jQuery development experience and still learned a lot about the framework.

The authors of the book recommend reading the appendices first before getting into the real stuff. They are a very good start for people who are not that familiar with JavaScript and get you up to speed on some essentials of the language like the JavaScript Object and how functions and closures work. These concepts are explained in a very clear way.

After the appendices you dive right into the jQuery goodness with the explanation of the pure basics. Selectors are a very important part which is handled in detail. Via events, animations and effects they show the basic utility functions that are built-in in jQuery. Although the whole book is a very interesting read chapter 7 really pops out and shows how you can write your own plugins, which can result in a lot of code reuse when used properly. The book is finished with how to do Ajax calls with jQuery and some of the best jQuery plugins.

I think it's quite clear by now that this book is a good read for all levels: beginner, intermediate and advanced. I've learned a lot about jQuery that made my job a lot easier. And I think that's the reason why we read technical books, broaden your horizon and learn how to use framework and tools more efficient. The authors certainly succeeded with this book.

To close I would like to list my 5 favorites things I learned or learned more about while reading the book:

  • Selectors, although I already knew a bunch about supported selectors I learned some new ones that I didn't know of
  • animate() that enables you to create your own custom animations and gives you endless possibilities
  • $.grep() can be used to filter arrays
  • $.post, $.get, $.ajax, ... all the different features in jQuery that support ajax calls to the server and a reference of all the different options.
  • Live Query plugin, which can monitor if certain events occur on elements which match a certain selector. The good thing about this plugin is when adding new items to the page that match the selector, you don't have to bind the events for this new item. The plugin takes care of that.
Tags from Technorati: ,,

Sequentially download multiple files (with jQuery)

On my previous job, I was working together with a colleague on a file transfer application which lived in the browser. We were up -and downloading multiple files at the same time and needed a rich user experience. To ensure the best experience when uploading we turned to swfupload, it's free and I highly recommend it. But download was another story. The user experience for downloading files is actually something for which we entirely depend on the browser. It's not that there is a lot of choice. You click a link to a file which the browser can't open then you get a save dialog box and the browser shows you a progress bar. All that is out of the hands of the developer you just put the link there or stream the file directly to the client and let the browser do his thing.

But we offered the user multiple files and he could determine which files he wanted to download. This is a simplified mockup of how the screen looked.

image

If a user wanted to download the files he could click the links one by one and then save them. But how to make the "Download selected files" button work. After some googling I found that there are numerous solutions for upload but didn't find any decent solution for a 'richer' download experience. And after thinking it through it makes sense, because downloading requires access to the hard disk of the user. This would be a serious risk to allow javascript to write to a certain folder on disk.

So we were stuck, some suggested of zipping all the zips to one file but we didn't want to burden the end user with the extra effort of unzipping.  I got a hint on a forum post (can't remember which one sorry for that) that if you pointed the source attribute of an iframe to the file the browser would offer it as a download. So the first attempt to to this was with the following HTML code:

<html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <script src="j/jquery.js" type="text/javascript"></script> <script src="j/index.js" type="text/javascript"></script> </head> <body> <h1>Download files</h1> <iframe src="" id="download-iframe" style="display:none;" /> </body> </html>

And the following JavaScript was executed when the document was loaded.

$(function() { $('#download-iframe').attr('src', 'file1.zip'); $('#download-iframe').attr('src', 'file2.zip'); $('#download-iframe').attr('src', 'file3.zip'); });

You can see I'm using some jQuery magic. If you haven't used it yet, stop reading and go check it out. Did I already mention I'm a fan?

But there is a problem with the code. Only the last file is offered as download. I guessed, I'm not 100 % sure and please correct me if I'm wrong, that the problem was that the statements were executed directly after each other. So I used a little timeout to see if that was the solution to our problem, like so:

$(function() { var fileIndex = 0; var fileArray = [ 'file1.zip', 'file2.zip', 'file3.zip' ]; $('#download-iframe').attr('src', fileArray[fileIndex]); fileIndex++; var interval = setInterval(function() { if(fileIndex < fileArray.length) { $('#download-iframe').attr('src', fileArray[fileIndex]); fileIndex++; } else { clearInterval(interval); } }, 100); });

As you can see the code is not that much longer, I now have an array of the filenames (could be extracted from a list of checkboxes) and offer the first file as download. Then I set an interval that fires every 100 milliseconds which offers the next file as a download. Once all files have been handled, the interval is cleared and we're done.

Now the user gets prompted with 3 download dialog boxes. I know, it sucks that he still has to click three times to save each download individually. But if the user sets a default download location the files are automatically saved to that location and he doesn't have to click for each file that gets downloaded. It's certainly not perfect and from a user experience standpoint it still kinda sucks ... but it works. If you have another idea of solving this problem, please feel free to elaborate in the comments.

Tags from Technorati: ,,