<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Christophe Coenraets &#187; Twitter Bootstrap</title>
	<atom:link href="http://coenraets.org/blog/category/twitter-bootstrap/feed/" rel="self" type="application/rss+xml" />
	<link>http://coenraets.org/blog</link>
	<description>Web Platform, Cloud and Mobile Application Development</description>
	<lastBuildDate>Mon, 13 May 2013 16:05:20 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Sample Application with Backbone.js and Twitter Bootstrap: Updated and Improved</title>
		<link>http://coenraets.org/blog/2013/04/sample-application-with-backbone-js-and-twitter-bootstrap-updated-and-improved/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=sample-application-with-backbone-js-and-twitter-bootstrap-updated-and-improved</link>
		<comments>http://coenraets.org/blog/2013/04/sample-application-with-backbone-js-and-twitter-bootstrap-updated-and-improved/#comments</comments>
		<pubDate>Wed, 17 Apr 2013 15:27:49 +0000</pubDate>
		<dc:creator>Christophe Coenraets</dc:creator>
				<category><![CDATA[Backbone.js]]></category>
		<category><![CDATA[Twitter Bootstrap]]></category>

		<guid isPermaLink="false">http://coenraets.org/blog/?p=5183</guid>
		<description><![CDATA[A year ago, I blogged Employee Directory, a sample application that demonstrates how to build modern web apps with Backbone.js and Twitter Bootstrap. With 1200+ stars and 300+ forks on GitHub, it has been my most popular sample application to date. Because of the continued interest in the application as a starting point and a [...]]]></description>
				<content:encoded><![CDATA[<p><a href="http://coenraets.org/directory/"><img src="http://coenraets.org/blog/wp-content/uploads/2013/04/directory-screenshot3.gif" alt="" title="directory-screenshot3" width="640" height="554" class="alignleft size-full wp-image-5422" /></a></p>
<p>A year ago, I blogged <a href="http://coenraets.org/blog/2012/02/sample-app-with-backbone-js-and-twitter-bootstrap/">Employee Directory</a>, a sample application that demonstrates how to build modern web apps with <a href="http://backbonejs.org/">Backbone.js</a> and <a href="http://twitter.github.io/bootstrap/">Twitter Bootstrap</a>. With 1200+ stars and 300+ forks on GitHub, it has been my most popular sample application to date. </p>
<p>Because of the continued interest in the application as a starting point and a reference for Backbone.js and Twitter Bootstrap, I decided to give it a well deserved update.</p>
<p>New in this version:</p>
<ul>
<li>Latest version of Backbone.js (1.0)</li>
<li>Latest version of Twitter Bootstrap (2.3.1)</li>
<li>Layout is now responsive</li>
<li>Data persistence layer is now abstracted (see below)</li>
<li>Additional data persistence options: In-memory datastore, Node.js/MongoDB, Parse.com (In addition to PHP and Java)</li>
<li>New GitHub repository organization (see below)</li>
<li>Bug fixes and cleaner code</li>
</ul>
<h3>Running the Application</h3>
<p>You can test the hosted version of the application <a href="http://coenraets.org/directory/">here</a>, or you can download the code (see GitHub repository information below) and test the application locally.</p>
<h3>Data Persistence Abstraction</h3>
<p>Among the great feedback I received, a number of you mentioned you wanted a self-contained version of the app with no dependency on a specific back end to be able to &#8220;download and run&#8221; without having to set up a server and a database. So I rearchitected the persistence layer with simple and pluggable data adapters. By default the application now uses an in-memory data store, but other adapters are available. To change the data persistence strategy, just comment out model-in-memory.js in index.html and uncomment one of the other data adapters using the table below as a reference.</p>
<p>I initially published the application with two implementations of a RESTful back end: A Java version using Jersey, and a PHP version using Slim.  A year later, I&#8217;m adding the long overdue Node.js/MongoDB back end.</p>
<table>
<tr style="font-weight:bold;">
<td>Adapter</td>
<td>Description</td>
<td>Back end Repo</td>
</tr>
<tr>
<td style="width:140px">model-in-memory.js</td>
<td>In-memory data store</td>
<td style="width:170px">No server required</td>
</tr>
<tr>
<td>model-rest-json.js</td>
<td>Backbone.js default behavior. The application gets data through RESTFul services.</td>
<td><a href="https://github.com/ccoenraets/directory-rest-nodejs">directory-server-nodejs</a><br/><br />
<a href="https://github.com/ccoenraets/directory-rest-php">directory-server-php</a><br/><br />
directory-server-java
</td>
</tr>
<tr>
<td>model-rest-jsonp.js</td>
<td>If the server serving your pages and the server serving your data are on different domains, use this adapter instead to avoid the same origin policy error.</td>
<td><a href="https://github.com/ccoenraets/directory-rest-nodejs">directory-server-nodejs</a><br/><br />
<a href="https://github.com/ccoenraets/directory-rest-php">directory-server-php</a><br/><br />
directory-server-java
</td>
</tr>
<tr>
<td>model-websql.js</td>
<td>Uses local database using the WebSQL api.</td>
<td>No server required</td>
</tr>
<tr>
<td>model-parse-dot-com.js</td>
<td>Don&#8217;t want to host your own data infrastructure? Parse.com is a cloud service that will host your data for you. Use this adapter to test your app with  sample data I deployed on Parse.com.</td>
<td>No server required</td>
</tr>
</table>
<p>The Node.js, Java, and PHP RESTful back ends work with both JSON and JSONP. If the request includes a query parameter named &#8220;callback&#8221;, a JSONP response is returned, otherwise, a regular JSON response is returned.</p>
<h3>New GitHub Repositories</h3>
<p>The original repository (<a href="https://github.com/ccoenraets/backbone-directory">backbone-directory</a>) grew somewhat chaotically as I kept adding different versions and different data persistence options. So I decided to start fresh with new repositories.</p>
<p>The client code for the application is available in the new <a href="https://github.com/ccoenraets/directory-backbone-bootstrap">directory-backbone-bootstrap</a> repository. In the future, this new repository naming scheme will allow me to add different versions of the app (for example, directory-backbone-foundation or directory-angular-bootstrap)  while keeping each repository clean and focused. </p>
<div class="woo-sc-box note   ">
Because the templates of this application are loaded using XMLHTTPRequest, you will get a cross domain error (Access-Control-Allow-Origin) if you load index.html from the file system (with the file:// protocol). Make sure you load the application from a web server. For example: http://localhost/directory-backbone-bootstrap.<br />
</div>
<p>If you want to go beyond the in-memory datastore, you can download the REST services in the following repositories:</p>
<p><a href="https://github.com/ccoenraets/directory-rest-nodejs">directory-rest-nodejs</a> (Node.js/MongoDB implementation)<br />
<a href="https://github.com/ccoenraets/directory-rest-php">directory-rest-php</a> (PHP implementation)<br />
directory-rest-java (Java implementation coming soon)</p>
]]></content:encoded>
			<wfw:commentRss>http://coenraets.org/blog/2013/04/sample-application-with-backbone-js-and-twitter-bootstrap-updated-and-improved/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>NodeCellar: Sample Application with Backbone.js, Twitter Bootstrap, Node.js, Express, and MongoDB</title>
		<link>http://coenraets.org/blog/2012/10/nodecellar-sample-application-with-backbone-js-twitter-bootstrap-node-js-express-and-mongodb/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=nodecellar-sample-application-with-backbone-js-twitter-bootstrap-node-js-express-and-mongodb</link>
		<comments>http://coenraets.org/blog/2012/10/nodecellar-sample-application-with-backbone-js-twitter-bootstrap-node-js-express-and-mongodb/#comments</comments>
		<pubDate>Thu, 04 Oct 2012 15:39:03 +0000</pubDate>
		<dc:creator>Christophe Coenraets</dc:creator>
				<category><![CDATA[Backbone.js]]></category>
		<category><![CDATA[Express]]></category>
		<category><![CDATA[HTML 5]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[Node.js]]></category>
		<category><![CDATA[Twitter Bootstrap]]></category>

		<guid isPermaLink="false">http://coenraets.org/blog/?p=4183</guid>
		<description><![CDATA[In my previous post, I shared my recent experience building a RESTful API with Node.js, MongoDB, and Express. In this post, I&#8217;m sharing the client application that uses that RESTful API. The Node Cellar application allows you to manage (retrieve, create, update, delete) the wines in a wine cellar database. The client application is built [...]]]></description>
				<content:encoded><![CDATA[<p><a href="http://nodecellar.coenraets.org"><img src="http://coenraets.org/blog/wp-content/uploads/2012/10/nodecellar.gif" alt="" title="nodecellar" width="640" height="463" class="aligncenter size-full wp-image-4197" /></a></p>
<p>In my <a href="http://coenraets.org/blog/2012/10/creating-a-rest-api-using-node-js-express-and-mongodb/">previous post</a>, I shared my recent experience building a RESTful API with <a href="http://nodejs.org">Node.js</a>, <a href="http://www.mongodb.org/">MongoDB</a>, and <a href="http://expressjs.com/">Express</a>.</p>
<p>In this post, I&#8217;m sharing the client application that uses that RESTful API. The Node Cellar application allows you to manage (retrieve, create, update, delete) the wines in a wine cellar database.<br />
<span id="more-4183"></span><br />
The client application is built with <a href="http://backbonejs.org/">Backbone.js</a> and <a href="http://twitter.github.com/bootstrap/">Twitter Bootstrap</a>.</p>
<h4>Run the Application</h4>
<p>You can run the application <a href="http://nodecellar.coenraets.org">here</a>. For obvious reasons, the create, update, delete features have been disabled in this hosted version. </p>
<p>NOTE: <span style="text-decoration: line-through;">Node.js is running on port 3000 on my EC2 Instance.</span> My friend <a href="http://www.jamesward.com/">James Ward</a> convinced me to host the application on their service over at Heroku. It&#8217;s now running on port 80 at <a href="http://nodecellar.coenraets.org">http://nodecellar.coenraets.org</a>. Thanks James!</p>
<p><a href="http://nodecellar.coenraets.org"><img src="http://coenraets.org/blog/wp-content/uploads/2012/10/nodecellar2.gif" alt="" title="nodecellar2" width="640" height="463" class="aligncenter size-full wp-image-4203" /></a></p>
<h4>Server-Side</h4>
<p>The details of the Node.js, MongoDB, and Express implementation are documented in my <a href="http://coenraets.org/blog/2012/10/creating-a-rest-api-using-node-js-express-and-mongodb/">previous post</a>.</p>
<h4>Client-Side</h4>
<p>In this application, Node.js is used to provide the RESTful services that the client application needs to manipulate the data. Node.js is not used to generate HTML/Views at the server-side. Instead, the Views are created dynamically at the client-side using Backbone.js and Underscore.js templates. They are injected into- and removed from the DOM as needed as you navigate through the application. Node Cellar is a &#8220;single page application&#8221;.</p>
<p>This is a Node.js and MongoDB powered version of an application I initially posted <a href="http://coenraets.org/blog/2012/05/single-page-crud-application-with-backbone-js-and-twitter-bootstrap/">here</a> with PHP and Java backends. The original post provides some additional Backbone.js context. This Node.js version also provides an improved user experience with the latest version of Twitter Bootstrap (2.1.1), and a <a href="http://twitter.github.com/bootstrap/scaffolding.html#responsive">responsive</a> layout. It also uses <a href="http://html.adobe.com/edge/webfonts/">Adobe Edge Web Fonts</a>.</p>
<h4>Source Code</h4>
<p>The source code is available in <a href="https://github.com/ccoenraets/nodecellar">this repository</a> on GitHub.</p>
<p><a href="http://nodecellar.coenraets.org"><img src="http://coenraets.org/blog/wp-content/uploads/2012/10/nodecellar3.gif" alt="" title="nodecellar3" width="640" height="463" class="aligncenter size-full wp-image-4204" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://coenraets.org/blog/2012/10/nodecellar-sample-application-with-backbone-js-twitter-bootstrap-node-js-express-and-mongodb/feed/</wfw:commentRss>
		<slash:comments>72</slash:comments>
		</item>
		<item>
		<title>Simple Offline Data Synchronization for Mobile Web and PhoneGap Applications</title>
		<link>http://coenraets.org/blog/2012/05/simple-offline-data-synchronization-for-mobile-web-and-phonegap-applications/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=simple-offline-data-synchronization-for-mobile-web-and-phonegap-applications</link>
		<comments>http://coenraets.org/blog/2012/05/simple-offline-data-synchronization-for-mobile-web-and-phonegap-applications/#comments</comments>
		<pubDate>Wed, 16 May 2012 19:36:45 +0000</pubDate>
		<dc:creator>Christophe Coenraets</dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[Backbone.js]]></category>
		<category><![CDATA[HTML 5]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[PhoneGap]]></category>
		<category><![CDATA[Twitter Bootstrap]]></category>

		<guid isPermaLink="false">http://coenraets.org/blog/?p=3652</guid>
		<description><![CDATA[Being able to work offline is an expected feature of mobile applications. For data-driven applications, it means that you &#8212; the developer &#8212; will have to store (a subset of) your application data locally, and implement a data synchronization mechanism that keeps your local and server data in sync. In this article, I describe a [...]]]></description>
				<content:encoded><![CDATA[<p>Being able to work offline is an expected feature of mobile applications. For data-driven applications, it means that you &#8212; the developer &#8212; will have to store (a subset of) your application data locally, and implement a data synchronization mechanism that keeps your local and server data in sync.</p>
<p>In this article, I describe a simple data synchronization strategy that uses the device&#8217;s (or browser&#8217;s) SQLite database. The implementation currently leverages the Web SQL API (even though the W3C is no longer actively maintaining the spec) because both iOS and Android support it, but they don&#8217;t support IndexedDB, the official alternative. However, the API described below &#8212; getLastSync(), getChanges(), applyChanges() &#8212; defines a generic synchronization contract, and the solution can be expanded and made &#8220;pluggable&#8221;: You could create different synchronization objects, each providing a different implementation of these methods. You could then choose which object to plug in based on the context and the platform your application is running on.</p>
<h3>Try it in the Playground</h3>
<p><a href="http://coenraets.org/offline-sync/client-app"><img src="http://coenraets.org/blog/wp-content/uploads/2012/05/Screen-Shot-2012-05-16-at-21.jpg" alt="" title="Screen Shot 2012-05-16 at 2" width="640" height="760" class="aligncenter size-full wp-image-3734" /></a><br />
<span id="more-3652"></span><br />
Before looking at the code, you can try some offline syncing in this a hosted playground:</p>
<ol>
<li>Open the <a href="http://coenraets.org/offline-sync/client-app">Offline Client Playground</a> in Chrome or Safari (they both support Web SQL).</li>
<li>Click the Synchronize button.</li>
<li>Look at the log (the textarea in the middle of the screen): Because it&#8217;s the first time you use the application, all the employees have been downloaded from the server and inserted in your local SQLite database.</li>
<li>Clear the log, click the Synchronize button, and look at the log again: because you now have an up-to-date local version of the data, the server didn&#8217;t return any change and your local database remains unchanged.</li>
<li>In another tab, open the <a href="http://coenraets.org/offline-sync/server-app">Server Admin PlayGround</a>.</li>
<li>Modify an existing employee and click Save. (Don&#8217;t worry, it&#8217;s using your own session-based data set).</li>
<li>Go back to the Offline Client tab, click Synchronize, and notice that the server returned one change,  and that it was applied to your local database.</li>
<li>Go back to the Server Admin tab and modify (create, update, delete) other employees. Switch back to the Offline Client tab, click Synchronize, and see how these changes are applied to your local database.</li>
<li>You can also use the Resources Tab in the Chrome Developer Tools to inspect your local database.</li>
</ol>
<h3>Server API</h3>
<p>The only piece of infrastructure you need at the server side is an API that returns the items that have changed (created, updated, or deleted) since a specific moment in time expressed as a timestamp. </p>
<p>Here is the RESTful API call used in my application:</p>
<p><a href="http://coenraets.org/offline-sync/api/employees?modifiedSince=2012-03-01 10:20:56">http://coenraets.org/offline-sync/api/employees?modifiedSince=2012-03-01 10:20:56</a></p>
<p>The format of the data returned by the server is up to you and is part of the contract between the client and the server. In this application, the server returns the changes as an array of JSON objects. The server-side technology (RoR, PHP, Java, .NET, &#8230;) and database system (SQL, NoSQL, &#8230;) you use to generate the list of changes is also totally up to you. I provide a simple PHP implementation as part of the source code. That implementation manages a session-based data set that provides an isolated and transient playground. In a real-life application, you&#8217;d obviously get the data from some sort of database.</p>
<h3>Client API</h3>
<p>At the client side, our synchronization API consists of three methods.</p>
<h4>getLastSync()</h4>
<p>A method that returns a timestamp to be used as the query parameter for the next synchronization request. A common practice is to persist a timestamp after each synchronization request. But things can go wrong and the timestamp itself can get out-of-sync. I prefer to &#8220;recalculate&#8221; the lastSync timestamp before each synchronization request.   </p>
<pre class="brush: jscript; title: ; notranslate">
getLastSync: function(callback) {
    this.db.transaction(
        function(tx) {
            var sql = &quot;SELECT MAX(lastModified) as lastSync FROM employee&quot;;
            tx.executeSql(sql, this.txErrorHandler,
                function(tx, results) {
                    var lastSync = results.rows.item(0).lastSync;
                    callback(lastSync);
                }
            );
        }
    );
}
</pre>
<h4>getChanges()</h4>
<p>This is a wrapper around an Ajax call to the server-side API that returns the items that have changed (created, updated, or deleted) since a specific moment in time defined in the modifiedSince parameter. </p>
<pre class="brush: jscript; title: ; notranslate">
getChanges: function(syncURL, modifiedSince, callback) {

    $.ajax({
        url: syncURL,
        data: {modifiedSince: modifiedSince},
        dataType:&quot;json&quot;,
        success:function (changes) {
            callback(changes);
        },
        error: function(model, response) {
            alert(response.responseText);
        }
    });

}
</pre>
<h4>applyChanges()</h4>
<p>A method that persists the changes in your local data store. Notice that SQLite supports a convenient &#8220;INSERT OR REPLACE&#8221; statement so that you don&#8217;t have to determine if you are dealing with a new or existing employee before persisting it.</p>
<pre class="brush: jscript; title: ; notranslate">
applyChanges: function(employees, callback) {
    this.db.transaction(
        function(tx) {
            var l = employees.length;
            var sql =
                &quot;INSERT OR REPLACE INTO employee (id, firstName, lastName, title, officePhone, deleted, lastModified) &quot; +
                &quot;VALUES (?, ?, ?, ?, ?, ?, ?)&quot;;
            var e;
            for (var i = 0; i &lt; l; i++) {
                e = employees[i];
                var params = [e.id, e.firstName, e.lastName, e.title, e.officePhone, e.deleted, e.lastModified];
                tx.executeSql(sql, params);
            }
        },
        this.txErrorHandler,
        function(tx) {
            callback();
        }
    );
}
</pre>
<h3>Synchronization Logic</h3>
<p>With these server and client APIs in place, you can choreograph a data synchronization process as follows: </p>
<pre class="brush: jscript; title: ; notranslate">
sync: function(syncURL, callback) {

    var self = this;
    this.getLastSync(function(lastSync){
        self.getChanges(syncURL, lastSync,
            function (changes) {
                self.applyChanges(changes, callback);
            }
        );
    });

}
</pre>
<h3>Final Notes</h3>
<ul>
<li>This solution currently supports unidirectional (server to client) data synchronization. It could easily be expanded to support bidirectional synchronization.</li>
<li>This solution currently implements &#8220;logical deletes&#8221;: items are not physically deleted from the table, but the value of their &#8220;deleted&#8221; column is set to true.</li>
<li>As mentioned above, you could replace the Web SQL implementation with another data access strategy. For example, take a look at <a href="http://brian.io/lawnchair/">Brian Leroux&#8217; Lawnchair</a> for another local persistence solution.</li>
</ul>
<h3>Source Code</h3>
<p>The source code is available in <a href="https://github.com/ccoenraets/offline-sync">this GitHub repository</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://coenraets.org/blog/2012/05/simple-offline-data-synchronization-for-mobile-web-and-phonegap-applications/feed/</wfw:commentRss>
		<slash:comments>37</slash:comments>
		</item>
		<item>
		<title>Single-Page CRUD Application with Backbone.js and Twitter Bootstrap</title>
		<link>http://coenraets.org/blog/2012/05/single-page-crud-application-with-backbone-js-and-twitter-bootstrap/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=single-page-crud-application-with-backbone-js-and-twitter-bootstrap</link>
		<comments>http://coenraets.org/blog/2012/05/single-page-crud-application-with-backbone-js-and-twitter-bootstrap/#comments</comments>
		<pubDate>Thu, 03 May 2012 14:23:34 +0000</pubDate>
		<dc:creator>Christophe Coenraets</dc:creator>
				<category><![CDATA[Backbone.js]]></category>
		<category><![CDATA[JQuery]]></category>
		<category><![CDATA[Twitter Bootstrap]]></category>

		<guid isPermaLink="false">http://coenraets.org/blog/?p=3575</guid>
		<description><![CDATA[A few weeks weeks ago, I posted a first Backbone.js and Twitter Bootstrap sample application. While interesting, &#8220;Employee Directory&#8221; is a read-only application. As such, it doesn’t show off the full power of Backbone&#8217;s models or the coolness of some of Bootstrap&#8217;s data entry features such as forms, validation, etc. To demonstrate these features, I [...]]]></description>
				<content:encoded><![CDATA[<p>A few weeks weeks ago, I <a href="http://coenraets.org/blog/2012/02/sample-app-with-backbone-js-and-twitter-bootstrap/">posted</a> a first <a href="http://documentcloud.github.com/backbone/">Backbone.js</a> and <a href="http://twitter.github.com/bootstrap/">Twitter Bootstrap</a> sample application. While interesting, &#8220;Employee Directory&#8221; is a read-only application. As such, it doesn’t show off the full power of Backbone&#8217;s models or the coolness of some of Bootstrap&#8217;s data entry features such as forms, validation, etc.</p>
<p>To demonstrate these features, I decided to revisit my <a href="http://coenraets.org/blog/2011/12/backbone-js-wine-cellar-tutorial-part-1-getting-started/">wine cellar application</a>, which was in need of a serious UI makeover.</p>
<p>You can run the application <a href="http://coenraets.org/backbone-cellar/bootstrap">here</a>.</p>
<p><a href="http://coenraets.org/backbone-cellar/bootstrap"><img src="http://coenraets.org/blog/wp-content/uploads/2012/05/cellar012.jpg" alt="" width="640" height="553" class="aligncenter size-full wp-image-3600" /></a></p>
<p><a href="http://coenraets.org/backbone-cellar/bootstrap"><img src="http://coenraets.org/blog/wp-content/uploads/2012/05/cellar021.jpg" alt="" title="cellar02" width="640" height="584"  class="aligncenter size-full wp-image-3603" /></a><br />
<span id="more-3575"></span><br />
This online version uses an in-memory datastore: all your changes will be lost the next time you start the application or hit your browser’s refresh button. The image upload feature is also disabled, but you can still drag an image from your file system and drop it  in the Wine Form, which is pretty cool (see the note about browser support below). The <a href="https://github.com/ccoenraets/backbone-cellar">source code</a> available on GitHub includes a persistent back-end (in addition to the in-memory datastore), and a fully functional implementation of the file upload feature.</p>
<h3>Code Highlights</h3>
<h4>Template Loader</h4>
<p>This application features a template loader that now uses jQuery “deferreds” to load the HTML templates more efficiently.</p>
<h4>Drag-and-Drop File Upload and HTML 5 File API</h4>
<p>To upload an image file for a Wine, drag a file from your file system and drop it in the image box inside the Wine Form: The image is automatically displayed inside the img tag. This is done using the HTML 5 File API and doesn’t require a server roundtrip. </p>
<p>NOTE: This feature only works in Chrome at this time. I will implement an alternative implementation in a future version of the application to provide a consistent behavior across browsers.</p>
<p>The image is uploaded to the server using Ajax (XHR) when you save the form: no page refresh or iframe hack.</p>
<p><h>Paging</h4>
<p>Twitter Bootstrap provides easy markup and styles to create paginated lists. In this application, the Bootstrap markup and styles are “componentized” or “widgetized” into a Backbone View (Paginator), which adds the appropriate pagination behavior.</p>
<p>NOTE: In the current implementation of this application, the entire data set is always retrieved from the server and paging is provided for a cosmetic/layout reason. You could easily replace this implementation with a true paging strategy where pages are lazy-loaded from the server as needed.</p>
<h4>Forms</h4>
<p>Backbone Cellar also uses Twitter Bootstrap’s forms, which greatly help with form layouts (see WineView). </p>
<h4>Validation</h4>
<p>Twitter Bootstrap also provides simple markup and styles to highlight validation errors in forms. In Backbone Cellar, Bootstrap’s validation markup and styles are wired with validation rules defined in the Backbone model. Note that at this time, the application doesn’t use the Backbone model’s default validate() method, but custom validateItem() and validateAll() methods instead. </p>
<p>The application also uses other Twitter Bootstrap features including thumbnails, dropdowns, alerts, etc.</p>
<h3>Source Code</h3>
<p>The source code is available in the <a href="https://github.com/ccoenraets/backbone-cellar/bootstrap">bootstrap</a> folder of the <a href="https://github.com/ccoenraets/backbone-cellar">backbone-cellar</a> repository on GitHub.</p>
<h3>Disclaimer</h3>
<p>This is a sample application, not a production application. Some trade-offs were made to keep the code generic, simple and readable. In a real-life application, you should consider implementing a namespacing scheme to keep the global namespace clean, and other optimization techniques such as view and/or data caching.</p>
]]></content:encoded>
			<wfw:commentRss>http://coenraets.org/blog/2012/05/single-page-crud-application-with-backbone-js-and-twitter-bootstrap/feed/</wfw:commentRss>
		<slash:comments>36</slash:comments>
		</item>
		<item>
		<title>Sample App with Backbone.js and Twitter Bootstrap</title>
		<link>http://coenraets.org/blog/2012/02/sample-app-with-backbone-js-and-twitter-bootstrap/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=sample-app-with-backbone-js-and-twitter-bootstrap</link>
		<comments>http://coenraets.org/blog/2012/02/sample-app-with-backbone-js-and-twitter-bootstrap/#comments</comments>
		<pubDate>Mon, 13 Feb 2012 18:51:18 +0000</pubDate>
		<dc:creator>Christophe Coenraets</dc:creator>
				<category><![CDATA[Backbone.js]]></category>
		<category><![CDATA[HTML 5]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Twitter Bootstrap]]></category>

		<guid isPermaLink="false">http://coenraets.org/blog/?p=3125</guid>
		<description><![CDATA[Backbone.js is a lightweight JavaScript framework that provides the basic infrastructure (Model, Collection, View, and Router classes) to bring structure to your Web applications. Twitter Bootstrap is a UI toolkit that provides simple and flexible HTML, CSS, and Javascript to implement popular user interface components and interactions. In other words, Backbone.js and Twitter Bootstrap focus [...]]]></description>
				<content:encoded><![CDATA[<p><a href="http://documentcloud.github.com/backbone/">Backbone.js</a> is a lightweight JavaScript framework that provides the basic infrastructure (Model, Collection, View, and Router classes) to bring structure to your Web applications. </p>
<p><a href="http://twitter.github.com/bootstrap/index.html">Twitter Bootstrap</a> is a UI toolkit that provides simple and flexible HTML, CSS, and Javascript to implement popular user interface components and interactions.   </p>
<p>In other words, Backbone.js and Twitter Bootstrap focus on different areas of your application: core architecture and user interface respectively. Because of their well-defined and non-overlapping scope, Backbone.js and Twitter Bootstrap work well together. In general, I find a lightweight architectural framework and a UI toolkit to be a powerful combination, and an interesting alternative to full-stack frameworks: it gives you the flexibility to choose the library you like (if any) in the respective areas of your application.</p>
<h3>The Sample Application</h3>
<p>To give this combination a try, I put together a new sample application that uses Backbone.js to organize the code, and Twitter Bootstrap to organize the UI. The application is an Employee Directory that allows you to look for employees by name, view the details of an employee, and navigate up and down the Org Chart by clicking the employee&#8217;s manager or any of his/her direct reports.</p>
<p>You can run the application <a href="http://coenraets.org/directory">here</a>.</p>
<p><a href="http://coenraets.org/blog/wp-content/uploads/2012/02/directory1.gif"><img src="http://coenraets.org/blog/wp-content/uploads/2012/02/directory1.gif" alt="" title="directory1" width="640" height="526" class="aligncenter size-full wp-image-3197" /></a></p>
<p><a href="http://coenraets.org/blog/wp-content/uploads/2012/02/directory2.gif"><img src="http://coenraets.org/blog/wp-content/uploads/2012/02/directory2.gif" alt="" title="directory2" width="640" height="526" class="aligncenter size-full wp-image-3200" /></a><br />
<span id="more-3125"></span><br />
Backbone Directory is a single page application: index.html is essentially empty. Views are injected into and removed from the DOM as needed. Even though it is a single page application, the Backbone.js Router makes it easy to keep the different states of the app &#8220;bookmarkable&#8221; and &#8220;deep-linkable&#8221;.</p>
<h3>Twitter Bootstrap highlights</h3>
<p>&#8220;Backbone Directory&#8221; uses a number of the Twitter Bootstrap styles, components, and interactions: the 12-column grid with nested columns, a &#8220;Navbar&#8221;, a &#8220;Search Form&#8221; with dropdown,  the dropdown plugin, the Glyphicons icons, Info and Warning alerts, a &#8220;Well&#8221;, etc.</p>
<h3>Backbone.js highlights</h3>
<p>If you are new to Backbone.js, you may want to start with the tutorial (<a href="http://coenraets.org/blog/2011/12/backbone-js-wine-cellar-tutorial-part-1-getting-started/">part 1</a>, <a href="http://coenraets.org/blog/2011/12/backbone-js-wine-cellar-tutorial-part-2-crud/">part 2</a>, <a href="http://coenraets.org/blog/2011/12/backbone-js-wine-cellar-tutorial-part-3-deep-linking-and-application-states/">part 3</a>, and <a href="http://coenraets.org/blog/2012/01/backbone-js-lessons-learned-and-improved-sample-app/">postface</a>) I blogged recently. &#8220;Backbone Directory&#8221; includes some interesting elements not covered in the tutorial:</p>
<ul>
<li><strong>One-to-Many association.</strong> A one-to-many (Manager-to-Employees) association is defined in the Employee model (model/employeemodel.js) as a collection of employees (the direct reports). That collection is lazily fetched in the render() function of EmployeeFullView (view/employeedetails.js).</li>
<li><strong>Composite View.</strong> EmployeeFullView (views/employeedetails.js) is an example of a composite view. Its render() function instantiates two subviews: EmployeeView and EmployeeListView (to display the employee&#8217;s direct reports).
</ul>
<h3>Source Code</h3>
<p>The source code is available in <a href="https://github.com/ccoenraets/backbone-directory">this repository</a> on GitHub.</p>
<p>Your feedback and comments are appreciated.</p>
]]></content:encoded>
			<wfw:commentRss>http://coenraets.org/blog/2012/02/sample-app-with-backbone-js-and-twitter-bootstrap/feed/</wfw:commentRss>
		<slash:comments>91</slash:comments>
		</item>
	</channel>
</rss>
