O:9:"MagpieRSS":23:{s:6:"parser";i:0;s:12:"current_item";a:0:{}s:5:"items";a:10:{i:0;a:13:{s:5:"title";s:44:"Chrome Dev Tools: Networking and the Console";s:4:"link";s:54:"http://feedproxy.google.com/~r/nettuts/~3/Tb5eRwHhSiA/";s:8:"comments";s:87:"http://net.tutsplus.com/tutorials/chrome-dev-tools-networking-and-the-console/#comments";s:7:"pubdate";s:31:"Tue, 27 Nov 2012 19:36:38 +0000";s:2:"dc";a:1:{s:7:"creator";s:10:"Umar Hansa";}s:8:"category";s:35:"OtherTutorialschromedevtoolingtools";s:4:"guid";s:32:"http://net.tutsplus.com/?p=28167";s:11:"description";s:21453:"<a
href='http://rss.buysellads.com/click.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28167&c=367543188' target='_blank'><img
src='http://rss.buysellads.com/img.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28167&c=367543188' border='0' alt='' /></a><p>In <a
href="http://net.tutsplus.com/tutorials/tools-and-tips/chrome-dev-tools-markup-and-style/">Part 1 &#8211; Chrome Dev Tools: Markup and Style</a>, we reviewed two panels: <em>Elements</em> and <em>Resources</em>. Moving on, now, we&#8217;ll take a look at the next two panels: <em>Network</em> and <em>Console</em>.</p><p><span
id="more-28167"></span></p><hr
/><h2>Network Panel</h2><p>The <a
href="https://developers.google.com/chrome-developer-tools/docs/network"><em>Network</em> panel</a> gives us a view into the resources that are requested and downloaded over the network in real-time. Viewing network traffic isn&#8217;t the most glamorous activity &#8211; especially if you&#8217;re new to web development. However, performance becomes an important issue, as your site&#8217;s traffic increases. Identifying and fixing requests that take a long time to complete is an important step in optimizing a site.</p><p>An HTTP proxy, such as <a
href="http://www.charlesproxy.com/">Charles Proxy</a>, can give you a decent amount of information regarding your website&#8217;s network. That being said, the <em>Network</em> panel offers a surprising amount of detailed information; considering how it&#8217;s only a few clicks away, it&#8217;s certainly an excellent candidate for debugging network issues. The following is a screenshot of the <em>Network</em> panel when loading the <a
href="https://touch.www.linkedin.com/#login">Linkedin mobile site</a> on a fresh page load:</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/network-panel-diagram.jpg" alt="The network panel" border="0" /></div><blockquote
class="pullquote"><p><code>$0</code> returns the currently selected element in the <em>Elements</em> panel.</p></blockquote><ol><li>This button opens the <em>Network</em> panel. Be sure to open the tab <strong>before</strong> loading a page so that it captures the network requests (e.g. open a new browser tab, open up developer tools, open up the network tab and then finally load the URL to monitor)</li><li>This row contains one resource with interesting information that I cover in the following points. The first column is the name and path of the resource. The resource name will show on the first line while the path to the resource shows on the second.</li><li>The <a
href="http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods">HTTP method</a> used for the request.</li><li>The <a
href="http://en.wikipedia.org/wiki/List_of_HTTP_status_codes#2xx_Success">HTTP status code</a> returned by the server. <code>200</code> is a common response for a successful response; although anything within the range of 200-299 is considered OK. Notice how one of the above requests is in red. This is related to the HTTP response code, a <a
href="http://www.flickr.com/photos/girliemac/6508023065/">401 Unauthorized</a> response, because I&#8217;m not logged in to the LinkedIn mobile site.</li><li>The <a
href="http://en.wikipedia.org/wiki/MIME#Content-Type">content-type</a> of a request. For example, in an HTTP POST (using the metrics resource as an example), the content-type in the request and response headers is: <code>application/json</code>; whereas, the main HTML page&#8217;s response headers contain a content-type of <code>text/html</code>. A small note on the application cache: when serving a manifest file, be sure to serve it with a content type of <code>text/cache-manifest</code>. When debugging, the &#8220;Type&#8221; column in the <em>Network</em> panel is the place to ensure it&#8217;s being served correctly!</li><li>The initiator is an interesting column; it allows us to see why a resource is downloaded. For example, you may see the <a
href="https://www.google.co.uk/search?q=utm.gif">__utm.gif</a> file often in your debugging sessions; it is used by Google Analytics. The initiator shows as <code>ga.js:52</code>, a value in <code>file_name:line_number</code> format. With this column, you can discover why, when, and how resources are downloaded. If <code>Parser</code> is shown for the initiator, chances are good that the browser initiated the request upon seeing something like a <code>&lt;link /&gt;</code> or <code>&lt;script /&gt;</code> element in the document.</li><blockquote
class="pullquote"><p><strong>Timing</strong> contains information on how long a request actually took to download.</p></blockquote><li>This displays the size of the resource, an invaluable piece of information. When building a site, be sure to regularly &#8220;sort by size&#8221; in the <em>Network</em> panel and ensure that your resource sizes are correct. It is sometimes considered a good practice to <a
href="http://stackoverflow.com/questions/1124149/is-embedding-background-image-data-into-css-as-base64-good-or-bad-practice">base 64 encode images</a> and embed them in CSS files. This can reduce the number of HTTP requests, but it also increases your CSS file&#8217;s size. Large resources should be delayed as much as possible to provide a snappy experience for the user.</li><li>This displays the amount of time it took to retrieve the resource. Resources served from a different domain may take longer to download than other resources served from another origin.</li><li><a
href="https://developer.mozilla.org/en-US/docs/DOM/DOM_event_reference/DOMContentLoaded">DOMContentLoaded</a> (an event we can listen for using JavaScript) fires once the DOM is ready.</li><li>The <a
href="https://developer.mozilla.org/en-US/docs/DOM/window.onload">Load event</a> which fires when the DOM is ready and resources have finished loading.</li><li>Timeline view of network requests. You can hover over them for more information.</li><li>Total size transferred, number of requests, and time taken.</li><li>Icons to interact with the <em>Network</em> panel, such as clearing the panel of all requests and changing icon size.</li><li>Useful network requests filters, e.g. you can control + click XHR and Images to only show network requests for an image resource or a request made with an XHR object.</li><li>Headings for the network requests; you can click a heading to sort the requests by the data in the column.</li></ol><h3>Selected Resource Pane</h3><p>Clicking on a request displays more information in a new panel, splitting the <em>Network</em> panel into two vertical panes.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/network-selected-resource.jpg" alt="" border="0" /></div><blockquote
class="pullquote"><p><a
href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Error">Errors</a> stand out from other console entries thanks to their red color and icon.</p></blockquote><p>The <em>Selected Resource</em> pane has tabs within itself, such as Headers, Preview, Response, Cookies &amp; timing.</p><ul><li><strong>Headers</strong> contains the <a
href="http://net.tutsplus.com/tutorials/other/http-headers-for-dummies/">request and response headers</a>.</li><li><strong>Preview</strong> contains a preview of the resource, for example a rendered image or some source code.</li><li><strong>Response</strong> is similar to Preview and shows what was received from the server.</li><li><strong>Cookies</strong> (if any) shows <a
href="http://net.tutsplus.com/tutorials/javascript-ajax/an-introduction-to-cookies/">cookies</a> sent with the request.</li><li><strong>Timing</strong> contains information on how long a request actually took to download.</li></ul><p>You can close this pane by clicking on the small X in the top left corner of the this pane.</p><h4>Headers</h4><p>The Headers tab provides you with some interesting information, which can prove useful when debugging. It displays both the request and response headers.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/network-source-vs-parsed.jpg" alt="Network panel, source vs. parsed" border="0" /></div><h4>Preview / Response</h4><p>The Preview and Response tabs display a small preview of the selected resource. The developer tools is smart enough to correctly display the response&#8217;s content. Images display as rendered images, XML as text, etc. You&#8217;ll also find extra information such as image sizes, content-type, etc.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/network-preview.jpg" alt="The response tab" border="0" /></div><h4>Timing</h4><p>The Timing tab includes time for <a
href="https://developers.google.com/speed/docs/best-practices/rtt#MinimizeDNSLookups">DNS lookups</a>, SSL negotiation, time to send and receive bytes, and the time that was spent waiting for a response.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/network-timing.jpg" alt="Network panel, resource timing information" border="0" /></div><p>Basically, everything regarding time can be found within this tab.</p><h3>Types of resources</h3><p>The Chrome Developer Tools handles many common resources, and you&#8217;ll get syntax highlighting in the preview for resources such as JavaScript, HTML, etc. Images will also display in their rendered form (very similar to the resources pane).</p><h4>WebSockets</h4><p>The <em>Network</em> panel has the ability to display the contents of a request made using the WebSocket protocol.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/network-websockets.jpg" alt="Viewing websockets in the network panel" border="0" /></div><p>Clicking on such a request displays a new tab named &#8220;Frames&#8221;, listing the frames sent and received.</p><h3>Resource Context Menu</h3><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/network-panel-context-menu.jpg" alt="Network panel context menu" border="0" /></div><p>Right-clicking a particular resource within the <em>Network</em> panel brings up the resource context menu. There are a few options including:</p><ul><li>Clearing the browser cache and cookies to force the browser to download resources from the server.</li><li>Copying the full URL of a resource to your clipboard.</li><li>Copying the request and response headers of a resource is useful for debugging. The request headers often include things like the <a
href="http://en.wikipedia.org/wiki/User_agent">user-agent</a>, the accepted languages the client supports, and possibly cookies. Response headers can include HTTP status codes, <a
href="http://stackoverflow.com/questions/2773396/whats-the-content-length-field-in-http-header">content lengths</a> and server information.</li><li>Viewing the associated HAR data, which I cover below.</li></ul><h4>HAR</h4><blockquote
class="pullquote"><p>Performance becomes an important issue, as your site’s traffic increases.</p></blockquote><p><a
href="http://www.softwareishard.com/blog/har-12-spec/">HAR</a> stands for <em>HTTP Archive</em>, a JSON-based format that contains a list of resources loaded in the page. The format contains nodes such as:</p><ul><li><code>creator</code> &#8211; information about the client that generated the HAR. For example, Chrome&#8217;s dev tools generates a HAR with <code>creator.name</code> set to &#8220;WebInspector&#8221;.</li><li><code>pages</code> &#8211; contains a list of pages associated with the capture. Along with the page title, you&#8217;ll also get a <code>pageTimings</code> object which contains the page load time.</li><li><code>entries</code> &#8211; contains the bulk of the data, and is likely to be a large array of resources. Each <code>entries</code> element can contain <code>request</code> (<code>cookies</code>, <code>headersSize</code>, <code>HTTPVersion</code>, <code>method</code>, <code>url</code>, <code>queryString</code> and more), <code>response</code> (<code>bodySize</code>, <code>status</code>, <code>headersSize</code>, <code>cookies</code> and more), <code>timings</code> (<code>blocked</code>, <code>connect</code>, <code>dns</code>, <code>receive</code>, <code>send</code>, <code>ssl</code> &amp; <code>wait</code>) and more.</li></ul><p>Having all this data is great and opens <a
href="http://www.showslow.org/Advanced_configuration_options#HAR_support">all sorts</a> of <a
href="https://github.com/ariya/phantomjs/blob/master/examples/netsniff.coffee">possibilities</a> for automation, in regard to page performance. Once you possess HAR data, you can use an easy-to-use viewer called <a
href="http://www.softwareishard.com/har/viewer/">HAR Viewer.</a></p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/har-viewer.jpg" alt="viewing HAR data" border="0" /></div><p>You can also view header information with each resource:</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/har-viewer-headers.jpg" alt="viewing HAR data headers" border="0" /></div><hr
/><h2>Console Panel</h2><p>The <a
href="https://developers.google.com/chrome-developer-tools/docs/console"><em>Console</em> Panel</a> allows you to execute JavaScript code within the context of the currently loaded page. The console isn&#8217;t ideal for writing large amounts of code, but it is excellent for small snippets. The following screenshot shows the <em>Console</em> Panel:</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/console-panel-diagram.jpg" alt="console panel diagram" border="0" /></div><blockquote
class="pullquote"><p>The console is excellent for small snippets.</p></blockquote><ol><li><a
href="http://getfirebug.com/logging"><code>console.log</code></a> writes the provided values to the console. There&#8217;s no need to concatenate values together; <code>console.log</code> supports multiple arguments of different types and writes each of them to the console. When you execute a command, you see the output in the immediately following line.</li><li>You may occasionally see &#8220;<code>[native code]</code>&#8221; when attempting to view a native function&#8217;s definition.</li><li>You can write <a
href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function">functions</a> and execute them. Be aware that pressing the <em>enter key</em> executes the code you typed into the console instead of inserting a new line. Hold <em>shift+enter</em> to insert a new line.</li><li>An example of an <a
href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array">array</a>. Notice the colors are different for different types of values.</li><li>An example of a large array with 303 elements. Notice how the elements are grouped together; this prevents the console from being flooded with large amounts of data.</li><li><code>$0</code> is a shortcut to return the currently selected element in the <a
href="https://developers.google.com/chrome-developer-tools/docs/elements"><em>Elements</em> panel</a>. Right-clicking on an element in the console gives you an option to view that element in the <em>Elements</em> panel.</li><li><a
href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Error">Errors</a> stand out from other console entries thanks to their red color and icon.</li><li>We can access anything in the page&#8217;s scope, including the <a
href="https://developer.mozilla.org/en-US/docs/DOM/window">window object</a>. In the screenshot, I created a new <code>WebKitCSSMatrix</code> object.</li><li>You can also style console entries using CSS.</li><li>The console provides code completion. Try typing in &#8220;<code>window.</code>&#8221; and see the vast amount of properties you can choose from!</li></ol><h4>UI</h4><p>On the <em>Network</em> panel, we can <strong>filter</strong> the resources shown in the console by clicking on the filters at the bottom; this is similar to the filtering on the <em>Console</em> Panel. You can <em>control + click</em> the filters to show more than one type.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/console-selective.jpg" alt="being selective in the console" border="0" /></div><p>Logged messages can also be styled like so:</p><pre class="brush: jscript; title: ; notranslate">console.log('%cHello', 'color: green; font-weight: bold;');</pre><h4>Grouping</h4><p>You can also group console entries by using <code>console.group</code>. The following screenshot shows an example:</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/console-group.jpg" alt="grouping in the console" border="0" /></div><p>Use <code>console.group()</code> to start a group and <code>console.groupEnd()</code> to end it. Anything written to the console between those delimiters will appear inside the group. Try it for yourself:</p><pre class="brush: jscript; title: ; notranslate">console.group(&quot;%cMy Custom Group&quot;, &quot;color: green&quot;);
console.log(&quot;A value part of a group&quot;);
console.group(&quot;%cA sub-group&quot;, &quot;color: blue&quot;);
console.log(&quot;Sub-group value&quot;);
console.groupEnd();
console.log(&quot;We're out of the sub-group now&quot;);
console.groupEnd();
console.log(&quot;%cA message with no grouping&quot;, &quot;text-decoration:underline&quot;);</pre><h4>Inspecting</h4><p>Viewing the contents of an <a
href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object">object</a> is simple. For small objects, the console displays an object&#8217;s contents in one line. Larger objects, however, appear as a collapsed group, and you can inspect them by clicking on the drop down arrow immediately to the left of the object.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/console-inspect.jpg" alt="renaming an element" border="0" /></div><p>Double clicking an identifier inside an object automatically highlights, making it easy to copy, paste, and edit.</p><h4>Miscellaneous</h4><p>Learning keyboard shortcuts and other commands helps you work more efficiently. Here are some examples:</p><ul><li><code>console.clear()</code> clears the console; <em>Control + L</em> achieves the same affect.</li><li><code>console.assert()</code> throws an error if the passed argument doesn&#8217;t resolve to <code>true</code>.</li><li><code>console.error()</code> throws a custom error in the console.</li><li><code>$0</code> returns the currently selected element in the <em>Elements</em> panel.</li><li><code>Esc</code> toggles the console on any panel other than the <em>Console</em> panel.</li></ul><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/console-shortcuts.jpg" alt="shortcuts in the console" border="0" /></div><p>Try the following:</p><pre class="brush: jscript; title: ; notranslate">console.clear();
console.assert(0 &gt; 1);
console.error(&quot;Error message&quot;);
$0 //get the currently selected element</pre><hr
/><h2>Until Next Time!</h2><p>I hope you&#8217;ve learned a few new tricks. Please keep in mind that Chrome&#8217;s developer tools are always in a state of flux. For example, a ruler tool was implemented shortly after we published the <a
href="http://net.tutsplus.com/tutorials/tools-and-tips/chrome-dev-tools-markup-and-style/">previous tutorial</a> in this mini-series. Be sure to enable them and try it out!</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/new-rulers.jpg" alt="rulers and guides" border="0" /></div><p>In the following tutorial, we&#8217;ll continue to look at JavaScript and discuss techniques to edit resources after a page has loaded. Thanks for reading!</p>
<p><a href="http://feedads.g.doubleclick.net/~a/z2bmg8mN7UuzG1bk1G9kF6stc34/0/da"><img src="http://feedads.g.doubleclick.net/~a/z2bmg8mN7UuzG1bk1G9kF6stc34/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/z2bmg8mN7UuzG1bk1G9kF6stc34/1/da"><img src="http://feedads.g.doubleclick.net/~a/z2bmg8mN7UuzG1bk1G9kF6stc34/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=Tb5eRwHhSiA:4O635bnhA8M:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=Tb5eRwHhSiA:4O635bnhA8M:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=Tb5eRwHhSiA:4O635bnhA8M:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=Tb5eRwHhSiA:4O635bnhA8M:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=Tb5eRwHhSiA:4O635bnhA8M:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=Tb5eRwHhSiA:4O635bnhA8M:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=Tb5eRwHhSiA:4O635bnhA8M:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=Tb5eRwHhSiA:4O635bnhA8M:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/Tb5eRwHhSiA" height="1" width="1"/>";s:3:"wfw";a:1:{s:10:"commentrss";s:83:"http://net.tutsplus.com/tutorials/chrome-dev-tools-networking-and-the-console/feed/";}s:5:"slash";a:1:{s:8:"comments";s:1:"3";}s:10:"feedburner";a:1:{s:8:"origlink";s:78:"http://net.tutsplus.com/tutorials/chrome-dev-tools-networking-and-the-console/";}s:7:"summary";s:21453:"<a
href='http://rss.buysellads.com/click.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28167&c=367543188' target='_blank'><img
src='http://rss.buysellads.com/img.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28167&c=367543188' border='0' alt='' /></a><p>In <a
href="http://net.tutsplus.com/tutorials/tools-and-tips/chrome-dev-tools-markup-and-style/">Part 1 &#8211; Chrome Dev Tools: Markup and Style</a>, we reviewed two panels: <em>Elements</em> and <em>Resources</em>. Moving on, now, we&#8217;ll take a look at the next two panels: <em>Network</em> and <em>Console</em>.</p><p><span
id="more-28167"></span></p><hr
/><h2>Network Panel</h2><p>The <a
href="https://developers.google.com/chrome-developer-tools/docs/network"><em>Network</em> panel</a> gives us a view into the resources that are requested and downloaded over the network in real-time. Viewing network traffic isn&#8217;t the most glamorous activity &#8211; especially if you&#8217;re new to web development. However, performance becomes an important issue, as your site&#8217;s traffic increases. Identifying and fixing requests that take a long time to complete is an important step in optimizing a site.</p><p>An HTTP proxy, such as <a
href="http://www.charlesproxy.com/">Charles Proxy</a>, can give you a decent amount of information regarding your website&#8217;s network. That being said, the <em>Network</em> panel offers a surprising amount of detailed information; considering how it&#8217;s only a few clicks away, it&#8217;s certainly an excellent candidate for debugging network issues. The following is a screenshot of the <em>Network</em> panel when loading the <a
href="https://touch.www.linkedin.com/#login">Linkedin mobile site</a> on a fresh page load:</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/network-panel-diagram.jpg" alt="The network panel" border="0" /></div><blockquote
class="pullquote"><p><code>$0</code> returns the currently selected element in the <em>Elements</em> panel.</p></blockquote><ol><li>This button opens the <em>Network</em> panel. Be sure to open the tab <strong>before</strong> loading a page so that it captures the network requests (e.g. open a new browser tab, open up developer tools, open up the network tab and then finally load the URL to monitor)</li><li>This row contains one resource with interesting information that I cover in the following points. The first column is the name and path of the resource. The resource name will show on the first line while the path to the resource shows on the second.</li><li>The <a
href="http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods">HTTP method</a> used for the request.</li><li>The <a
href="http://en.wikipedia.org/wiki/List_of_HTTP_status_codes#2xx_Success">HTTP status code</a> returned by the server. <code>200</code> is a common response for a successful response; although anything within the range of 200-299 is considered OK. Notice how one of the above requests is in red. This is related to the HTTP response code, a <a
href="http://www.flickr.com/photos/girliemac/6508023065/">401 Unauthorized</a> response, because I&#8217;m not logged in to the LinkedIn mobile site.</li><li>The <a
href="http://en.wikipedia.org/wiki/MIME#Content-Type">content-type</a> of a request. For example, in an HTTP POST (using the metrics resource as an example), the content-type in the request and response headers is: <code>application/json</code>; whereas, the main HTML page&#8217;s response headers contain a content-type of <code>text/html</code>. A small note on the application cache: when serving a manifest file, be sure to serve it with a content type of <code>text/cache-manifest</code>. When debugging, the &#8220;Type&#8221; column in the <em>Network</em> panel is the place to ensure it&#8217;s being served correctly!</li><li>The initiator is an interesting column; it allows us to see why a resource is downloaded. For example, you may see the <a
href="https://www.google.co.uk/search?q=utm.gif">__utm.gif</a> file often in your debugging sessions; it is used by Google Analytics. The initiator shows as <code>ga.js:52</code>, a value in <code>file_name:line_number</code> format. With this column, you can discover why, when, and how resources are downloaded. If <code>Parser</code> is shown for the initiator, chances are good that the browser initiated the request upon seeing something like a <code>&lt;link /&gt;</code> or <code>&lt;script /&gt;</code> element in the document.</li><blockquote
class="pullquote"><p><strong>Timing</strong> contains information on how long a request actually took to download.</p></blockquote><li>This displays the size of the resource, an invaluable piece of information. When building a site, be sure to regularly &#8220;sort by size&#8221; in the <em>Network</em> panel and ensure that your resource sizes are correct. It is sometimes considered a good practice to <a
href="http://stackoverflow.com/questions/1124149/is-embedding-background-image-data-into-css-as-base64-good-or-bad-practice">base 64 encode images</a> and embed them in CSS files. This can reduce the number of HTTP requests, but it also increases your CSS file&#8217;s size. Large resources should be delayed as much as possible to provide a snappy experience for the user.</li><li>This displays the amount of time it took to retrieve the resource. Resources served from a different domain may take longer to download than other resources served from another origin.</li><li><a
href="https://developer.mozilla.org/en-US/docs/DOM/DOM_event_reference/DOMContentLoaded">DOMContentLoaded</a> (an event we can listen for using JavaScript) fires once the DOM is ready.</li><li>The <a
href="https://developer.mozilla.org/en-US/docs/DOM/window.onload">Load event</a> which fires when the DOM is ready and resources have finished loading.</li><li>Timeline view of network requests. You can hover over them for more information.</li><li>Total size transferred, number of requests, and time taken.</li><li>Icons to interact with the <em>Network</em> panel, such as clearing the panel of all requests and changing icon size.</li><li>Useful network requests filters, e.g. you can control + click XHR and Images to only show network requests for an image resource or a request made with an XHR object.</li><li>Headings for the network requests; you can click a heading to sort the requests by the data in the column.</li></ol><h3>Selected Resource Pane</h3><p>Clicking on a request displays more information in a new panel, splitting the <em>Network</em> panel into two vertical panes.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/network-selected-resource.jpg" alt="" border="0" /></div><blockquote
class="pullquote"><p><a
href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Error">Errors</a> stand out from other console entries thanks to their red color and icon.</p></blockquote><p>The <em>Selected Resource</em> pane has tabs within itself, such as Headers, Preview, Response, Cookies &amp; timing.</p><ul><li><strong>Headers</strong> contains the <a
href="http://net.tutsplus.com/tutorials/other/http-headers-for-dummies/">request and response headers</a>.</li><li><strong>Preview</strong> contains a preview of the resource, for example a rendered image or some source code.</li><li><strong>Response</strong> is similar to Preview and shows what was received from the server.</li><li><strong>Cookies</strong> (if any) shows <a
href="http://net.tutsplus.com/tutorials/javascript-ajax/an-introduction-to-cookies/">cookies</a> sent with the request.</li><li><strong>Timing</strong> contains information on how long a request actually took to download.</li></ul><p>You can close this pane by clicking on the small X in the top left corner of the this pane.</p><h4>Headers</h4><p>The Headers tab provides you with some interesting information, which can prove useful when debugging. It displays both the request and response headers.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/network-source-vs-parsed.jpg" alt="Network panel, source vs. parsed" border="0" /></div><h4>Preview / Response</h4><p>The Preview and Response tabs display a small preview of the selected resource. The developer tools is smart enough to correctly display the response&#8217;s content. Images display as rendered images, XML as text, etc. You&#8217;ll also find extra information such as image sizes, content-type, etc.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/network-preview.jpg" alt="The response tab" border="0" /></div><h4>Timing</h4><p>The Timing tab includes time for <a
href="https://developers.google.com/speed/docs/best-practices/rtt#MinimizeDNSLookups">DNS lookups</a>, SSL negotiation, time to send and receive bytes, and the time that was spent waiting for a response.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/network-timing.jpg" alt="Network panel, resource timing information" border="0" /></div><p>Basically, everything regarding time can be found within this tab.</p><h3>Types of resources</h3><p>The Chrome Developer Tools handles many common resources, and you&#8217;ll get syntax highlighting in the preview for resources such as JavaScript, HTML, etc. Images will also display in their rendered form (very similar to the resources pane).</p><h4>WebSockets</h4><p>The <em>Network</em> panel has the ability to display the contents of a request made using the WebSocket protocol.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/network-websockets.jpg" alt="Viewing websockets in the network panel" border="0" /></div><p>Clicking on such a request displays a new tab named &#8220;Frames&#8221;, listing the frames sent and received.</p><h3>Resource Context Menu</h3><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/network-panel-context-menu.jpg" alt="Network panel context menu" border="0" /></div><p>Right-clicking a particular resource within the <em>Network</em> panel brings up the resource context menu. There are a few options including:</p><ul><li>Clearing the browser cache and cookies to force the browser to download resources from the server.</li><li>Copying the full URL of a resource to your clipboard.</li><li>Copying the request and response headers of a resource is useful for debugging. The request headers often include things like the <a
href="http://en.wikipedia.org/wiki/User_agent">user-agent</a>, the accepted languages the client supports, and possibly cookies. Response headers can include HTTP status codes, <a
href="http://stackoverflow.com/questions/2773396/whats-the-content-length-field-in-http-header">content lengths</a> and server information.</li><li>Viewing the associated HAR data, which I cover below.</li></ul><h4>HAR</h4><blockquote
class="pullquote"><p>Performance becomes an important issue, as your site’s traffic increases.</p></blockquote><p><a
href="http://www.softwareishard.com/blog/har-12-spec/">HAR</a> stands for <em>HTTP Archive</em>, a JSON-based format that contains a list of resources loaded in the page. The format contains nodes such as:</p><ul><li><code>creator</code> &#8211; information about the client that generated the HAR. For example, Chrome&#8217;s dev tools generates a HAR with <code>creator.name</code> set to &#8220;WebInspector&#8221;.</li><li><code>pages</code> &#8211; contains a list of pages associated with the capture. Along with the page title, you&#8217;ll also get a <code>pageTimings</code> object which contains the page load time.</li><li><code>entries</code> &#8211; contains the bulk of the data, and is likely to be a large array of resources. Each <code>entries</code> element can contain <code>request</code> (<code>cookies</code>, <code>headersSize</code>, <code>HTTPVersion</code>, <code>method</code>, <code>url</code>, <code>queryString</code> and more), <code>response</code> (<code>bodySize</code>, <code>status</code>, <code>headersSize</code>, <code>cookies</code> and more), <code>timings</code> (<code>blocked</code>, <code>connect</code>, <code>dns</code>, <code>receive</code>, <code>send</code>, <code>ssl</code> &amp; <code>wait</code>) and more.</li></ul><p>Having all this data is great and opens <a
href="http://www.showslow.org/Advanced_configuration_options#HAR_support">all sorts</a> of <a
href="https://github.com/ariya/phantomjs/blob/master/examples/netsniff.coffee">possibilities</a> for automation, in regard to page performance. Once you possess HAR data, you can use an easy-to-use viewer called <a
href="http://www.softwareishard.com/har/viewer/">HAR Viewer.</a></p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/har-viewer.jpg" alt="viewing HAR data" border="0" /></div><p>You can also view header information with each resource:</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/har-viewer-headers.jpg" alt="viewing HAR data headers" border="0" /></div><hr
/><h2>Console Panel</h2><p>The <a
href="https://developers.google.com/chrome-developer-tools/docs/console"><em>Console</em> Panel</a> allows you to execute JavaScript code within the context of the currently loaded page. The console isn&#8217;t ideal for writing large amounts of code, but it is excellent for small snippets. The following screenshot shows the <em>Console</em> Panel:</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/console-panel-diagram.jpg" alt="console panel diagram" border="0" /></div><blockquote
class="pullquote"><p>The console is excellent for small snippets.</p></blockquote><ol><li><a
href="http://getfirebug.com/logging"><code>console.log</code></a> writes the provided values to the console. There&#8217;s no need to concatenate values together; <code>console.log</code> supports multiple arguments of different types and writes each of them to the console. When you execute a command, you see the output in the immediately following line.</li><li>You may occasionally see &#8220;<code>[native code]</code>&#8221; when attempting to view a native function&#8217;s definition.</li><li>You can write <a
href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function">functions</a> and execute them. Be aware that pressing the <em>enter key</em> executes the code you typed into the console instead of inserting a new line. Hold <em>shift+enter</em> to insert a new line.</li><li>An example of an <a
href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array">array</a>. Notice the colors are different for different types of values.</li><li>An example of a large array with 303 elements. Notice how the elements are grouped together; this prevents the console from being flooded with large amounts of data.</li><li><code>$0</code> is a shortcut to return the currently selected element in the <a
href="https://developers.google.com/chrome-developer-tools/docs/elements"><em>Elements</em> panel</a>. Right-clicking on an element in the console gives you an option to view that element in the <em>Elements</em> panel.</li><li><a
href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Error">Errors</a> stand out from other console entries thanks to their red color and icon.</li><li>We can access anything in the page&#8217;s scope, including the <a
href="https://developer.mozilla.org/en-US/docs/DOM/window">window object</a>. In the screenshot, I created a new <code>WebKitCSSMatrix</code> object.</li><li>You can also style console entries using CSS.</li><li>The console provides code completion. Try typing in &#8220;<code>window.</code>&#8221; and see the vast amount of properties you can choose from!</li></ol><h4>UI</h4><p>On the <em>Network</em> panel, we can <strong>filter</strong> the resources shown in the console by clicking on the filters at the bottom; this is similar to the filtering on the <em>Console</em> Panel. You can <em>control + click</em> the filters to show more than one type.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/console-selective.jpg" alt="being selective in the console" border="0" /></div><p>Logged messages can also be styled like so:</p><pre class="brush: jscript; title: ; notranslate">console.log('%cHello', 'color: green; font-weight: bold;');</pre><h4>Grouping</h4><p>You can also group console entries by using <code>console.group</code>. The following screenshot shows an example:</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/console-group.jpg" alt="grouping in the console" border="0" /></div><p>Use <code>console.group()</code> to start a group and <code>console.groupEnd()</code> to end it. Anything written to the console between those delimiters will appear inside the group. Try it for yourself:</p><pre class="brush: jscript; title: ; notranslate">console.group(&quot;%cMy Custom Group&quot;, &quot;color: green&quot;);
console.log(&quot;A value part of a group&quot;);
console.group(&quot;%cA sub-group&quot;, &quot;color: blue&quot;);
console.log(&quot;Sub-group value&quot;);
console.groupEnd();
console.log(&quot;We're out of the sub-group now&quot;);
console.groupEnd();
console.log(&quot;%cA message with no grouping&quot;, &quot;text-decoration:underline&quot;);</pre><h4>Inspecting</h4><p>Viewing the contents of an <a
href="https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object">object</a> is simple. For small objects, the console displays an object&#8217;s contents in one line. Larger objects, however, appear as a collapsed group, and you can inspect them by clicking on the drop down arrow immediately to the left of the object.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/console-inspect.jpg" alt="renaming an element" border="0" /></div><p>Double clicking an identifier inside an object automatically highlights, making it easy to copy, paste, and edit.</p><h4>Miscellaneous</h4><p>Learning keyboard shortcuts and other commands helps you work more efficiently. Here are some examples:</p><ul><li><code>console.clear()</code> clears the console; <em>Control + L</em> achieves the same affect.</li><li><code>console.assert()</code> throws an error if the passed argument doesn&#8217;t resolve to <code>true</code>.</li><li><code>console.error()</code> throws a custom error in the console.</li><li><code>$0</code> returns the currently selected element in the <em>Elements</em> panel.</li><li><code>Esc</code> toggles the console on any panel other than the <em>Console</em> panel.</li></ul><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/console-shortcuts.jpg" alt="shortcuts in the console" border="0" /></div><p>Try the following:</p><pre class="brush: jscript; title: ; notranslate">console.clear();
console.assert(0 &gt; 1);
console.error(&quot;Error message&quot;);
$0 //get the currently selected element</pre><hr
/><h2>Until Next Time!</h2><p>I hope you&#8217;ve learned a few new tricks. Please keep in mind that Chrome&#8217;s developer tools are always in a state of flux. For example, a ruler tool was implemented shortly after we published the <a
href="http://net.tutsplus.com/tutorials/tools-and-tips/chrome-dev-tools-markup-and-style/">previous tutorial</a> in this mini-series. Be sure to enable them and try it out!</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2158_chrome2/new-rulers.jpg" alt="rulers and guides" border="0" /></div><p>In the following tutorial, we&#8217;ll continue to look at JavaScript and discuss techniques to edit resources after a page has loaded. Thanks for reading!</p>
<p><a href="http://feedads.g.doubleclick.net/~a/z2bmg8mN7UuzG1bk1G9kF6stc34/0/da"><img src="http://feedads.g.doubleclick.net/~a/z2bmg8mN7UuzG1bk1G9kF6stc34/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/z2bmg8mN7UuzG1bk1G9kF6stc34/1/da"><img src="http://feedads.g.doubleclick.net/~a/z2bmg8mN7UuzG1bk1G9kF6stc34/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=Tb5eRwHhSiA:4O635bnhA8M:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=Tb5eRwHhSiA:4O635bnhA8M:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=Tb5eRwHhSiA:4O635bnhA8M:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=Tb5eRwHhSiA:4O635bnhA8M:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=Tb5eRwHhSiA:4O635bnhA8M:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=Tb5eRwHhSiA:4O635bnhA8M:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=Tb5eRwHhSiA:4O635bnhA8M:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=Tb5eRwHhSiA:4O635bnhA8M:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/Tb5eRwHhSiA" height="1" width="1"/>";s:14:"date_timestamp";i:1354044998;}i:1;a:13:{s:5:"title";s:81:"Chatting with Obama For America’s Director of Frontend Development: Daniel Ryan";s:4:"link";s:54:"http://feedproxy.google.com/~r/nettuts/~3/fXfSHsKc6j4/";s:8:"comments";s:131:"http://net.tutsplus.com/articles/interviews/chatting-with-obama-for-americas-director-of-frontend-development-daniel-ryan/#comments";s:7:"pubdate";s:31:"Mon, 26 Nov 2012 14:54:37 +0000";s:2:"dc";a:1:{s:7:"creator";s:16:"Jonathan Cutrell";}s:8:"category";s:10:"Interviews";s:4:"guid";s:32:"http://net.tutsplus.com/?p=28220";s:11:"description";s:16223:"<a
href='http://rss.buysellads.com/click.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28220&c=1037932174' target='_blank'><img
src='http://rss.buysellads.com/img.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28220&c=1037932174' border='0' alt='' /></a><p>Whether you lean to the right or the left, there&#8217;s little doubt that, if you&#8217;re a Nettuts+ reader, you&#8217;ll likely agree that technology is rapidly shaping politics. In United States Presidential campaigns, the web was a major platform for front-facing unification of a message, but it was also a core part of each side&#8217;s internal processes.</p><p>Recently, we had the opportunity to interview <a
href="http://dryan.com/">Daniel Ryan</a> &#8211; the Director of Frontend Development for &#8220;Obama for America&#8221; &#8211; about the strategies, technologies, and experiences that were a part of the race to November 6.</p><p><span
id="more-28220"></span></p><hr
/><div
class="question"><h4><span>Q</span>What was the biggest large-scale challenge for the design and development teams during the campaign?</h4></div><div
class="tutorial_image"> <a
href="http://www.barackobama.com/"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2160_obamaWebsite/obama-website.jpg" alt="Obama For America Website"></a></div><p>The biggest scale challenge wasn&#8217;t a single project; it was the sheer volume of requests we got each day. Our dev team was split among three areas: fundraising, persuasion and getting voters to the polls. Turning around new designs through approvals by messaging, policy, research, legal, etc., then launching those projects within a few days or often a few hours was the single largest challenge. Both Design and Dev had a team of Producers who managed those requests, assigned them to relevant staff and saw them through completion.</p><blockquote><p> The biggest challenge [...] was the shear volume of requests we got each day.</p></blockquote><hr
/><div
class="question"><h4><span>Q</span> How did the campaign approach A/B testing and data-driven design decision-making?</h4></div><p>One of the things that has been said often about the campaign is that we were data driven. This couldn&#8217;t be more true. My deputy Kyle Rush oversaw an optimization working group consisting of developers, designers, user experience engineers, data analysts, online ad specialists and content writers. We used a mix of approaches, mostly focused on <a
href="https://www.optimizely.com/">Optimizely</a> for A/B testing to prove (and disprove, often) theses about how pages could perform better.</p><div
class="tutorial_image"> <a
href="https://www.optimizely.com/"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2160_obamaWebsite/optimizely.jpg" alt="Optimizely"></a></div><p>Our traffic levels meant we could run multiple tests per day to significant levels. A weekly report was compiled with updated best practices and recommendations based on those findings. We estimate that we achieved about $125 million in incremental improvements to our fundraising pages alone.</p><hr
/><div
class="question"><h4><span>Q</span> Can you give us a simple run-down of the stack, from back to front?</h4></div><p>There wasn&#8217;t a single stack. One of the smartest things we did was run dozens of decoupled systems tied together with JavaScript and <a
href="http://www.akamai.com/">Akamai</a> services. Broadly, our stack ran on <a
href="http://aws.amazon.com/">Amazon Web Services</a>, including thousands of EC2 instances, several large database clusters and S3 hosting. Our main site, <a
href="http://www.barackobama.com/">www.barackobama.com</a>, was an <a
href="http://expressionengine.com/">Expression Engine</a> install backed by EC2 and RDS and fronted by Akamai caching.</p><p>Akamai offloaded about 98% of all of our traffic. Additionally we used <a
href="https://github.com/mojombo/jekyll">Jekyll</a>, multiple custom apps built on <a
href="https://www.djangoproject.com/">Django</a>, <a
href="http://flask.pocoo.org/">Flask</a>, <a
href="http://rubyonrails.org/">Rails</a> and <a
href="http://www.magentocommerce.com/">Magento</a>. Our widest-used language was <a
href="http://www.python.org/">Python</a>.</p><blockquote><p>One of the smartest things we did was run dozens of decoupled systems tied together with JavaScript and Akamai services.</p></blockquote><hr
/><div
class="question"><h4><span>Q</span> What are some of the open-source tools OFA used during the campaign? What was the production/deployment strategy?</h4></div><p>On the client-side, we rolled our own CSS grid and core styles along with <a
href="http://jquery.com">jQuery</a>, <a
href="http://modernizr.com">Modernizr</a> and a core JavaScript library that lazy loaded modules as needed. We used <a
href="https://github.com/janl/mustache.js/">Mustache.js</a> templates quite a bit for browser-based apps. As the first responsive website for a national campaign, we tried out a lot of open source tools for making mobile experiences better. <a
href="http://fitvidsjs.com/">Fitvids.js</a> was one of the heaviest used. Internally, we worked in <a
href="http://lesscss.org/">LESS CSS</a>, compiled by <a
href="http://incident57.com/codekit/">CodeKit</a>. One of the devs showed me LESS while we were overhauling the site in October 2011; by the end of the day, the whole site had switched to it. This is just one example of how we stayed open to better approaches every day and weren&#8217;t scared to embrace a new method or system if it made sense.</p><p>We ran <a
href="http://git-scm.com/">git</a> as our VCS of choice, for all the obvious reasons. All of our code went through <a
href="https://github.com/">Github</a>, which also served as our main code management flow. We were heavily guided by the principles of <a
href="http://zachholman.com/talk/how-github-uses-github-to-build-github">&#8220;How Github Uses Github to Build Github&#8221;</a>. Wherever it made sense, our flow was:</p><ul><li>branch locally</li><li>set a Git tag on the repo once the code was ready for review and testing</li><li>deploy the tag to staging servers</li><li>code review and QA</li><li>once the code was production ready, set up a pull request to the master branch</li><li>pull requests were reviewed by lead developers or senior developers; static assets were deployed to S3, while server-side code required a deploy request to our DevOps team</li><li>the DevOps team used Puppet and Gippetto to create apk distros for the Linux boxes</li><li>small code changes would get deployed on the fly; large ones would get built out under new server clusters, tested internally and then swapped in place of the old version</li></ul><p>We didn&#8217;t get to use this flow everywhere we would have liked, because we came into a working system, rather than starting from scratch. When I arrived in August 2011, there were no dev or staging environments for our main site, for instance. We got a staging system in place pretty quickly, but always struggled to have local dev environments for Expression Engine.</p><hr
/><div
class="question"><h4><span>Q</span> Where did design ideas originate? What was the process of taking an idea from birth to deployment?</h4></div><p>Design ideas largely came from the Design team directly. Josh Higgins, our Design Director, and I worked very hard to make sure our teams collaborated continuously. We sat in our own section of the office, along with the program/project managers, so we could keep the two teams working physically near each other. Many of the designs we rolled out started by a designer or developer finding a cool idea somewhere and emailing it around to the two teams. These ideas then became the vernacular we would talk in when trying to come up with a specific concept. As with everything else, though, data was our guide. No matter how cool we thought something was, if the data showed it wasn&#8217;t getting the results we wanted, we would try another approach.</p><blockquote><p>Many of the designs we rolled out started by a designer or developer finding a cool idea somewhere and emailing it around to the two teams. These ideas then became the vernacular we would talk in when trying to come up with a specific concept.</p></blockquote><p>The process was much like any good digital agency. We&#8217;d have a kickoff meeting with PMs, Producers, Leads, etc. to figure out the scope of a project. Someone would send around the notes from that, and we&#8217;d all tweak them for a bit then send up to our leadership to get sign off on the direction we wanted to go in. After incorporating feedback, either a designer would begin comps or, for more complicated projects, a developer would begin prototypes. The assigned developer and designer would iterate through those until the project was live and ready for testing. Normally, we would send the staging version around for approvals at the same time the QA team was doing cross-browser testing. The team would iterate on the notes from both and then we&#8217;d launch. Keep in mind that near the end of the summer, we were doing this on a dozen projects or more simultaneously. Many times, we&#8217;d do this whole cycle in a single day.</p><hr
/><div
class="question"><h4><span>Q</span> We have read a bit about the technical issues that plagued the Romney camp throughout the campaign, including server outages and hard drive failures. What were some of the most important strategic decisions the Obama team made to avoid these problems?</h4></div><blockquote
class="pullquote"><p>I think our approach basically boiled down to pragmatic paranoia.</p></blockquote><p>This was my first campaign as a staffer, but we had many alumni from &#8217;08 with us. I think I had been in Chicago less than a week before I&#8217;d heard about <a
href="http://www.theatlantic.com/politics/archive/2012/11/orca-failed-but-so-did-obamas-2008-version-of-the-same/265077/">the failure of Houdini</a>, which was the Obama &#8217;08 system akin to Romney&#8217;s Orca. Because of the institutional experience with this voter monitoring system&#8217;s failure, we never put ourselves in a place where a single system failure could do real damage. We had the luxury of time, which we used in part to build redundancies. Our payment processor, for instance, was actually one in-house system and one vendor system that Akamai flipped between automatically if one side went down. That system worked so well we replicated it for polling places. We had two APIs, one internal and one powered by Google, with a thin PHP app to make the output the same. Not only could Akamai automatically fail between them without the end user noticing, but we had a system in place where we could choose which states used which system proactively. This let us prevent a traffic spike outage. The systems we relied upon specifically for Election Day all had two backup systems: one powered by Google Doc spreadsheets and one consisting of printed hard-copies of critical data. I think our approach basically boiled down to pragmatic paranoia.</p><hr
/><div
class="question"><h4><span>Q</span> How did responsive design play a role in the Obama strategic team? Was the design &#8220;mobile first&#8221;?</h4></div><div
class="tutorial_image"> <img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2160_obamaWebsite/obama-responsive.jpg" alt="Responsive Obama Website"></div><p>Early on, the campaign tried making a <a
href="http://jquerymobile.com/">jQuery Mobile</a> powered site, but maintaining two templates for everything simply wasn&#8217;t going to scale. We were seeing 25% of our traffic come from mobile devices, but almost none of our donations. When we set out to do a site overhaul in Fall 2011, it was a foregone conclusion we would do mobile-first, responsive/adaptive. It was a learning process for all of us. If there&#8217;s one takeaway I would really stress, mobile-first doesn&#8217;t mean starting with a 320 pixel wide design, it means starting with a low bandwidth experience. We learned that lesson over and over throughout the course of the campaign. Mobile first is a comprehensive approach including content creation that is mobile friendly, design that is flexible and code that is as lean as possible.</p><blockquote><p>Mobile-first doesn&#8217;t mean starting with a 320 pixel wide design, it means starting with a low bandwidth experience.</p></blockquote><hr
/><div
class="question"><h4><span>Q</span> What was the biggest lesson to be learned about large-scale deployment?</h4></div><p>The biggest lesson I learned about large-scale deployment is hire smart people. When you&#8217;re trying to tune for scale, especially in the hockey stick curve we knew we were going to have, you need people at every part of the stack thinking about how to be more efficient. Most of my team had no experience at the kind of scale we wound up working at, but we learned quickly and adapted.</p><hr
/><div
class="question"><h4><span>Q</span> What was the general management structure of projects for the Obama team?</h4></div><blockquote
class="pullquote"><p>I truly believe that this is the last presidential campaign where the &#8220;Internet people&#8221; will be separated into their own group.</p></blockquote><p>The structure varied by project, but our overall structure was basically divided into those three buckets I mentioned before: fundraising, persuasion and turning out voters. Internally, there was a Digital Department, which my team was part of along with Design, Online Ads, Social, Email, Content, Digital Analytics, Program Managers, Video, Online Organizing, Rapid Response and our management team. Generally speaking, we handled all the public-facing work of the campaign online. Additionally, the Tech Department was responsible for the infrastructure (our DevOps team) and the server-side code for virtually everything we did. There was some crossover between the two departments as well. A large part of my role was coordinating with Tech and DevOps as we constantly deployed more and more systems.</p><p>I truly believe that this is the last presidential campaign where the &#8220;Internet people&#8221; will be separated into their own group. Our work covered every area of the campaign at some point. 2016 should be much more of a matrix org chart than a hierarchical one.</p><hr
/><h2>In Closing</h2><p>Thanks again to Daniel for agreeing to speak with us. To stay up to date, be sure to <a
href="http://twitter.com/dryan">follow him on Twitter</a>, and keep an eye on <a
href="http://dryan.com/">his website.</a></p><div
class="tutorial_image"> <a
href="http://dryan.com/"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2160_obamaWebsite/daniel-ryan-website.jpg" alt="Daniel Ryan"></a></div>
<p><a href="http://feedads.g.doubleclick.net/~a/wb3Qu70ev66MCPsvXuMzDRjdBkQ/0/da"><img src="http://feedads.g.doubleclick.net/~a/wb3Qu70ev66MCPsvXuMzDRjdBkQ/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/wb3Qu70ev66MCPsvXuMzDRjdBkQ/1/da"><img src="http://feedads.g.doubleclick.net/~a/wb3Qu70ev66MCPsvXuMzDRjdBkQ/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=fXfSHsKc6j4:8ObdbLIuUnA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=fXfSHsKc6j4:8ObdbLIuUnA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=fXfSHsKc6j4:8ObdbLIuUnA:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=fXfSHsKc6j4:8ObdbLIuUnA:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=fXfSHsKc6j4:8ObdbLIuUnA:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=fXfSHsKc6j4:8ObdbLIuUnA:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=fXfSHsKc6j4:8ObdbLIuUnA:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=fXfSHsKc6j4:8ObdbLIuUnA:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/fXfSHsKc6j4" height="1" width="1"/>";s:3:"wfw";a:1:{s:10:"commentrss";s:127:"http://net.tutsplus.com/articles/interviews/chatting-with-obama-for-americas-director-of-frontend-development-daniel-ryan/feed/";}s:5:"slash";a:1:{s:8:"comments";s:2:"24";}s:10:"feedburner";a:1:{s:8:"origlink";s:122:"http://net.tutsplus.com/articles/interviews/chatting-with-obama-for-americas-director-of-frontend-development-daniel-ryan/";}s:7:"summary";s:16223:"<a
href='http://rss.buysellads.com/click.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28220&c=1037932174' target='_blank'><img
src='http://rss.buysellads.com/img.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28220&c=1037932174' border='0' alt='' /></a><p>Whether you lean to the right or the left, there&#8217;s little doubt that, if you&#8217;re a Nettuts+ reader, you&#8217;ll likely agree that technology is rapidly shaping politics. In United States Presidential campaigns, the web was a major platform for front-facing unification of a message, but it was also a core part of each side&#8217;s internal processes.</p><p>Recently, we had the opportunity to interview <a
href="http://dryan.com/">Daniel Ryan</a> &#8211; the Director of Frontend Development for &#8220;Obama for America&#8221; &#8211; about the strategies, technologies, and experiences that were a part of the race to November 6.</p><p><span
id="more-28220"></span></p><hr
/><div
class="question"><h4><span>Q</span>What was the biggest large-scale challenge for the design and development teams during the campaign?</h4></div><div
class="tutorial_image"> <a
href="http://www.barackobama.com/"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2160_obamaWebsite/obama-website.jpg" alt="Obama For America Website"></a></div><p>The biggest scale challenge wasn&#8217;t a single project; it was the sheer volume of requests we got each day. Our dev team was split among three areas: fundraising, persuasion and getting voters to the polls. Turning around new designs through approvals by messaging, policy, research, legal, etc., then launching those projects within a few days or often a few hours was the single largest challenge. Both Design and Dev had a team of Producers who managed those requests, assigned them to relevant staff and saw them through completion.</p><blockquote><p> The biggest challenge [...] was the shear volume of requests we got each day.</p></blockquote><hr
/><div
class="question"><h4><span>Q</span> How did the campaign approach A/B testing and data-driven design decision-making?</h4></div><p>One of the things that has been said often about the campaign is that we were data driven. This couldn&#8217;t be more true. My deputy Kyle Rush oversaw an optimization working group consisting of developers, designers, user experience engineers, data analysts, online ad specialists and content writers. We used a mix of approaches, mostly focused on <a
href="https://www.optimizely.com/">Optimizely</a> for A/B testing to prove (and disprove, often) theses about how pages could perform better.</p><div
class="tutorial_image"> <a
href="https://www.optimizely.com/"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2160_obamaWebsite/optimizely.jpg" alt="Optimizely"></a></div><p>Our traffic levels meant we could run multiple tests per day to significant levels. A weekly report was compiled with updated best practices and recommendations based on those findings. We estimate that we achieved about $125 million in incremental improvements to our fundraising pages alone.</p><hr
/><div
class="question"><h4><span>Q</span> Can you give us a simple run-down of the stack, from back to front?</h4></div><p>There wasn&#8217;t a single stack. One of the smartest things we did was run dozens of decoupled systems tied together with JavaScript and <a
href="http://www.akamai.com/">Akamai</a> services. Broadly, our stack ran on <a
href="http://aws.amazon.com/">Amazon Web Services</a>, including thousands of EC2 instances, several large database clusters and S3 hosting. Our main site, <a
href="http://www.barackobama.com/">www.barackobama.com</a>, was an <a
href="http://expressionengine.com/">Expression Engine</a> install backed by EC2 and RDS and fronted by Akamai caching.</p><p>Akamai offloaded about 98% of all of our traffic. Additionally we used <a
href="https://github.com/mojombo/jekyll">Jekyll</a>, multiple custom apps built on <a
href="https://www.djangoproject.com/">Django</a>, <a
href="http://flask.pocoo.org/">Flask</a>, <a
href="http://rubyonrails.org/">Rails</a> and <a
href="http://www.magentocommerce.com/">Magento</a>. Our widest-used language was <a
href="http://www.python.org/">Python</a>.</p><blockquote><p>One of the smartest things we did was run dozens of decoupled systems tied together with JavaScript and Akamai services.</p></blockquote><hr
/><div
class="question"><h4><span>Q</span> What are some of the open-source tools OFA used during the campaign? What was the production/deployment strategy?</h4></div><p>On the client-side, we rolled our own CSS grid and core styles along with <a
href="http://jquery.com">jQuery</a>, <a
href="http://modernizr.com">Modernizr</a> and a core JavaScript library that lazy loaded modules as needed. We used <a
href="https://github.com/janl/mustache.js/">Mustache.js</a> templates quite a bit for browser-based apps. As the first responsive website for a national campaign, we tried out a lot of open source tools for making mobile experiences better. <a
href="http://fitvidsjs.com/">Fitvids.js</a> was one of the heaviest used. Internally, we worked in <a
href="http://lesscss.org/">LESS CSS</a>, compiled by <a
href="http://incident57.com/codekit/">CodeKit</a>. One of the devs showed me LESS while we were overhauling the site in October 2011; by the end of the day, the whole site had switched to it. This is just one example of how we stayed open to better approaches every day and weren&#8217;t scared to embrace a new method or system if it made sense.</p><p>We ran <a
href="http://git-scm.com/">git</a> as our VCS of choice, for all the obvious reasons. All of our code went through <a
href="https://github.com/">Github</a>, which also served as our main code management flow. We were heavily guided by the principles of <a
href="http://zachholman.com/talk/how-github-uses-github-to-build-github">&#8220;How Github Uses Github to Build Github&#8221;</a>. Wherever it made sense, our flow was:</p><ul><li>branch locally</li><li>set a Git tag on the repo once the code was ready for review and testing</li><li>deploy the tag to staging servers</li><li>code review and QA</li><li>once the code was production ready, set up a pull request to the master branch</li><li>pull requests were reviewed by lead developers or senior developers; static assets were deployed to S3, while server-side code required a deploy request to our DevOps team</li><li>the DevOps team used Puppet and Gippetto to create apk distros for the Linux boxes</li><li>small code changes would get deployed on the fly; large ones would get built out under new server clusters, tested internally and then swapped in place of the old version</li></ul><p>We didn&#8217;t get to use this flow everywhere we would have liked, because we came into a working system, rather than starting from scratch. When I arrived in August 2011, there were no dev or staging environments for our main site, for instance. We got a staging system in place pretty quickly, but always struggled to have local dev environments for Expression Engine.</p><hr
/><div
class="question"><h4><span>Q</span> Where did design ideas originate? What was the process of taking an idea from birth to deployment?</h4></div><p>Design ideas largely came from the Design team directly. Josh Higgins, our Design Director, and I worked very hard to make sure our teams collaborated continuously. We sat in our own section of the office, along with the program/project managers, so we could keep the two teams working physically near each other. Many of the designs we rolled out started by a designer or developer finding a cool idea somewhere and emailing it around to the two teams. These ideas then became the vernacular we would talk in when trying to come up with a specific concept. As with everything else, though, data was our guide. No matter how cool we thought something was, if the data showed it wasn&#8217;t getting the results we wanted, we would try another approach.</p><blockquote><p>Many of the designs we rolled out started by a designer or developer finding a cool idea somewhere and emailing it around to the two teams. These ideas then became the vernacular we would talk in when trying to come up with a specific concept.</p></blockquote><p>The process was much like any good digital agency. We&#8217;d have a kickoff meeting with PMs, Producers, Leads, etc. to figure out the scope of a project. Someone would send around the notes from that, and we&#8217;d all tweak them for a bit then send up to our leadership to get sign off on the direction we wanted to go in. After incorporating feedback, either a designer would begin comps or, for more complicated projects, a developer would begin prototypes. The assigned developer and designer would iterate through those until the project was live and ready for testing. Normally, we would send the staging version around for approvals at the same time the QA team was doing cross-browser testing. The team would iterate on the notes from both and then we&#8217;d launch. Keep in mind that near the end of the summer, we were doing this on a dozen projects or more simultaneously. Many times, we&#8217;d do this whole cycle in a single day.</p><hr
/><div
class="question"><h4><span>Q</span> We have read a bit about the technical issues that plagued the Romney camp throughout the campaign, including server outages and hard drive failures. What were some of the most important strategic decisions the Obama team made to avoid these problems?</h4></div><blockquote
class="pullquote"><p>I think our approach basically boiled down to pragmatic paranoia.</p></blockquote><p>This was my first campaign as a staffer, but we had many alumni from &#8217;08 with us. I think I had been in Chicago less than a week before I&#8217;d heard about <a
href="http://www.theatlantic.com/politics/archive/2012/11/orca-failed-but-so-did-obamas-2008-version-of-the-same/265077/">the failure of Houdini</a>, which was the Obama &#8217;08 system akin to Romney&#8217;s Orca. Because of the institutional experience with this voter monitoring system&#8217;s failure, we never put ourselves in a place where a single system failure could do real damage. We had the luxury of time, which we used in part to build redundancies. Our payment processor, for instance, was actually one in-house system and one vendor system that Akamai flipped between automatically if one side went down. That system worked so well we replicated it for polling places. We had two APIs, one internal and one powered by Google, with a thin PHP app to make the output the same. Not only could Akamai automatically fail between them without the end user noticing, but we had a system in place where we could choose which states used which system proactively. This let us prevent a traffic spike outage. The systems we relied upon specifically for Election Day all had two backup systems: one powered by Google Doc spreadsheets and one consisting of printed hard-copies of critical data. I think our approach basically boiled down to pragmatic paranoia.</p><hr
/><div
class="question"><h4><span>Q</span> How did responsive design play a role in the Obama strategic team? Was the design &#8220;mobile first&#8221;?</h4></div><div
class="tutorial_image"> <img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2160_obamaWebsite/obama-responsive.jpg" alt="Responsive Obama Website"></div><p>Early on, the campaign tried making a <a
href="http://jquerymobile.com/">jQuery Mobile</a> powered site, but maintaining two templates for everything simply wasn&#8217;t going to scale. We were seeing 25% of our traffic come from mobile devices, but almost none of our donations. When we set out to do a site overhaul in Fall 2011, it was a foregone conclusion we would do mobile-first, responsive/adaptive. It was a learning process for all of us. If there&#8217;s one takeaway I would really stress, mobile-first doesn&#8217;t mean starting with a 320 pixel wide design, it means starting with a low bandwidth experience. We learned that lesson over and over throughout the course of the campaign. Mobile first is a comprehensive approach including content creation that is mobile friendly, design that is flexible and code that is as lean as possible.</p><blockquote><p>Mobile-first doesn&#8217;t mean starting with a 320 pixel wide design, it means starting with a low bandwidth experience.</p></blockquote><hr
/><div
class="question"><h4><span>Q</span> What was the biggest lesson to be learned about large-scale deployment?</h4></div><p>The biggest lesson I learned about large-scale deployment is hire smart people. When you&#8217;re trying to tune for scale, especially in the hockey stick curve we knew we were going to have, you need people at every part of the stack thinking about how to be more efficient. Most of my team had no experience at the kind of scale we wound up working at, but we learned quickly and adapted.</p><hr
/><div
class="question"><h4><span>Q</span> What was the general management structure of projects for the Obama team?</h4></div><blockquote
class="pullquote"><p>I truly believe that this is the last presidential campaign where the &#8220;Internet people&#8221; will be separated into their own group.</p></blockquote><p>The structure varied by project, but our overall structure was basically divided into those three buckets I mentioned before: fundraising, persuasion and turning out voters. Internally, there was a Digital Department, which my team was part of along with Design, Online Ads, Social, Email, Content, Digital Analytics, Program Managers, Video, Online Organizing, Rapid Response and our management team. Generally speaking, we handled all the public-facing work of the campaign online. Additionally, the Tech Department was responsible for the infrastructure (our DevOps team) and the server-side code for virtually everything we did. There was some crossover between the two departments as well. A large part of my role was coordinating with Tech and DevOps as we constantly deployed more and more systems.</p><p>I truly believe that this is the last presidential campaign where the &#8220;Internet people&#8221; will be separated into their own group. Our work covered every area of the campaign at some point. 2016 should be much more of a matrix org chart than a hierarchical one.</p><hr
/><h2>In Closing</h2><p>Thanks again to Daniel for agreeing to speak with us. To stay up to date, be sure to <a
href="http://twitter.com/dryan">follow him on Twitter</a>, and keep an eye on <a
href="http://dryan.com/">his website.</a></p><div
class="tutorial_image"> <a
href="http://dryan.com/"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2160_obamaWebsite/daniel-ryan-website.jpg" alt="Daniel Ryan"></a></div>
<p><a href="http://feedads.g.doubleclick.net/~a/wb3Qu70ev66MCPsvXuMzDRjdBkQ/0/da"><img src="http://feedads.g.doubleclick.net/~a/wb3Qu70ev66MCPsvXuMzDRjdBkQ/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/wb3Qu70ev66MCPsvXuMzDRjdBkQ/1/da"><img src="http://feedads.g.doubleclick.net/~a/wb3Qu70ev66MCPsvXuMzDRjdBkQ/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=fXfSHsKc6j4:8ObdbLIuUnA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=fXfSHsKc6j4:8ObdbLIuUnA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=fXfSHsKc6j4:8ObdbLIuUnA:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=fXfSHsKc6j4:8ObdbLIuUnA:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=fXfSHsKc6j4:8ObdbLIuUnA:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=fXfSHsKc6j4:8ObdbLIuUnA:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=fXfSHsKc6j4:8ObdbLIuUnA:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=fXfSHsKc6j4:8ObdbLIuUnA:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/fXfSHsKc6j4" height="1" width="1"/>";s:14:"date_timestamp";i:1353941677;}i:2;a:13:{s:5:"title";s:69:"How to Add Custom Configuration Settings for an (ASP).NET Application";s:4:"link";s:54:"http://feedproxy.google.com/~r/nettuts/~3/2aVOu3wGcGI/";s:8:"comments";s:121:"http://net.tutsplus.com/tutorials/asp-net/how-to-add-custom-configuration-settings-for-your-asp-net-application/#comments";s:7:"pubdate";s:31:"Sat, 24 Nov 2012 16:23:33 +0000";s:2:"dc";a:1:{s:7:"creator";s:13:"Jeremy McPeak";}s:8:"category";s:11:"ASP.NET.net";s:4:"guid";s:31:"http://net.tutsplus.com/?p=9590";s:11:"description";s:28257:"<a
href='http://rss.buysellads.com/click.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=9590&c=1829150769' target='_blank'><img
src='http://rss.buysellads.com/img.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=9590&c=1829150769' border='0' alt='' /></a><p>Since its release, ASP.NET applications and components have looked to the web.config file to load any settings they need to function. However, adding custom settings to add flexibility and robustness to an application or component isn&#8217;t as straight forward as most would like. This article teaches you how to write the necessary classes to handle XML configuration elements and use the settings they contain within your code.</p><p><span
id="more-9590"></span></p> November, 2012<p>The .NET Framework provides a wide variety of settings that can be configured within web.config to modify the behavior of one or more built-in components within the application. For some developers, sticking solely with the settings provided by the .NET Framework is sufficient. But many more developers find they need to control a broader collection of settings &#8211; either for components (written by themselves or a third party), or simply a set of values they find themselves using throughout their application.</p><p>The web.config file does allow you to set custom settings with the &lt;appSettings/&gt; element, but it doesn&#8217;t allow anything other than simple key/value pairs. The following XML element is an example of a setting contained within &lt;appSettings/&gt;:</p><pre class="xml" name="code">&lt;add key=&quot;myKey&quot; value=&quot;myValue&quot;/&gt;</pre><p>Key/Value settings certainly can be helpful in many circumstances, but &lt;appSettings/&gt; settings simply aren&#8217;t flexible enough for robust or complex components or settings.</p><p>Thankfully, Microsoft enables developers to write classes that add programmatic access to custom configuration settings contained within web.config.</p><hr
/><h2>The Configuration Section</h2><p>Settings within web.config are categorized into configuration sections. For example, the settings contained within the <code>&lt;system.web/&gt;</code> section pertains to ASP.NET settings for your application. You can change the authentication scheme of your app, as well as add or remove HTTP handlers to perform specific functions for specific file types. The &lt;system.webServer/&gt; section allows you to control many of IIS7ís settings without having direct access to IIS7.</p><p>A configuration section is required of all settings not contained within the &lt;appSettings/&gt; element. So itís a good idea to design the XML structure of your configuration settings before writing any code.</p><p>The configuration used as an example in this tutorial is for a component that retrieves RSS or Atom feeds. It doesn&#8217;t do any parsing, as that is beyond the scope of this tutorial. Instead of hard coding the list of feeds to retrieve, the component looks to its configuration to contain the names and URLs of the feeds to retrieve. The component is called FeedRetriever, and the desired XML structure of its configuration looks like this:</p><pre class="xml" name="code">&lt;feedRetriever&gt;
    &lt;feeds&gt;
        &lt;add name=&quot;Nettuts+&quot; url=&quot;http://feeds.feedburner.com/nettuts&quot; cache=&quot;false&quot;/&gt;
        &lt;add name=&quot;Jeremy McPeak&quot; url=&quot;http://www.wdonline.com/feeds/blog/rss/&quot; /&gt;
        &lt;add name=&quot;Nicholas C. Zakas&quot; url=&quot;http://feeds.nczonline.net/blog/&quot; /&gt;
    &lt;/feeds&gt;
&lt;/feedRetriever&gt;</pre><p>The &lt;feedRetriever/&gt; element defines by the configuration section. As a general rule, a configuration section should share the name of the the component it is designed for. The &lt;feedRetriever/&gt; elements only child is the &lt;feeds/&gt; element. Think of this element as a collection of feeds because it contains several &lt;add/&gt; elements (think of the Add() method that most collection objects have). The choice of using an element named &quot;add&quot; may seem strange at first, but the &lt;add/&gt; element is used throughout the majority of built-in configuration sections. So using it here simply follows the design practices put forth by Microsoft.</p><p>These &lt;add/&gt; elements use the name, url, and cache attributes to set certain settings for each feed. Naturally, the name and url attributes are required, but the cache attribute is not, and should default as true.</p><p>The above configuration is simple. The &lt;feedRetriever/&gt; element could be modified to contain another child, called &lt;globalSettings/&gt;, to contain settings that would apply to all feeds. The &lt;add/&gt; elements could also use additional attributes, such as cacheTime and requestFrequency, to control how long a feed is cached and how often it is requested from the remote host. The only limit to the extensibility and configurability is your imagination.</p><hr
/><h2>Writing the Configuration Handler</h2><p>After designing the XML structure, the next step is to write a configuration handler to process the settings defined in the XML. The handler is primarily a class that inherits from <a
title="MSDN Documentation for System.Configuration.ConfigurationSection" href="http://msdn.microsoft.com/en-us/library/system.configuration.configurationsection.aspx" target="_blank">System.Configuration.ConfigurationSection</a>, but it also incorporates the use of other classes &#8211; such as classes that derive from <a
title="MSDN Documentation for the System.Configuration.ConfigurationElement class." href="http://msdn.microsoft.com/en-us/library/system.configuration.configurationelement.aspx" target="_blank">System.Configuration.ConfigurationElement</a> and <a
title="MSDN Documentation for the System.Configuration.ConfigurationElementCollection class." href="http://msdn.microsoft.com/en-us/library/system.configuration.configurationelementcollection.aspx" target="_blank">System.Configuration.ConfigurationElementCollection</a>.</p><p>Classes based on ConfigurationElement represent individual elements; it is the building block of a configuration section. Types that derive from ConfigurationElementCollection simply represent elements that contain more than one type of element. From the configuration listed above, the &lt;feeds/&gt; element is represented by a class that derives from ConfigurationElementCollection, and the &lt;add/&gt; elements are represented by a ConfigurationElement-based class.</p><hr
/><h2>Representing the <code>&lt;add/&gt;</code> Element</h2><p>Youíll start with the &lt;add/&gt; element by representing it with a class called FeedElement (derived from ConfigurationElement). This class, and future configuration-related classes, reside in the FeedRetriever.Configuration namespace.</p><p>Every ConfigurationElement object functions as an indexer for its internal collection of property values. It is this internal collection, along with .NET attributes, that enables you to map the &lt;add/&gt; elementís attributes to the properties of the FeedElement class.</p><p>The following code is the complete code for the FeedElement class:</p><pre class="c#" name="code">public class FeedElement : ConfigurationElement
{
    [ConfigurationProperty(&quot;name&quot;, IsKey = true, IsRequired = true)]
    public string Name
    {
        get { return (string)this[&quot;name&quot;]; }
        set { this[&quot;name&quot;] = value; }
    }
    [ConfigurationProperty(&quot;url&quot;, IsRequired = true, DefaultValue = &quot;http://localhost&quot;)]
    [RegexStringValidator(@&quot;https?\://\S+&quot;)]
    public string Url
    {
        get { return (string)this[&quot;url&quot;]; }
        set { this[&quot;url&quot;] = value; }
    }
    [ConfigurationProperty(&quot;cache&quot;, IsRequired = false, DefaultValue = true)]
    public bool Cache
    {
        get { return (bool)this[&quot;cache&quot;]; }
        set { this[&quot;cache&quot;] = value; }
    }
}</pre><p>The ConfigurationElement class serves as an indexer to an underlying collection of configuration properties (hence the indexer notation of this[keyValue]). By using the this keyword and accessing the underlying property with a string key, you can get and set the property&#8217;s value without needing a private field to contain that data. The underlying property collection stores data as type Object; therefore, you have to cast the value as the appropriate type if you want to do anything with it.</p><p>The properties that represent XML attributes are decorated with <a
title="MSDN - Documention for the ConfigrationPropertyAttribute class." href="http://msdn.microsoft.com/en-us/library/system.configuration.configurationpropertyattribute.aspx" target="_blank">ConfigurationPropertyAttribute</a> attributes. The first parameter of of the ConfigurationPropertyAttribute attribute is the name of the XML attribute found within the &lt;add/&gt; element. Following the first parameter are a set of any number of named parameters. The following list is a complete list of possible parameters:</p><ul><li>DefaultValue &#8211; Gets or sets the default value for the decorated property. This parameter<br
/> is not required.</li><li>IsDefaultCollection &#8211; Gets or a sets a Boolean value indicating whether the property<br
/> is the default property collection for the decorated property. This parameter is<br
/> not required, and the default is false.</li><li>IsKey &#8211; Gets or sets a Boolean value indicating whether this property is a key property<br
/> for the decorated element property. This parameter is not required, and its default<br
/> value is false.</li><li>IsRequired &#8211; Gets or sets a Boolean value indicating whether the decorated element<br
/> property is required. This parameter is not required, and its default value is false.</li></ul><p>The default value of &quot;http://localhost&quot; for the Url property is not an error. The .NET Framework also grants you the ability to decorate the properties with validator attributes &#8211; such as the <a
title="MSDN Documentation for the RegexStringValidatorAttribute class." href="http://msdn.microsoft.com/en-us/library/system.configuration.regexstringvalidatorattribute.aspx" target="_blank">RegexStringValidatorAttribute</a> decorating the Url property. This validator takes the value of the Url property and validates it against the regular expression provided to the attribute; however, it also validates the Url property before it contains the data from the XML element. The default value of the Url property is an empty string when a FeedElement object is first created. An empty string does not validate against the provided regular expression, so the validator throws an ArgumentException before any data is loaded from the XML file.</p><p>There are two possible workarounds for this problem. The first approach modifies the regular expression to allow empty strings. The second approach assigns a default value to the property. It does not matter in this particular case. Even with a default value, the url attribute is still a required attribute in the &lt;add/&gt; element &#8211; the application throws a ConfigurationErrorsException if an &lt;add/&gt; element does not have a url attribute.</p><p>There are several other validator attributes in the System.Configuration namespace to validate data assigned to properties and the XML attributes they map to. The following lists all of the validator attributes within the System.Configuration namespace:</p><ul><li><a
title="MSDN Documentation for the CallBackValidatorAttribute class." href="http://msdn.microsoft.com/en-us/library/system.configuration.callbackvalidatorattribute.aspx" target="_blank">CallbackValidatorAttribute</a> &#8211; Provides an association between a <a
title="MSDN Documentation for the CallbackValidator class." href="http://msdn.microsoft.com/en-us/library/system.configuration.callbackvalidator.aspx" target="_blank">CallbackValidator</a> object and the code to validate &#8211; allows<br
/> dynamic validation for a configuration value.</li><li><a
title="MSDN Documentation for the IntegerValidatorAttribute class" href="http://msdn.microsoft.com/en-us/library/system.configuration.integervalidatorattribute.aspx" target="_blank">IntegerValidatorAttribute</a> &#8211; Validates using an <a
title="MSDN Documentation for the IntegerValidator class." href="http://msdn.microsoft.com/en-us/library/system.configuration.integervalidatorattribute.aspx" target="_blank">IntegerValidator</a> object to determine if the configuration value falls within or outside a specific range.</li><li> <a
title="MSDN Documentation for the LongValidatorAttribute class." href="http://msdn.microsoft.com/en-us/library/system.configuration.longvalidatorattribute.aspx" target="_blank"> LongValidatorAttribute</a> &#8211; Validates using a <a
title="MSDN Documentation for the LongValidator class." href="http://msdn.microsoft.com/en-us/library/system.configuration.longvalidator.aspx" target="_blank">LongValidator</a> object to determine if the configuration value falls within or outside a specific range.</li><li><a
title="MSDN Documentation for the PositiveTimeSpanValidatorAttribute class." href="http://msdn.microsoft.com/en-us/library/system.configuration.positivetimespanvalidatorattribute.aspx" target="_blank">PositiveTimeSpanValidatorAttribute</a> &#8211; Validates using a <a
title="MSDN Documentation for the PositiveTimeSpanValidator class." href="http://msdn.microsoft.com/en-us/library/system.configuration.positivetimespanvalidator.aspx" target="_blank">PositiveTimeSpanValidator</a> object for positive TimeSpan configuration values.</li><li><a
title="MSDN Documentation for the RegexStringValidatorAttribute class." href="http://msdn.microsoft.com/en-us/library/system.configuration.regexstringvalidatorattribute.aspx" target="_blank">RegexStringValidatorAttribute</a> &#8211; Validates using a <a
title="MSDN Documentation for the RegexStringValidator class." href="http://msdn.microsoft.com/en-us/library/system.configuration.regexstringvalidator.aspx" target="_blank">RegexStringValidator</a> object to determine if the configuration value adheres to the the regular expression.</li><li><a
title="MSDN Documentation for the StringValidatorAttribute class." href="http://msdn.microsoft.com/en-us/library/system.configuration.stringvalidatorattribute.aspx" target="_blank">StringValidatorAttribute</a> &#8211; Validates using a <a
title="MSDN Documetation for the StringValidator class." href="http://msdn.microsoft.com/en-us/library/system.configuration.stringvalidator.aspx" target="_blank">StringValidator</a> object to ensure the configuration value meets certain criteria &#8211; such as string length and invalid characters.</li><li><a
title="MSDN Documentation for the SubclassTypeValidatorAttribute class." href="http://msdn.microsoft.com/en-us/library/system.configuration.subclasstypevalidatorattribute.aspx" target="_blank">SubclassTypeValidatorAttribute</a> &#8211; Validates using a <a
title="MSDN Documentation for the SubclassTypeValidator class." href="http://msdn.microsoft.com/en-us/library/system.configuration.subclasstypevalidator.aspx" target="_blank">SubclassTypeValidator</a> object to determine if the configuration value derives of a given type.</li><li><a
title="MSDN Documentation for the TimeSpanValidatorAttribute class." href="http://msdn.microsoft.com/en-us/library/system.configuration.timespanvalidatorattribute.aspx" target="_blank">TimeSpanValidatorAttribute</a> &#8211; Validates using a <a
title="MSDN Documentation for the TimeSpanValidator class." href="http://msdn.microsoft.com/en-us/library/system.configuration.timespanvalidator.aspx" target="_blank">TimeSpanValidator</a> object to determine if the configuration value is falls within or outside a specific range.</li></ul><p>With the exception of the CallbackValidatorAttribute, you do not have to create corresponding validator objects to use in conjunction with the validator attributes. The .NET runtime creates the appropriate validator objects for you, and the attributes contain the needed parameters to configure the validator objects.</p><p>This small bit of code is all that is required to programmatically represent individual &lt;add/&gt; elements. The next step is to write a class that represents the &lt;feeds/&gt; element.</p><hr
/><h2>Writing an Element Collection Class</h2><p>The XML representation of the &lt;feeds/&gt; element is that of a collection of feed elements. Likewise, the programmatic representation of the &lt;feeds/&gt; element is a collection of FeedElement objects. This class, called FeedElementCollection, derives from the abstract ConfigurationElementCollection class.</p><p>The ConfigurationElementCollection class contains several members, but only two are marked as abstract. Thus, the simplest ConfigurationElementCollection implementation has two methods:</p><ul><li>CreateNewElement() &#8211; Creates a new ConfigurationElement object (FeedElement in this<br
/> case).</li><li>GetElementKey() &#8211; Gets the element key for a specified configuration element (the<br
/> Name property of FeedElement objects in this case).</li></ul><p>With that in mind, view the complete code for the FeedElementCollection class below:</p><pre class="c#" name="code">[ConfigurationCollection(typeof(FeedElement))]
public class FeedElementCollection : ConfigurationElementCollection
{
    protected override ConfigurationElement CreateNewElement()
    {
        return new FeedElement();
    }
    protected override object GetElementKey(ConfigurationElement element)
    {
        return ((FeedElement)element).Name;
    }
}</pre><p>A <a
title="MSDN Documentation for the ConfigurationCollectionAttribute class." href="http://msdn.microsoft.com/en-us/library/system.configuration.configurationcollectionattribute.aspx" target="_blank">ConfigurationCollectionAttribute</a> decorates this collection class. The first parameter to the attribute is a Type object &#8211; the type of the items the collection contains. In this case, it&#8217;s the FeedElement type. After the type parameter are several named parameters you can pass to the attribute. These are listed below:</p><ul><li>AddItemName &#8211; Sets the name of the &lt;add/&gt; configuration element. For example,<br
/> setting this as &quot;feed&quot; would require the &lt;add/&gt; elements in the<br
/> configuration to be changed to &lt;feed/&gt;.</li><li>ClearItemsName &#8211; Sets the name of the &lt;clear/&gt; configuration element (used<br
/> to clear all items from the collection).</li><li>RemoveItemName &#8211; Sets the name for the &lt;remove/&gt; configuration element (used<br
/> to remove an item from the collection).</li></ul><p>Leaving these named parameters blank defaults them to &lt;add/&gt;, &lt;clear/&gt;, &lt;remove/&gt;.</p><hr
/><h2>Writing the FeedRetreiverSection Class</h2><p>The final class, called FeedRetrieverSection, derives from ConfigurationSection and represents the &lt;feedRetriever/&gt; element. This is the simplest class of the configuration classes, as the only requirement it must meet is to provide programmatic access to the &lt;feeds/&gt; element (the FeedElementCollection).</p><pre class="c#" name="code">public class FeedRetrieverSection : ConfigurationSection
{
    [ConfigurationProperty(&quot;feeds&quot;, IsDefaultCollection = true)]
    public FeedElementCollection Feeds
    {
        get { return (FeedElementCollection)this[&quot;feeds&quot;]; }
        set { this[&quot;feeds&quot;] = value; }
    }
}</pre><p>It&#8217;s one property, of type FeedElementCollection and called Feeds, is decorated with a ConfigurationPropertyAttribute &#8211; mapping it to the &lt;feeds/&gt; element.</p><hr
/><h2>Modifying web.config</h2><p>With the configuration handler complete, you can add the appropriate elements to web.config. The &lt;feedRetriever/&gt; section can go anywhere in the file as long as itís a direct descendent of the root element (the &lt;configuration/&gt; element). Placing it within another configuration section results in an error.</p><p>The next step is adding a &lt;section/&gt; child element to &lt;configSections/&gt;. The &lt;section/&gt; element has two attributes of interest:</p><ul><li>name &#8211; The name of the configuration section element. In this case, name is feedRetriever.</li><li>type &#8211; The qualified name of the class associated with the section, and if necessary,<br
/> the name of the assembly the class resides in. In this case, the qualified name<br
/> is FeedRetriever.Configuration.FeedRetrieverSection. If it resides in a separate<br
/> assembly, the type attribute would have a value of &quot;FeedRetriever.Configuration.FeedRetrieverSection,<br
/> &lt;assemblyName&gt;&quot;, where &lt;assemblyName&gt; is the name of the assembly<br
/> without the angle brackets.</li></ul><p>The following &lt;section/&gt; element is what you add to a web.config file, under &lt;configSections/&gt;, when the configuration classes do not reside in a separate assembly (as is the case in the code download):</p><pre class="xml" name="code">&lt;section name=&quot;feedRetriever&quot; type=&quot;FeedRetriever.Configuration.FeedRetrieverSection&quot;/&gt;</pre><p>Now your application is properly configured to use the FeedRetrieverSection, FeedElementCollection, and FeedElement classes to grant you programmatic access to the custom settings contained within the &lt;feedRetriever/&gt; configuration section in web.config. So how do you access these settings from within your code?</p><hr
/><h2>Accessing Configuration Data from Code</h2><p>The System.Configuration namespace contains a static class called ConfigurationManager. If you use the &lt;connectionStrings/&gt; section to house your connection strings, you are at least familiar with ConfigurationManager. It has a method called GetSection(), which accepts a string containing the name of the configuration section to retrieve. The following code demonstrates this (assume using System.Configuration is at the top of the code file):</p><pre class="c#" name="code">FeedRetrieverSection config = ConfigurationManager.GetSection(&quot;feedRetriever&quot;) as FeedRetrieverSection;</pre><p>The GetSection() method returns a value of type Object, so it must be cast to whatever type the handler is for that section. This code retrieves the section named feedRetriever and casts the result as FeedRetrieverSection. Once you have the object, you can start accessing configuration data programmatically.</p><p>To give you an idea of how configuration settings can be used within your component or application, the following code is a very basic implementation of the FeedRetriever component.</p><pre class="c#" name="code">public class FeedRetriever
{
    public static FeedRetrieverSection _Config =
        ConfigurationManager.GetSection(&quot;feedRetriever&quot;) as FeedRetrieverSection;
<br />
    public static void GetFeeds()
    {
        foreach (FeedElement feedEl in _Config.Feeds)
        {
            // make request
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(feedEl.Url);
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            if (response.StatusCode == HttpStatusCode.OK)
            {
                string feedData = String.Empty;
                using (StreamReader reader =
                             new StreamReader(response.GetResponseStream()))
                {
                    feedData = reader.ReadToEnd();
                }
                if (feedEl.Cache)
                {
                    // filename of cache file
                    string filename = String.Format(&quot;{0}_{1}.xml&quot;,
                                            feedEl.Name, DateTime.Now.Ticks);
                    // cache file
                    using (StreamWriter writer =
                             new StreamWriter(@&quot;C:\&quot; + filename))
                    {
                        writer.Write(feedData);
                    }
                }
            }
        }
    }
}</pre><p>First, a static variable called _Config, of type FeedRetreiverSection, is declared and assigned a value by calling ConfigurationManager.GetSection(). Making the variable static is a design choice. By doing so, all members of the class, either instance or static, would have access to the configuration settings without having to make multiple calls to GetSection().</p><p>Once you retrieve the section handler with GetSection(), you have complete access to objects created from your handler classes. The first line of GetFeeds() is a for each loop that loops through all FeedElement objects contained with the FeedElementCollection object returned by the Feeds property. This gives you direct access to those FeedElement objects &#8211; making it easy to access each feed&#8217;s name, URL, and cache settings.</p><p>During each iteration of the loop, the method makes a request using the FeedElement objectís Url property. If the request results in a success, the feedís data is retrieved and stored in the feedData variable. Then the code checks the FeedElement objectís Cache property to determine whether or not to cache the feed. Caching the the feed involves constructing a filename by using the FeedElement objectís Name property and the current date and time. Then a StreamWriter object creates the file and writes the feedís data to it.</p><p>As you can see, using the configuration section handler classes is key to retrieving and using custom settings residing in web.config. It certainly requires more time and effort from you, but it definitely makes your application or component much easier to configure for yourself and other developers.</p><hr
/><h2>Sell your .NET Components on CodeCanyon!</h2><div
class="tutorial_image"> <a
href="http://codecanyon.net"><br
/> <img
src="http://envato.s3.amazonaws.com/referrer_adverts/cc_728x90_v2.gif" alt="CodeCanyon" style="width: 600px;" /><br
/> </a></div><p><strong>Did you know that we have a <a
href="http://codecanyon.net/category/net">.NET category</a> on <a
href="http://codecanyon.net/">CodeCanyon</a>. If you&#8217;re a skilled .NET dev, why not sell your scripts/components/controls as an author, and <a
href="http://codecanyon.net/wiki/selling/author-selling/author-program/">earn 40-70% of every sale</a>?</strong></p><ul
class="webroundup"><li>Follow us on <a
href="http://www.twitter.com/nettuts">Twitter</a>, or subscribe to the <a
href="http://feeds.feedburner.com/nettuts" title="Nettuts+ RSS Feed">Nettuts+ RSS Feed</a> for the best web development tutorials on the web.</li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/DzwiQ1C88Is6heDH1KLLKpZwo5c/0/da"><img src="http://feedads.g.doubleclick.net/~a/DzwiQ1C88Is6heDH1KLLKpZwo5c/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/DzwiQ1C88Is6heDH1KLLKpZwo5c/1/da"><img src="http://feedads.g.doubleclick.net/~a/DzwiQ1C88Is6heDH1KLLKpZwo5c/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=2aVOu3wGcGI:fC_1aCG_c_o:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=2aVOu3wGcGI:fC_1aCG_c_o:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=2aVOu3wGcGI:fC_1aCG_c_o:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=2aVOu3wGcGI:fC_1aCG_c_o:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=2aVOu3wGcGI:fC_1aCG_c_o:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=2aVOu3wGcGI:fC_1aCG_c_o:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=2aVOu3wGcGI:fC_1aCG_c_o:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=2aVOu3wGcGI:fC_1aCG_c_o:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/2aVOu3wGcGI" height="1" width="1"/>";s:3:"wfw";a:1:{s:10:"commentrss";s:117:"http://net.tutsplus.com/tutorials/asp-net/how-to-add-custom-configuration-settings-for-your-asp-net-application/feed/";}s:5:"slash";a:1:{s:8:"comments";s:2:"33";}s:10:"feedburner";a:1:{s:8:"origlink";s:112:"http://net.tutsplus.com/tutorials/asp-net/how-to-add-custom-configuration-settings-for-your-asp-net-application/";}s:7:"summary";s:28257:"<a
href='http://rss.buysellads.com/click.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=9590&c=1829150769' target='_blank'><img
src='http://rss.buysellads.com/img.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=9590&c=1829150769' border='0' alt='' /></a><p>Since its release, ASP.NET applications and components have looked to the web.config file to load any settings they need to function. However, adding custom settings to add flexibility and robustness to an application or component isn&#8217;t as straight forward as most would like. This article teaches you how to write the necessary classes to handle XML configuration elements and use the settings they contain within your code.</p><p><span
id="more-9590"></span></p> November, 2012<p>The .NET Framework provides a wide variety of settings that can be configured within web.config to modify the behavior of one or more built-in components within the application. For some developers, sticking solely with the settings provided by the .NET Framework is sufficient. But many more developers find they need to control a broader collection of settings &#8211; either for components (written by themselves or a third party), or simply a set of values they find themselves using throughout their application.</p><p>The web.config file does allow you to set custom settings with the &lt;appSettings/&gt; element, but it doesn&#8217;t allow anything other than simple key/value pairs. The following XML element is an example of a setting contained within &lt;appSettings/&gt;:</p><pre class="xml" name="code">&lt;add key=&quot;myKey&quot; value=&quot;myValue&quot;/&gt;</pre><p>Key/Value settings certainly can be helpful in many circumstances, but &lt;appSettings/&gt; settings simply aren&#8217;t flexible enough for robust or complex components or settings.</p><p>Thankfully, Microsoft enables developers to write classes that add programmatic access to custom configuration settings contained within web.config.</p><hr
/><h2>The Configuration Section</h2><p>Settings within web.config are categorized into configuration sections. For example, the settings contained within the <code>&lt;system.web/&gt;</code> section pertains to ASP.NET settings for your application. You can change the authentication scheme of your app, as well as add or remove HTTP handlers to perform specific functions for specific file types. The &lt;system.webServer/&gt; section allows you to control many of IIS7ís settings without having direct access to IIS7.</p><p>A configuration section is required of all settings not contained within the &lt;appSettings/&gt; element. So itís a good idea to design the XML structure of your configuration settings before writing any code.</p><p>The configuration used as an example in this tutorial is for a component that retrieves RSS or Atom feeds. It doesn&#8217;t do any parsing, as that is beyond the scope of this tutorial. Instead of hard coding the list of feeds to retrieve, the component looks to its configuration to contain the names and URLs of the feeds to retrieve. The component is called FeedRetriever, and the desired XML structure of its configuration looks like this:</p><pre class="xml" name="code">&lt;feedRetriever&gt;
    &lt;feeds&gt;
        &lt;add name=&quot;Nettuts+&quot; url=&quot;http://feeds.feedburner.com/nettuts&quot; cache=&quot;false&quot;/&gt;
        &lt;add name=&quot;Jeremy McPeak&quot; url=&quot;http://www.wdonline.com/feeds/blog/rss/&quot; /&gt;
        &lt;add name=&quot;Nicholas C. Zakas&quot; url=&quot;http://feeds.nczonline.net/blog/&quot; /&gt;
    &lt;/feeds&gt;
&lt;/feedRetriever&gt;</pre><p>The &lt;feedRetriever/&gt; element defines by the configuration section. As a general rule, a configuration section should share the name of the the component it is designed for. The &lt;feedRetriever/&gt; elements only child is the &lt;feeds/&gt; element. Think of this element as a collection of feeds because it contains several &lt;add/&gt; elements (think of the Add() method that most collection objects have). The choice of using an element named &quot;add&quot; may seem strange at first, but the &lt;add/&gt; element is used throughout the majority of built-in configuration sections. So using it here simply follows the design practices put forth by Microsoft.</p><p>These &lt;add/&gt; elements use the name, url, and cache attributes to set certain settings for each feed. Naturally, the name and url attributes are required, but the cache attribute is not, and should default as true.</p><p>The above configuration is simple. The &lt;feedRetriever/&gt; element could be modified to contain another child, called &lt;globalSettings/&gt;, to contain settings that would apply to all feeds. The &lt;add/&gt; elements could also use additional attributes, such as cacheTime and requestFrequency, to control how long a feed is cached and how often it is requested from the remote host. The only limit to the extensibility and configurability is your imagination.</p><hr
/><h2>Writing the Configuration Handler</h2><p>After designing the XML structure, the next step is to write a configuration handler to process the settings defined in the XML. The handler is primarily a class that inherits from <a
title="MSDN Documentation for System.Configuration.ConfigurationSection" href="http://msdn.microsoft.com/en-us/library/system.configuration.configurationsection.aspx" target="_blank">System.Configuration.ConfigurationSection</a>, but it also incorporates the use of other classes &#8211; such as classes that derive from <a
title="MSDN Documentation for the System.Configuration.ConfigurationElement class." href="http://msdn.microsoft.com/en-us/library/system.configuration.configurationelement.aspx" target="_blank">System.Configuration.ConfigurationElement</a> and <a
title="MSDN Documentation for the System.Configuration.ConfigurationElementCollection class." href="http://msdn.microsoft.com/en-us/library/system.configuration.configurationelementcollection.aspx" target="_blank">System.Configuration.ConfigurationElementCollection</a>.</p><p>Classes based on ConfigurationElement represent individual elements; it is the building block of a configuration section. Types that derive from ConfigurationElementCollection simply represent elements that contain more than one type of element. From the configuration listed above, the &lt;feeds/&gt; element is represented by a class that derives from ConfigurationElementCollection, and the &lt;add/&gt; elements are represented by a ConfigurationElement-based class.</p><hr
/><h2>Representing the <code>&lt;add/&gt;</code> Element</h2><p>Youíll start with the &lt;add/&gt; element by representing it with a class called FeedElement (derived from ConfigurationElement). This class, and future configuration-related classes, reside in the FeedRetriever.Configuration namespace.</p><p>Every ConfigurationElement object functions as an indexer for its internal collection of property values. It is this internal collection, along with .NET attributes, that enables you to map the &lt;add/&gt; elementís attributes to the properties of the FeedElement class.</p><p>The following code is the complete code for the FeedElement class:</p><pre class="c#" name="code">public class FeedElement : ConfigurationElement
{
    [ConfigurationProperty(&quot;name&quot;, IsKey = true, IsRequired = true)]
    public string Name
    {
        get { return (string)this[&quot;name&quot;]; }
        set { this[&quot;name&quot;] = value; }
    }
    [ConfigurationProperty(&quot;url&quot;, IsRequired = true, DefaultValue = &quot;http://localhost&quot;)]
    [RegexStringValidator(@&quot;https?\://\S+&quot;)]
    public string Url
    {
        get { return (string)this[&quot;url&quot;]; }
        set { this[&quot;url&quot;] = value; }
    }
    [ConfigurationProperty(&quot;cache&quot;, IsRequired = false, DefaultValue = true)]
    public bool Cache
    {
        get { return (bool)this[&quot;cache&quot;]; }
        set { this[&quot;cache&quot;] = value; }
    }
}</pre><p>The ConfigurationElement class serves as an indexer to an underlying collection of configuration properties (hence the indexer notation of this[keyValue]). By using the this keyword and accessing the underlying property with a string key, you can get and set the property&#8217;s value without needing a private field to contain that data. The underlying property collection stores data as type Object; therefore, you have to cast the value as the appropriate type if you want to do anything with it.</p><p>The properties that represent XML attributes are decorated with <a
title="MSDN - Documention for the ConfigrationPropertyAttribute class." href="http://msdn.microsoft.com/en-us/library/system.configuration.configurationpropertyattribute.aspx" target="_blank">ConfigurationPropertyAttribute</a> attributes. The first parameter of of the ConfigurationPropertyAttribute attribute is the name of the XML attribute found within the &lt;add/&gt; element. Following the first parameter are a set of any number of named parameters. The following list is a complete list of possible parameters:</p><ul><li>DefaultValue &#8211; Gets or sets the default value for the decorated property. This parameter<br
/> is not required.</li><li>IsDefaultCollection &#8211; Gets or a sets a Boolean value indicating whether the property<br
/> is the default property collection for the decorated property. This parameter is<br
/> not required, and the default is false.</li><li>IsKey &#8211; Gets or sets a Boolean value indicating whether this property is a key property<br
/> for the decorated element property. This parameter is not required, and its default<br
/> value is false.</li><li>IsRequired &#8211; Gets or sets a Boolean value indicating whether the decorated element<br
/> property is required. This parameter is not required, and its default value is false.</li></ul><p>The default value of &quot;http://localhost&quot; for the Url property is not an error. The .NET Framework also grants you the ability to decorate the properties with validator attributes &#8211; such as the <a
title="MSDN Documentation for the RegexStringValidatorAttribute class." href="http://msdn.microsoft.com/en-us/library/system.configuration.regexstringvalidatorattribute.aspx" target="_blank">RegexStringValidatorAttribute</a> decorating the Url property. This validator takes the value of the Url property and validates it against the regular expression provided to the attribute; however, it also validates the Url property before it contains the data from the XML element. The default value of the Url property is an empty string when a FeedElement object is first created. An empty string does not validate against the provided regular expression, so the validator throws an ArgumentException before any data is loaded from the XML file.</p><p>There are two possible workarounds for this problem. The first approach modifies the regular expression to allow empty strings. The second approach assigns a default value to the property. It does not matter in this particular case. Even with a default value, the url attribute is still a required attribute in the &lt;add/&gt; element &#8211; the application throws a ConfigurationErrorsException if an &lt;add/&gt; element does not have a url attribute.</p><p>There are several other validator attributes in the System.Configuration namespace to validate data assigned to properties and the XML attributes they map to. The following lists all of the validator attributes within the System.Configuration namespace:</p><ul><li><a
title="MSDN Documentation for the CallBackValidatorAttribute class." href="http://msdn.microsoft.com/en-us/library/system.configuration.callbackvalidatorattribute.aspx" target="_blank">CallbackValidatorAttribute</a> &#8211; Provides an association between a <a
title="MSDN Documentation for the CallbackValidator class." href="http://msdn.microsoft.com/en-us/library/system.configuration.callbackvalidator.aspx" target="_blank">CallbackValidator</a> object and the code to validate &#8211; allows<br
/> dynamic validation for a configuration value.</li><li><a
title="MSDN Documentation for the IntegerValidatorAttribute class" href="http://msdn.microsoft.com/en-us/library/system.configuration.integervalidatorattribute.aspx" target="_blank">IntegerValidatorAttribute</a> &#8211; Validates using an <a
title="MSDN Documentation for the IntegerValidator class." href="http://msdn.microsoft.com/en-us/library/system.configuration.integervalidatorattribute.aspx" target="_blank">IntegerValidator</a> object to determine if the configuration value falls within or outside a specific range.</li><li> <a
title="MSDN Documentation for the LongValidatorAttribute class." href="http://msdn.microsoft.com/en-us/library/system.configuration.longvalidatorattribute.aspx" target="_blank"> LongValidatorAttribute</a> &#8211; Validates using a <a
title="MSDN Documentation for the LongValidator class." href="http://msdn.microsoft.com/en-us/library/system.configuration.longvalidator.aspx" target="_blank">LongValidator</a> object to determine if the configuration value falls within or outside a specific range.</li><li><a
title="MSDN Documentation for the PositiveTimeSpanValidatorAttribute class." href="http://msdn.microsoft.com/en-us/library/system.configuration.positivetimespanvalidatorattribute.aspx" target="_blank">PositiveTimeSpanValidatorAttribute</a> &#8211; Validates using a <a
title="MSDN Documentation for the PositiveTimeSpanValidator class." href="http://msdn.microsoft.com/en-us/library/system.configuration.positivetimespanvalidator.aspx" target="_blank">PositiveTimeSpanValidator</a> object for positive TimeSpan configuration values.</li><li><a
title="MSDN Documentation for the RegexStringValidatorAttribute class." href="http://msdn.microsoft.com/en-us/library/system.configuration.regexstringvalidatorattribute.aspx" target="_blank">RegexStringValidatorAttribute</a> &#8211; Validates using a <a
title="MSDN Documentation for the RegexStringValidator class." href="http://msdn.microsoft.com/en-us/library/system.configuration.regexstringvalidator.aspx" target="_blank">RegexStringValidator</a> object to determine if the configuration value adheres to the the regular expression.</li><li><a
title="MSDN Documentation for the StringValidatorAttribute class." href="http://msdn.microsoft.com/en-us/library/system.configuration.stringvalidatorattribute.aspx" target="_blank">StringValidatorAttribute</a> &#8211; Validates using a <a
title="MSDN Documetation for the StringValidator class." href="http://msdn.microsoft.com/en-us/library/system.configuration.stringvalidator.aspx" target="_blank">StringValidator</a> object to ensure the configuration value meets certain criteria &#8211; such as string length and invalid characters.</li><li><a
title="MSDN Documentation for the SubclassTypeValidatorAttribute class." href="http://msdn.microsoft.com/en-us/library/system.configuration.subclasstypevalidatorattribute.aspx" target="_blank">SubclassTypeValidatorAttribute</a> &#8211; Validates using a <a
title="MSDN Documentation for the SubclassTypeValidator class." href="http://msdn.microsoft.com/en-us/library/system.configuration.subclasstypevalidator.aspx" target="_blank">SubclassTypeValidator</a> object to determine if the configuration value derives of a given type.</li><li><a
title="MSDN Documentation for the TimeSpanValidatorAttribute class." href="http://msdn.microsoft.com/en-us/library/system.configuration.timespanvalidatorattribute.aspx" target="_blank">TimeSpanValidatorAttribute</a> &#8211; Validates using a <a
title="MSDN Documentation for the TimeSpanValidator class." href="http://msdn.microsoft.com/en-us/library/system.configuration.timespanvalidator.aspx" target="_blank">TimeSpanValidator</a> object to determine if the configuration value is falls within or outside a specific range.</li></ul><p>With the exception of the CallbackValidatorAttribute, you do not have to create corresponding validator objects to use in conjunction with the validator attributes. The .NET runtime creates the appropriate validator objects for you, and the attributes contain the needed parameters to configure the validator objects.</p><p>This small bit of code is all that is required to programmatically represent individual &lt;add/&gt; elements. The next step is to write a class that represents the &lt;feeds/&gt; element.</p><hr
/><h2>Writing an Element Collection Class</h2><p>The XML representation of the &lt;feeds/&gt; element is that of a collection of feed elements. Likewise, the programmatic representation of the &lt;feeds/&gt; element is a collection of FeedElement objects. This class, called FeedElementCollection, derives from the abstract ConfigurationElementCollection class.</p><p>The ConfigurationElementCollection class contains several members, but only two are marked as abstract. Thus, the simplest ConfigurationElementCollection implementation has two methods:</p><ul><li>CreateNewElement() &#8211; Creates a new ConfigurationElement object (FeedElement in this<br
/> case).</li><li>GetElementKey() &#8211; Gets the element key for a specified configuration element (the<br
/> Name property of FeedElement objects in this case).</li></ul><p>With that in mind, view the complete code for the FeedElementCollection class below:</p><pre class="c#" name="code">[ConfigurationCollection(typeof(FeedElement))]
public class FeedElementCollection : ConfigurationElementCollection
{
    protected override ConfigurationElement CreateNewElement()
    {
        return new FeedElement();
    }
    protected override object GetElementKey(ConfigurationElement element)
    {
        return ((FeedElement)element).Name;
    }
}</pre><p>A <a
title="MSDN Documentation for the ConfigurationCollectionAttribute class." href="http://msdn.microsoft.com/en-us/library/system.configuration.configurationcollectionattribute.aspx" target="_blank">ConfigurationCollectionAttribute</a> decorates this collection class. The first parameter to the attribute is a Type object &#8211; the type of the items the collection contains. In this case, it&#8217;s the FeedElement type. After the type parameter are several named parameters you can pass to the attribute. These are listed below:</p><ul><li>AddItemName &#8211; Sets the name of the &lt;add/&gt; configuration element. For example,<br
/> setting this as &quot;feed&quot; would require the &lt;add/&gt; elements in the<br
/> configuration to be changed to &lt;feed/&gt;.</li><li>ClearItemsName &#8211; Sets the name of the &lt;clear/&gt; configuration element (used<br
/> to clear all items from the collection).</li><li>RemoveItemName &#8211; Sets the name for the &lt;remove/&gt; configuration element (used<br
/> to remove an item from the collection).</li></ul><p>Leaving these named parameters blank defaults them to &lt;add/&gt;, &lt;clear/&gt;, &lt;remove/&gt;.</p><hr
/><h2>Writing the FeedRetreiverSection Class</h2><p>The final class, called FeedRetrieverSection, derives from ConfigurationSection and represents the &lt;feedRetriever/&gt; element. This is the simplest class of the configuration classes, as the only requirement it must meet is to provide programmatic access to the &lt;feeds/&gt; element (the FeedElementCollection).</p><pre class="c#" name="code">public class FeedRetrieverSection : ConfigurationSection
{
    [ConfigurationProperty(&quot;feeds&quot;, IsDefaultCollection = true)]
    public FeedElementCollection Feeds
    {
        get { return (FeedElementCollection)this[&quot;feeds&quot;]; }
        set { this[&quot;feeds&quot;] = value; }
    }
}</pre><p>It&#8217;s one property, of type FeedElementCollection and called Feeds, is decorated with a ConfigurationPropertyAttribute &#8211; mapping it to the &lt;feeds/&gt; element.</p><hr
/><h2>Modifying web.config</h2><p>With the configuration handler complete, you can add the appropriate elements to web.config. The &lt;feedRetriever/&gt; section can go anywhere in the file as long as itís a direct descendent of the root element (the &lt;configuration/&gt; element). Placing it within another configuration section results in an error.</p><p>The next step is adding a &lt;section/&gt; child element to &lt;configSections/&gt;. The &lt;section/&gt; element has two attributes of interest:</p><ul><li>name &#8211; The name of the configuration section element. In this case, name is feedRetriever.</li><li>type &#8211; The qualified name of the class associated with the section, and if necessary,<br
/> the name of the assembly the class resides in. In this case, the qualified name<br
/> is FeedRetriever.Configuration.FeedRetrieverSection. If it resides in a separate<br
/> assembly, the type attribute would have a value of &quot;FeedRetriever.Configuration.FeedRetrieverSection,<br
/> &lt;assemblyName&gt;&quot;, where &lt;assemblyName&gt; is the name of the assembly<br
/> without the angle brackets.</li></ul><p>The following &lt;section/&gt; element is what you add to a web.config file, under &lt;configSections/&gt;, when the configuration classes do not reside in a separate assembly (as is the case in the code download):</p><pre class="xml" name="code">&lt;section name=&quot;feedRetriever&quot; type=&quot;FeedRetriever.Configuration.FeedRetrieverSection&quot;/&gt;</pre><p>Now your application is properly configured to use the FeedRetrieverSection, FeedElementCollection, and FeedElement classes to grant you programmatic access to the custom settings contained within the &lt;feedRetriever/&gt; configuration section in web.config. So how do you access these settings from within your code?</p><hr
/><h2>Accessing Configuration Data from Code</h2><p>The System.Configuration namespace contains a static class called ConfigurationManager. If you use the &lt;connectionStrings/&gt; section to house your connection strings, you are at least familiar with ConfigurationManager. It has a method called GetSection(), which accepts a string containing the name of the configuration section to retrieve. The following code demonstrates this (assume using System.Configuration is at the top of the code file):</p><pre class="c#" name="code">FeedRetrieverSection config = ConfigurationManager.GetSection(&quot;feedRetriever&quot;) as FeedRetrieverSection;</pre><p>The GetSection() method returns a value of type Object, so it must be cast to whatever type the handler is for that section. This code retrieves the section named feedRetriever and casts the result as FeedRetrieverSection. Once you have the object, you can start accessing configuration data programmatically.</p><p>To give you an idea of how configuration settings can be used within your component or application, the following code is a very basic implementation of the FeedRetriever component.</p><pre class="c#" name="code">public class FeedRetriever
{
    public static FeedRetrieverSection _Config =
        ConfigurationManager.GetSection(&quot;feedRetriever&quot;) as FeedRetrieverSection;
<br />
    public static void GetFeeds()
    {
        foreach (FeedElement feedEl in _Config.Feeds)
        {
            // make request
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(feedEl.Url);
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            if (response.StatusCode == HttpStatusCode.OK)
            {
                string feedData = String.Empty;
                using (StreamReader reader =
                             new StreamReader(response.GetResponseStream()))
                {
                    feedData = reader.ReadToEnd();
                }
                if (feedEl.Cache)
                {
                    // filename of cache file
                    string filename = String.Format(&quot;{0}_{1}.xml&quot;,
                                            feedEl.Name, DateTime.Now.Ticks);
                    // cache file
                    using (StreamWriter writer =
                             new StreamWriter(@&quot;C:\&quot; + filename))
                    {
                        writer.Write(feedData);
                    }
                }
            }
        }
    }
}</pre><p>First, a static variable called _Config, of type FeedRetreiverSection, is declared and assigned a value by calling ConfigurationManager.GetSection(). Making the variable static is a design choice. By doing so, all members of the class, either instance or static, would have access to the configuration settings without having to make multiple calls to GetSection().</p><p>Once you retrieve the section handler with GetSection(), you have complete access to objects created from your handler classes. The first line of GetFeeds() is a for each loop that loops through all FeedElement objects contained with the FeedElementCollection object returned by the Feeds property. This gives you direct access to those FeedElement objects &#8211; making it easy to access each feed&#8217;s name, URL, and cache settings.</p><p>During each iteration of the loop, the method makes a request using the FeedElement objectís Url property. If the request results in a success, the feedís data is retrieved and stored in the feedData variable. Then the code checks the FeedElement objectís Cache property to determine whether or not to cache the feed. Caching the the feed involves constructing a filename by using the FeedElement objectís Name property and the current date and time. Then a StreamWriter object creates the file and writes the feedís data to it.</p><p>As you can see, using the configuration section handler classes is key to retrieving and using custom settings residing in web.config. It certainly requires more time and effort from you, but it definitely makes your application or component much easier to configure for yourself and other developers.</p><hr
/><h2>Sell your .NET Components on CodeCanyon!</h2><div
class="tutorial_image"> <a
href="http://codecanyon.net"><br
/> <img
src="http://envato.s3.amazonaws.com/referrer_adverts/cc_728x90_v2.gif" alt="CodeCanyon" style="width: 600px;" /><br
/> </a></div><p><strong>Did you know that we have a <a
href="http://codecanyon.net/category/net">.NET category</a> on <a
href="http://codecanyon.net/">CodeCanyon</a>. If you&#8217;re a skilled .NET dev, why not sell your scripts/components/controls as an author, and <a
href="http://codecanyon.net/wiki/selling/author-selling/author-program/">earn 40-70% of every sale</a>?</strong></p><ul
class="webroundup"><li>Follow us on <a
href="http://www.twitter.com/nettuts">Twitter</a>, or subscribe to the <a
href="http://feeds.feedburner.com/nettuts" title="Nettuts+ RSS Feed">Nettuts+ RSS Feed</a> for the best web development tutorials on the web.</li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/DzwiQ1C88Is6heDH1KLLKpZwo5c/0/da"><img src="http://feedads.g.doubleclick.net/~a/DzwiQ1C88Is6heDH1KLLKpZwo5c/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/DzwiQ1C88Is6heDH1KLLKpZwo5c/1/da"><img src="http://feedads.g.doubleclick.net/~a/DzwiQ1C88Is6heDH1KLLKpZwo5c/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=2aVOu3wGcGI:fC_1aCG_c_o:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=2aVOu3wGcGI:fC_1aCG_c_o:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=2aVOu3wGcGI:fC_1aCG_c_o:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=2aVOu3wGcGI:fC_1aCG_c_o:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=2aVOu3wGcGI:fC_1aCG_c_o:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=2aVOu3wGcGI:fC_1aCG_c_o:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=2aVOu3wGcGI:fC_1aCG_c_o:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=2aVOu3wGcGI:fC_1aCG_c_o:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/2aVOu3wGcGI" height="1" width="1"/>";s:14:"date_timestamp";i:1353774213;}i:3;a:13:{s:5:"title";s:21:"Mockery: A Better Way";s:4:"link";s:54:"http://feedproxy.google.com/~r/nettuts/~3/Fz9EiD5jKew/";s:8:"comments";s:68:"http://net.tutsplus.com/tutorials/php/mockery-a-better-way/#comments";s:7:"pubdate";s:31:"Wed, 21 Nov 2012 16:56:44 +0000";s:2:"dc";a:1:{s:7:"creator";s:12:"Patkos Csaba";}s:8:"category";s:16:"PHPmockeryphptdd";s:4:"guid";s:32:"http://net.tutsplus.com/?p=28097";s:11:"description";s:33389:"<a
href='http://rss.buysellads.com/click.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28097&c=934690681' target='_blank'><img
src='http://rss.buysellads.com/img.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28097&c=934690681' border='0' alt='' /></a><p><a
href="https://github.com/padraic/mockery">Mockery</a> is a PHP extension that offers a superior mocking experience, particularly when compared to <a
href="http://www.phpunit.de/manual/current/en/index.html">PHPUnit</a>. While PHPUnit&#8217;s mocking framework is powerful, Mockery offers a more natural language with a Hamcrest-like set of matchers. In this article, I&#8217;ll compare the two mocking frameworks and highlight the best features of Mockery.</p><p><span
id="more-28097"></span></p><p>Mockery offers a set of mocking-related matchers that are very similar to a Hamcrest dictionary, offering a very natural way to express mocked expectations. Mockery does not override or conflict with PHPUnit&#8217;s built-in mocking functions; in fact, you can use them both at the same time (and even in the same test method).</p><hr
/><h2>Installing Mockery</h2><p>There are multiple ways to install Mockery; here are the most common methods.</p><h3>Use Composer</h3><p>Create a file called <code>composer.json</code> in you project&#8217;s root folder, and add the following code to that file:</p><pre class="brush: jscript; title: ; notranslate">{
    &quot;require&quot;: {
        &quot;Mockery/Mockery&quot;: &quot;&gt;=0.7.2&quot;
    }
}</pre><p>Next, simply install Composer in your project&#8217;s root folder using the following command:</p><pre class="brush: bash; title: ; notranslate">curl -s http://getcomposer.org/installer | php</pre><p>Finally, install any required dependencies (including Mockery) with this command:</p><pre class="brush: bash; title: ; notranslate">php composer.phar install</pre><p>With everything installed, let&#8217;s ensure that our Mockery installation works. For the sake of simplicity, I&#8217;ll assume that you have a folder, called <code>Test</code> in your project&#8217;s root directory. All of the examples in this tutorial will reside in this folder. Here&#8217;s the code I&#8217;ve used to ensure that Mockery works with my project:</p><pre class="brush: php; title: ; notranslate">//Filename: JustToCheckMockeryTest.php
require_once '../vendor/autoload.php';
class JustToCheckMockeryTest extends PHPUnit_Framework_TestCase {
	protected function tearDown() {
		\Mockery::close();
	}
	function testMockeryWorks() {
		$mock = \Mockery::mock('AClassToBeMocked');
		$mock-&gt;shouldReceive('someMethod')-&gt;once();
		$workerObject = new AClassToWorkWith;
		$workerObject-&gt;doSomethingWit($mock);
	}
}
class AClassToBeMocked {}
class AClassToWorkWith {
	function doSomethingWit($anotherClass) {
		return $anotherClass-&gt;someMethod();
	}
}</pre><h3>Linux Users: Use Your Distro&#8217;s Packages</h3><p>Some Linux distributions make it easy to install Mockery, but only a handful provide a Mockery package for their system. The following list are the only distros I&#8217;m aware of:</p><ul><li><strong>Sabayon</strong>: <code>equo install Mockery</code></li><li><strong>Fedora / RHE</strong>: <code>yum install Mockery</code></li></ul><h3>Use PEAR</h3><p>PEAR fans can install Mockery by issuing the following commands:</p><pre class="brush: bash; title: ; notranslate">sudo pear channel-discover pear.survivethedeepend.com
sudo pear channel-discover hamcrest.googlecode.com/svn/pear
sudo pear install --alldeps deepend/Mockery</pre><h3>Installing from Source</h3><p>Installing from GitHub is for the real geeks! You can always grab the latest version of Mockery through its GitHub repository.</p><pre class="brush: bash; title: ; notranslate">git clone git://github.com/padraic/Mockery.git
cd Mockery
sudo pear channel-discover hamcrest.googlecode.com/svn/pear
sudo pear install --alldeps package.xml</pre><hr
/><h2>Creating our First Mocked Object</h2><p>Let&#8217;s mock some objects before we define any expectations. The following code will modify the previous example to include both PHPUnit and Mockery examples:</p><pre class="brush: php; title: ; notranslate">//Filename: MockeryABetterWayOfMockingTest.php
require_once '../vendor/autoload.php';
class MockeryVersusPHPUnitGetMockTest extends PHPUnit_Framework_TestCase {
	function testCreateAMockedObject() {
		// With PHPUnit
		$phpunitMock = $this-&gt;getMock('AClassToBeMocked');
		// With Mockery
		$mockeryMock = \Mockery::mock('AClassToBeMocked');
	}
}
class AClassToBeMocked {
}</pre><blockquote
class="pullquote"><p>Mockery allows you to define mocks for classes that do not exist.</p></blockquote><p>The first line ensures that we have access to Mockery. Next, we create a test class, called <code>MockeryVersusPHPUnitGetMockTest</code>, which has a method, <code>testCreateAMockedObject()</code>. The mocked class, <code>AClassToBeMocked</code>, is completely empty at this time; in fact, you could completely remove the class without causing the test to fail.</p><p>The <code>testCreateAMockedObject()</code> test method defines two objects. The first is a PHPUnit mock, and the second is created with Mockery. Mockery&#8217;s syntax is:</p><pre class="brush: php; title: ; notranslate">$mockedObject = \Mockery::mock('SomeClassToBeMocked');</pre><hr
/><h2>Assign Simple Expectations</h2><p>Mocks are commonly used to verify an object&#8217;s behavior (primarily its methods) by specifying what are called <em>expectations</em>. Let&#8217;s set up a few simple expectations.</p><h3>Expect a Method to be Called</h3><p>Probably the most common expectation is one that expects a specific method call. Most mocking frameworks allow you to specify the amount of calls you expect a method to receive. We&#8217;ll begin with a simple single call expectation:</p><pre class="brush: php; title: ; notranslate">//Filename: MockeryABetterWayOfMockingTest.php
require_once '../vendor/autoload.php';
class MockeryVersusPHPUnitGetMockTest extends PHPUnit_Framework_TestCase {
	protected function tearDown() {
		\Mockery::close();
	}
	function testExpectOnce() {
		$someObject = new SomeClass();
		// With PHPUnit
		$phpunitMock = $this-&gt;getMock('AClassToBeMocked');
		$phpunitMock-&gt;expects($this-&gt;once())-&gt;method('someMethod');
		// Exercise for PHPUnit
		$someObject-&gt;doSomething($phpunitMock);
		// With Mockery
		$mockeryMock = \Mockery::mock('AnInexistentClass');
		$mockeryMock-&gt;shouldReceive('someMethod')-&gt;once();
		// Exercise for Mockery
		$someObject-&gt;doSomething($mockeryMock);
	}
}
class AClassToBeMocked {
	function someMethod() {}
}
class SomeClass {
	function doSomething($anotherObject) {
		$anotherObject-&gt;someMethod();
	}
}
</pre><p>This code configures an expectation for both PHPUnit and Mockery. Let&#8217;s start with the former.</p><blockquote
class="pullquote"><p>Some Linux distributions make it easy to install Mockery.</p></blockquote><p>We use the <code>expects()</code> method to define an expectation to call <code>someMethod()</code> once. But in order for PHPUnit to work correctly, we <strong>must</strong> define a class called <code>AClassToBeMocked</code>, and it must have a <code>someMethod()</code> method.</p><p>This is a problem. If you are mocking a lot of objects and developing using TDD principles for a top-down design, you would not want to create all the classes and methods before your test. Your test should fail for the right reason, that the expected method was not called, instead of a critical PHP error with no relation to the real implementation. Go ahead and try to remove the <code>someMethod()</code> definition from <code>AClassToBeMocked</code>, and see what happens.</p><blockquote><p>Mockery, on the other hand, allows you to define mocks for classes that do not exist.</p></blockquote><p>Notice that the above example creates a mock for <code>AnInexistentClass</code>, which as its name implies, does not exist (nor does its <code>someMethod()</code> method).</p><p>At the end of the above example, we define the <code>SomeClass</code> class to exercise our code. We initialize an object, called <code>$someObject</code> in the first line of the test method, and we effectively exercise the code after defining our expectations.</p><div
class="tip-shortcode"><p><strong>Please Note:</strong> Mockery evaluates expectations on its <code>close()</code> method. For this reason, you should always have a <code>tearDown()</code> method on your test that calls <code>\Mockery::close()</code>. Otherwise, Mockery gives false positives.</p></div><h3>Expect More Than One Call</h3><p>As I noted previously, most mocking frameworks have the ability to specify expectations for multiple method calls. PHPUnit uses the <code>$this->exactly()</code> construct for this purpose. The following code defines the expectations for calling a method multiple times:</p><pre class="brush: php; title: ; notranslate">function testExpectMultiple() {
	$someObject = new SomeClass();
	// With PHPUnit 2 times
	$phpunitMock = $this-&gt;getMock('AClassToBeMocked');
	$phpunitMock-&gt;expects($this-&gt;exactly(2))-&gt;method('someMethod');
	// Exercise for PHPUnit
	$someObject-&gt;doSomething($phpunitMock);
	$someObject-&gt;doSomething($phpunitMock);
	// With Mockery 2 times
	$mockeryMock = \Mockery::mock('AnInexistentClass');
	$mockeryMock-&gt;shouldReceive('someMethod')-&gt;twice();
	// Exercise for Mockery
	$someObject-&gt;doSomething($mockeryMock);
	$someObject-&gt;doSomething($mockeryMock);
	// With Mockery 3 times
	$mockeryMock = \Mockery::mock('AnInexistentClass');
	$mockeryMock-&gt;shouldReceive('someMethod')-&gt;times(3);
	// Exercise for Mockery
	$someObject-&gt;doSomething($mockeryMock);
	$someObject-&gt;doSomething($mockeryMock);
	$someObject-&gt;doSomething($mockeryMock);
}</pre><p>Mockery provides two different methods to better suit your needs. The first method, <code>twice()</code>, expects two method calls. The other method is <code>times()</code>, which lets you specify an amount. Mockery&#8217;s approach is much cleaner and easier to read.</p><hr
/><h2>Returning Values</h2><p>Another common use for mocks is to test a method&#8217;s return value. Naturally, both PHPUnit and Mockery have the means to verify return values. Once again, let&#8217;s start with something simple.</p><h3>Simple Return Values</h3><p>The following code contains both PHPUnit and Mockery code. I also updated <code>SomeClass</code> to provide a testable return value.</p><pre class="brush: php; title: ; notranslate">class MockeryVersusPHPUnitGetMockTest extends PHPUnit_Framework_TestCase {
	protected function tearDown() {
		\Mockery::close();
	}
	// [...] //
	function testSimpleReturnValue() {
		$someObject = new SomeClass();
		$someValue = 'some value';
		// With PHPUnit
		$phpunitMock = $this-&gt;getMock('AClassToBeMocked');
		$phpunitMock-&gt;expects($this-&gt;once())-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($someValue));
		// Expect the returned value
		$this-&gt;assertEquals($someValue, $someObject-&gt;doSomething($phpunitMock));
		// With Mockery
		$mockeryMock = \Mockery::mock('AnInexistentClass');
		$mockeryMock-&gt;shouldReceive('someMethod')-&gt;once()-&gt;andReturn($someValue);
		// Expect the returned value
		$this-&gt;assertEquals($someValue, $someObject-&gt;doSomething($mockeryMock));
	}
}
class AClassToBeMocked {
	function someMethod() {
	}
}
class SomeClass {
	function doSomething($anotherObject) {
		return $anotherObject-&gt;someMethod();
	}
}</pre><p>Both PHPUnit&#8217;s and Mockery&#8217;s API is straight-forward and easy to use, but I still find Mockery to be cleaner and more readable.</p><h3>Returning Different Values</h3><p>Frequent unit testers can testify to complications with methods that return different values. Unfortunately, PHPUnit&#8217;s limited <code>$this->at($index)</code> method is the <strong>only</strong> way to return different values from the same method. The following code demonstrates the <code>at()</code> method:</p><pre class="brush: php; title: ; notranslate">function testDemonstratePHPUnitCallIndexing() {
	$someObject = new SomeClass();
	$firstValue = 'first value';
	$secondValue = 'second value';
	// With PHPUnit
	$phpunitMock = $this-&gt;getMock('AClassToBeMocked');
	$phpunitMock-&gt;expects($this-&gt;at(0))-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($firstValue));
	$phpunitMock-&gt;expects($this-&gt;at(1))-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($secondValue));
	// Expect the returned value
	$this-&gt;assertEquals($firstValue, $someObject-&gt;doSomething($phpunitMock));
	$this-&gt;assertEquals($secondValue, $someObject-&gt;doSomething($phpunitMock));
}</pre><p>This code defines two separate expectations and makes two different calls to <code>someMethod()</code>; so, this test passes. But let&#8217;s introduce a twist and add a double call in the tested class:</p><pre class="brush: php; title: ; notranslate">
// [...] //
function testDemonstratePHPUnitCallIndexingOnTheSameClass() {
	$someObject = new SomeClass();
	$firstValue = 'first value';
	$secondValue = 'second value';
	// With PHPUnit
	$phpunitMock = $this-&gt;getMock('AClassToBeMocked');
	$phpunitMock-&gt;expects($this-&gt;at(0))-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($firstValue));
	$phpunitMock-&gt;expects($this-&gt;at(1))-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($secondValue));
	// Expect the returned value
	$this-&gt;assertEquals('first value second value', $someObject-&gt;concatenate($phpunitMock));
}
class SomeClass {
	function doSomething($anotherObject) {
		return $anotherObject-&gt;someMethod();
	}
	function concatenate($anotherObject) {
		return $anotherObject-&gt;someMethod() . ' ' . $anotherObject-&gt;someMethod();
	}
}</pre><p>The test still passes. PHPUnit expects two calls to <code>someMethod()</code> that happen inside the tested class when performing the concatenation via the <code>concatenate()</code> method. The first call returns the first value, and the second call returns the second value. But, here&#8217;s the catch: what would happen if you double the assertion? Here&#8217;s the code:</p><pre class="brush: php; title: ; notranslate">function testDemonstratePHPUnitCallIndexingOnTheSameClass() {
	$someObject = new SomeClass();
	$firstValue = 'first value';
	$secondValue = 'second value';
	// With PHPUnit
	$phpunitMock = $this-&gt;getMock('AClassToBeMocked');
	$phpunitMock-&gt;expects($this-&gt;at(0))-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($firstValue));
	$phpunitMock-&gt;expects($this-&gt;at(1))-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($secondValue));
	// Expect the returned value
	$this-&gt;assertEquals('first value second value', $someObject-&gt;concatenate($phpunitMock));
	$this-&gt;assertEquals('first value second value', $someObject-&gt;concatenate($phpunitMock));
}</pre><p>It returns the following error:</p><pre class="brush: xml; title: ; notranslate">Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'first value second value'
+' '</pre><p>PHPUnit continues counting between distinct calls to <code>concatenate()</code>. By the time the second call in the last assertion occurs, <code>$index</code> is at the values <code>2</code> and <code>3</code>. You can make the test pass by modifying your expectations to consider the two new steps, like this:</p><pre class="brush: php; title: ; notranslate">function testDemonstratePHPUnitCallIndexingOnTheSameClass() {
	$someObject = new SomeClass();
	$firstValue = 'first value';
	$secondValue = 'second value';
	// With PHPUnit
	$phpunitMock = $this-&gt;getMock('AClassToBeMocked');
	$phpunitMock-&gt;expects($this-&gt;at(0))-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($firstValue));
	$phpunitMock-&gt;expects($this-&gt;at(1))-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($secondValue));
	$phpunitMock-&gt;expects($this-&gt;at(2))-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($firstValue));
	$phpunitMock-&gt;expects($this-&gt;at(3))-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($secondValue));
	// Expect the returned value
	$this-&gt;assertEquals('first value second value', $someObject-&gt;concatenate($phpunitMock));
	$this-&gt;assertEquals('first value second value', $someObject-&gt;concatenate($phpunitMock));
}</pre><p>You can probably live with this code, but Mockery makes this scenario trivial. Don&#8217;t believe me? Take a look:</p><pre class="brush: php; title: ; notranslate">function testMultipleReturnValuesWithMockery() {
	$someObject = new SomeClass();
	$firstValue = 'first value';
	$secondValue = 'second value';
	// With Mockery
	$mockeryMock = \Mockery::mock('AnInexistentClass');
	$mockeryMock-&gt;shouldReceive('someMethod')-&gt;andReturn($firstValue, $secondValue, $firstValue, $secondValue);
	// Expect the returned value
	$this-&gt;assertEquals('first value second value', $someObject-&gt;concatenate($mockeryMock));
	$this-&gt;assertEquals('first value second value', $someObject-&gt;concatenate($mockeryMock));
}</pre><p>Like PHPUnit, Mockery uses index counting, but we don&#8217;t have to worry about indices. Instead, we simply list all the expected values, and Mockery returns them in order.</p><p>Additionally, PHPUnit returns <code>NULL</code> for unspecified indexes, but Mockery always returns the last specified value. That&#8217;s a nice touch.</p><h3>Try Multiple Methods with Indexing</h3><p>Let&#8217;s introduce a second method into our code, the <code>concatWithMinus()</code> method:</p><pre class="brush: php; title: ; notranslate">class SomeClass {
	function doSomething($anotherObject) {
		return $anotherObject-&gt;someMethod();
	}
	function concatenate($anotherObject) {
		return $anotherObject-&gt;someMethod() . ' ' . $anotherObject-&gt;someMethod();
	}
	function concatWithMinus($anotherObject) {
		return $anotherObject-&gt;anotherMethod() . ' - ' . $anotherObject-&gt;anotherMethod();
	}
}</pre><p>This method behaves similarly to <code>concatenate()</code>, but it concatenates the string values with &#8220;<code> - </code>&#8221; as opposed to a single space. Because these two methods perform similar tasks, it makes sense to to test them inside the same test method to avoid duplicate testing.</p><p>As demonstrated in the above code, the second function uses a different mocked method called <code>anotherMethod()</code>. I made this change to force us to mock both methods in our tests. Our mockable class now looks like this:</p><pre class="brush: php; title: ; notranslate">class AClassToBeMocked {
	function someMethod() {
	}
	function anotherMethod() {
	}
}</pre><p>Testing this with PHPUnit might look like the following:</p><pre class="brush: php; title: ; notranslate">function testPHPUnitIndexingOnMultipleMethods() {
	$someObject = new SomeClass();
	$firstValue = 'first value';
	$secondValue = 'second value';
	// With PHPUnit
	$phpunitMock = $this-&gt;getMock('AClassToBeMocked');
	// First and second call on the semeMethod:
	$phpunitMock-&gt;expects($this-&gt;at(0))-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($firstValue));
	$phpunitMock-&gt;expects($this-&gt;at(1))-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($secondValue));
	// Expect the returned value
	$this-&gt;assertEquals('first value second value', $someObject-&gt;concatenate($phpunitMock));
	// First and second call on the anotherMethod:
	$phpunitMock-&gt;expects($this-&gt;at(0))-&gt;method('anotherMethod')-&gt;will($this-&gt;returnValue($firstValue));
	$phpunitMock-&gt;expects($this-&gt;at(1))-&gt;method('anotherMethod')-&gt;will($this-&gt;returnValue($secondValue));
	// Expect the returned value
	$this-&gt;assertEquals('first value - second value', $someObject-&gt;concatWithMinus($phpunitMock));
}</pre><p>The logic is sound. Define two different expectations for each method and specify the return value. This works only with PHPUnit 3.6 or newer.</p><div
class="tip-shortcode"><p><strong>Please Note:</strong> PHPunit 3.5 and older had a bug which did not reset the index for each method, resulting in unexpected return values for mocked methods.</p></div><p>Let&#8217;s look at the same scenario with Mockery. Once again, we get much cleaner code. See for yourself:</p><pre class="brush: php; title: ; notranslate">function testMultipleReturnValuesForDifferentFunctionsWithMockery() {
	$someObject = new SomeClass();
	$firstValue = 'first value';
	$secondValue = 'second value';
	// With Mockery
	$mockeryMock = \Mockery::mock('AnInexistentClass');
	$mockeryMock-&gt;shouldReceive('someMethod')-&gt;andReturn($firstValue, $secondValue);
	$mockeryMock-&gt;shouldReceive('anotherMethod')-&gt;andReturn($firstValue, $secondValue);
	// Expect the returned value
	$this-&gt;assertEquals('first value second value', $someObject-&gt;concatenate($mockeryMock));
	$this-&gt;assertEquals('first value - second value', $someObject-&gt;concatWithMinus($mockeryMock));
}</pre><hr
/><h2>Return Values Based on Given Parameter</h2><p>Honestly, this is something PHPUnit simply cannot do. At the time of this writing, PHPUnit does not permit you to return different values from the same function based on the function&#8217;s parameter. Therefore, the following test fails:</p><pre class="brush: php; title: ; notranslate">
// [...] //
function testPHUnitCandDecideByParameter() {
	$someObject = new SomeClass();
	// With PHPUnit
	$phpunitMock = $this-&gt;getMock('AClassToBeMocked');
	$phpunitMock-&gt;expects($this-&gt;any())-&gt;method('getNumber')-&gt;with(2)-&gt;will($this-&gt;returnValue(2));
	$phpunitMock-&gt;expects($this-&gt;any())-&gt;method('getNumber')-&gt;with(3)-&gt;will($this-&gt;returnValue(3));
	$this-&gt;assertEquals(4, $someObject-&gt;doubleNumber($phpunitMock, 2));
	$this-&gt;assertEquals(6, $someObject-&gt;doubleNumber($phpunitMock, 3));
}
class AClassToBeMocked {
// [...] //
	function getNumber($number) {
		return $number;
	}
}
class SomeClass {
	// [...] //
	function doubleNumber($anotherObject, $number) {
		return $anotherObject-&gt;getNumber($number) * 2;
	}
}</pre><p>Please ignore the fact that there is no logic in this example; it would fail even if it was present. This code, however, does help illustrate the idea.</p><p>This test fails because PHPUnit cannot differentiate between the two expectations in the test. The second expectation, expecting parameter <code>3</code>, simply overrides the first expecting parameter <code>2</code>. If you attempt to run this test, you get the following error:</p><pre class="brush: xml; title: ; notranslate">Expectation failed for method name is equal to &lt;string:getNumber&gt; when invoked zero or more times
Parameter 0 for invocation AClassToBeMocked::getNumber(2) does not match expected value.
Failed asserting that 2 matches expected 3.</pre><p>Mockery can do this, and the code below works exactly as you would expect it to work. The method returns different values based on its provided parameters:</p><pre class="brush: php; title: ; notranslate">function testMockeryReturningDifferentValuesBasedOnParameter() {
	$someObject = new SomeClass();
	// Mockery
	$mockeryMock = \Mockery::mock('AnInexistentClass');
	$mockeryMock-&gt;shouldReceive('getNumber')-&gt;with(2)-&gt;andReturn(2);
	$mockeryMock-&gt;shouldReceive('getNumber')-&gt;with(3)-&gt;andReturn(3);
	$this-&gt;assertEquals(4, $someObject-&gt;doubleNumber($mockeryMock, 2));
	$this-&gt;assertEquals(6, $someObject-&gt;doubleNumber($mockeryMock, 3));
}</pre><hr
/><h2>Partial Mocks</h2><p>Sometimes, you want to mock only specific methods on your object (as opposed to mocking an entire object). The following <code>Calculator</code> class already exists; we want to only mock certain methods:</p><pre class="brush: php; title: ; notranslate">class Calculator {
	function add($firstNo, $secondNo) {
		return $firstNo + $secondNo;
	}
	function subtract($firstNo, $secondNo) {
		return $firstNo - $secondNo;
	}
	function multiply($value, $multiplier) {
		$newValue = 0;
		for($i=0;$i&lt;$multiplier;$i++)
			$newValue = $this-&gt;add($newValue, $value);
		return $newValue;
	}
}</pre><p>This <code>Calculator</code> class has three methods: <code>add()</code>, <code>subtract()</code>, and <code>multiply()</code>. Multiply uses a loop to perform the multiplication by calling the <code>add()</code> for a specified amount of times (e.g. <code>2 x 3</code> is really <code>2 + 2 + 2</code>).</p><p>Let&#8217;s assume that we want to test <code>multiply()</code> in total isolation; so, we&#8217;ll mock <code>add()</code> and check for specific behavior on <code>multiply()</code>. Here are some possible tests:</p><pre class="brush: php; title: ; notranslate">function testPartialMocking() {
	$value = 3;
	$multiplier = 2;
	$result = 6;
	// PHPUnit
	$phpMock = $this-&gt;getMock('Calculator', array('add'));
	$phpMock-&gt;expects($this-&gt;exactly(2))-&gt;method('add')-&gt;will($this-&gt;returnValue($result));
	$this-&gt;assertEquals($result, $phpMock-&gt;multiply($value,$multiplier));
	// Mockery
	$mockeryMock = \Mockery::mock(new Calculator);
	$mockeryMock-&gt;shouldReceive('add')-&gt;andReturn($result);
	$this-&gt;assertEquals($result, $mockeryMock-&gt;multiply($value,$multiplier));
	// Mockery extended test checking parameters
	$mockeryMock2 = \Mockery::mock(new Calculator);
	$mockeryMock2-&gt;shouldReceive('add')-&gt;with(0,3)-&gt;andReturn(3);
	$mockeryMock2-&gt;shouldReceive('add')-&gt;with(3,3)-&gt;andReturn(6);
	$this-&gt;assertEquals($result, $mockeryMock2-&gt;multiply($value,$multiplier));
}</pre><blockquote
class="pullquote"><p>Mockery offers&#8230;a very natural way to express mocked expectations.</p></blockquote><p>The first PHPUnit test is anemic; it simply tests that the method <code>add()</code> is called twice and it returns the final value on each call. It gets the job done, but it&#8217;s also a little complicated. PHPUnit forces you to pass the list of methods that you want to mock as second parameter to <code>$this->getMock()</code>. Otherwise, PHPUnit would mock all methods, each returning <code>NULL</code> by default. This list <strong>must</strong> be kept in concordance with the expectations you define on your mocked object.</p><p>For example, if I add a second expectation to <code>$phpMock</code>&#8216;s <code>substract()</code> method, PHPUnit would ignore it and call the original <code>substract()</code> method. That is, unless I explicitly specify the name of the method (<code>substract</code>) in the <code>$this->getmock()</code> statement.</p><p>Of course, Mockery is different by allowing you to provide a real object to <code>\Mockery::mock()</code>, and it automatically creates a partial mock. It achieves this by implementing a proxy-like solution for mocking. All the expectations you define are used, but Mockery falls back to the original method if you do not specify an expectation for that method.</p><div
class="tip-shortcode"><p><strong>Please Note:</strong> Mockery&#8217;s approach is very simple, but internal method calls do not pass through the mocked object.</p></div><p>This example is misleading, but it illustrates <strong>how not to use</strong> Mockery&#8217;s partial mocks. Yes, Mockery creates a partial mock if you pass a real object, but it only mocks <strong>only external calls</strong>. For example, based on the previous code, the <code>multiply()</code> method calls the real <code>add()</code> method. Go ahead and try to change the last expectation from <code>...->andReturn(6)</code> to <code>...->andReturn(7)</code>. The test should obviously fail, but it doesn&#8217;t because the real <code>add()</code> executes instead of the mocked <code>add()</code> method.</p><p>But we can circumvent this issue by creating mocks like this:</p><pre class="brush: php; title: ; notranslate">//Instead of
$mockeryMock = \Mockery::mock(new Calculator);
// Create the mock like this
$mockeryMock = \Mockery::mock('Calculator[add]');</pre><p>While syntactically different, the concept is similar to PHPUnit&#8217;s approach: you have to list the mocked methods in two places. But for any other test, you can just simply pass the real object, which is much easier&#8211;especially when dealing with constructor parameters.</p><hr
/><h2>Dealing with Constructor Parameters</h2><p>Let&#8217;s add a constructor with two parameters to the <code>Calculator</code> class. The revised code:</p><pre class="brush: php; title: ; notranslate">class Calculator {
	public $myNumbers = array();
	function __construct($firstNo, $secondNo) {
		$this-&gt;myNumbers[]=$firstNo;
		$this-&gt;myNumbers[]=$secondNo;
	}
	// [...] //
}</pre><p>Every test in this article will fail after adding this constructor. More precisely, the <code>testPartialMock()</code> test results in the following error:</p><pre class="brush: xml; title: ; notranslate">Missing argument 1 for Calculator::__construct(),
called in /usr/share/php/PHPUnit/Framework/MockObject/Generator.php
on line 224 and defined</pre><p>PHPUnit tries to mock the real object by automatically calling the constructor, expecting to have the parameters correctly set. There are two ways around this problem: either set the parameters, or don&#8217;t call the constructor.</p><pre class="brush: php; title: ; notranslate">//Specify Constructor Parameters
$phpMock = $this-&gt;getMock('Calculator', array('add'), array(1,2));
//Do not call original constructor
$phpMock = $this-&gt;getMock('Calculator', array('add'), array(), '', false);</pre><p>Mockery <em>automagically</em> works around this problem. It&#8217;s okay not to specify a constructor parameter; Mockery will simply not call the constructor. But you can specify a list of constructor parameters for Mockery to use. For example:</p><pre class="brush: php; title: ; notranslate">function testMockeryConstructorParameters() {
	$result = 6;
	// Mockery
	// Do not call constructor
	$noConstrucCall = \Mockery::mock('Calculator[add]');
	$noConstrucCall-&gt;shouldReceive('add')-&gt;andReturn($result);
	// Use constructor parameters
	$withConstructParams = \Mockery::mock('Calculator[add]', array(1,2));
	$withConstructParams-&gt;shouldReceive('add')-&gt;andReturn($result);
	// User real object with real values and mock over it
	$realCalculator = new Calculator(1,2);
	$mockRealObj = \Mockery::mock($realCalculator);
	$mockRealObj-&gt;shouldReceive('add')-&gt;andReturn($result);
}</pre><hr
/><h2>Technical Considerations</h2><p>Mockery is another library that integrates your tests, and you may want to consider what technical implications this may have.</p><ul><li>Mockery uses a lot of memory. You will have to increase the maximum memory to 512MB if you want to run many tests(say over 1000 tests with more than 3000 assertions). See <code>php.ini</code> documentation for further details.</li><li>You have to organize your tests to run in separate processes, when mocking static methods and static method calls.</li><li>You can auto-load Mockery into every test by using PHPUnit&#8217;s bootstrap functionality (helpful when you have many tests and you don&#8217;t want to repeat yourself).</li><li>You can automate the call to <code>\Mockery::close()</code> in each test&#8217;s <code>tearDown()</code> by editing <code>phpunit.xml</code>.</li></ul><hr
/><h2>Final Conclusions</h2><p>PHPUnit certainly has its issues, especially when it comes to functionality and expressiveness. Mockery can greatly improve your mocking experience by making your tests easy to write and understand &#8211; but it&#8217;s not perfect (there&#8217;s no such thing!).</p><p>This tutorial has highlighted many key aspects of Mockery, but, honestly, we&#8217;ve barely scratched the surface. Be sure to explore the <a
href="https://github.com/padraic/Mockery">project&#8217;s Github repository</a> to learn more.</p><p>Thanks for reading!</p>
<p><a href="http://feedads.g.doubleclick.net/~a/liB_MlxAy3GFaYfAxEUxGaJGmfo/0/da"><img src="http://feedads.g.doubleclick.net/~a/liB_MlxAy3GFaYfAxEUxGaJGmfo/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/liB_MlxAy3GFaYfAxEUxGaJGmfo/1/da"><img src="http://feedads.g.doubleclick.net/~a/liB_MlxAy3GFaYfAxEUxGaJGmfo/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=Fz9EiD5jKew:jb7HtXeNL7M:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=Fz9EiD5jKew:jb7HtXeNL7M:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=Fz9EiD5jKew:jb7HtXeNL7M:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=Fz9EiD5jKew:jb7HtXeNL7M:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=Fz9EiD5jKew:jb7HtXeNL7M:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=Fz9EiD5jKew:jb7HtXeNL7M:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=Fz9EiD5jKew:jb7HtXeNL7M:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=Fz9EiD5jKew:jb7HtXeNL7M:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/Fz9EiD5jKew" height="1" width="1"/>";s:3:"wfw";a:1:{s:10:"commentrss";s:64:"http://net.tutsplus.com/tutorials/php/mockery-a-better-way/feed/";}s:5:"slash";a:1:{s:8:"comments";s:2:"43";}s:10:"feedburner";a:1:{s:8:"origlink";s:59:"http://net.tutsplus.com/tutorials/php/mockery-a-better-way/";}s:7:"summary";s:33389:"<a
href='http://rss.buysellads.com/click.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28097&c=934690681' target='_blank'><img
src='http://rss.buysellads.com/img.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28097&c=934690681' border='0' alt='' /></a><p><a
href="https://github.com/padraic/mockery">Mockery</a> is a PHP extension that offers a superior mocking experience, particularly when compared to <a
href="http://www.phpunit.de/manual/current/en/index.html">PHPUnit</a>. While PHPUnit&#8217;s mocking framework is powerful, Mockery offers a more natural language with a Hamcrest-like set of matchers. In this article, I&#8217;ll compare the two mocking frameworks and highlight the best features of Mockery.</p><p><span
id="more-28097"></span></p><p>Mockery offers a set of mocking-related matchers that are very similar to a Hamcrest dictionary, offering a very natural way to express mocked expectations. Mockery does not override or conflict with PHPUnit&#8217;s built-in mocking functions; in fact, you can use them both at the same time (and even in the same test method).</p><hr
/><h2>Installing Mockery</h2><p>There are multiple ways to install Mockery; here are the most common methods.</p><h3>Use Composer</h3><p>Create a file called <code>composer.json</code> in you project&#8217;s root folder, and add the following code to that file:</p><pre class="brush: jscript; title: ; notranslate">{
    &quot;require&quot;: {
        &quot;Mockery/Mockery&quot;: &quot;&gt;=0.7.2&quot;
    }
}</pre><p>Next, simply install Composer in your project&#8217;s root folder using the following command:</p><pre class="brush: bash; title: ; notranslate">curl -s http://getcomposer.org/installer | php</pre><p>Finally, install any required dependencies (including Mockery) with this command:</p><pre class="brush: bash; title: ; notranslate">php composer.phar install</pre><p>With everything installed, let&#8217;s ensure that our Mockery installation works. For the sake of simplicity, I&#8217;ll assume that you have a folder, called <code>Test</code> in your project&#8217;s root directory. All of the examples in this tutorial will reside in this folder. Here&#8217;s the code I&#8217;ve used to ensure that Mockery works with my project:</p><pre class="brush: php; title: ; notranslate">//Filename: JustToCheckMockeryTest.php
require_once '../vendor/autoload.php';
class JustToCheckMockeryTest extends PHPUnit_Framework_TestCase {
	protected function tearDown() {
		\Mockery::close();
	}
	function testMockeryWorks() {
		$mock = \Mockery::mock('AClassToBeMocked');
		$mock-&gt;shouldReceive('someMethod')-&gt;once();
		$workerObject = new AClassToWorkWith;
		$workerObject-&gt;doSomethingWit($mock);
	}
}
class AClassToBeMocked {}
class AClassToWorkWith {
	function doSomethingWit($anotherClass) {
		return $anotherClass-&gt;someMethod();
	}
}</pre><h3>Linux Users: Use Your Distro&#8217;s Packages</h3><p>Some Linux distributions make it easy to install Mockery, but only a handful provide a Mockery package for their system. The following list are the only distros I&#8217;m aware of:</p><ul><li><strong>Sabayon</strong>: <code>equo install Mockery</code></li><li><strong>Fedora / RHE</strong>: <code>yum install Mockery</code></li></ul><h3>Use PEAR</h3><p>PEAR fans can install Mockery by issuing the following commands:</p><pre class="brush: bash; title: ; notranslate">sudo pear channel-discover pear.survivethedeepend.com
sudo pear channel-discover hamcrest.googlecode.com/svn/pear
sudo pear install --alldeps deepend/Mockery</pre><h3>Installing from Source</h3><p>Installing from GitHub is for the real geeks! You can always grab the latest version of Mockery through its GitHub repository.</p><pre class="brush: bash; title: ; notranslate">git clone git://github.com/padraic/Mockery.git
cd Mockery
sudo pear channel-discover hamcrest.googlecode.com/svn/pear
sudo pear install --alldeps package.xml</pre><hr
/><h2>Creating our First Mocked Object</h2><p>Let&#8217;s mock some objects before we define any expectations. The following code will modify the previous example to include both PHPUnit and Mockery examples:</p><pre class="brush: php; title: ; notranslate">//Filename: MockeryABetterWayOfMockingTest.php
require_once '../vendor/autoload.php';
class MockeryVersusPHPUnitGetMockTest extends PHPUnit_Framework_TestCase {
	function testCreateAMockedObject() {
		// With PHPUnit
		$phpunitMock = $this-&gt;getMock('AClassToBeMocked');
		// With Mockery
		$mockeryMock = \Mockery::mock('AClassToBeMocked');
	}
}
class AClassToBeMocked {
}</pre><blockquote
class="pullquote"><p>Mockery allows you to define mocks for classes that do not exist.</p></blockquote><p>The first line ensures that we have access to Mockery. Next, we create a test class, called <code>MockeryVersusPHPUnitGetMockTest</code>, which has a method, <code>testCreateAMockedObject()</code>. The mocked class, <code>AClassToBeMocked</code>, is completely empty at this time; in fact, you could completely remove the class without causing the test to fail.</p><p>The <code>testCreateAMockedObject()</code> test method defines two objects. The first is a PHPUnit mock, and the second is created with Mockery. Mockery&#8217;s syntax is:</p><pre class="brush: php; title: ; notranslate">$mockedObject = \Mockery::mock('SomeClassToBeMocked');</pre><hr
/><h2>Assign Simple Expectations</h2><p>Mocks are commonly used to verify an object&#8217;s behavior (primarily its methods) by specifying what are called <em>expectations</em>. Let&#8217;s set up a few simple expectations.</p><h3>Expect a Method to be Called</h3><p>Probably the most common expectation is one that expects a specific method call. Most mocking frameworks allow you to specify the amount of calls you expect a method to receive. We&#8217;ll begin with a simple single call expectation:</p><pre class="brush: php; title: ; notranslate">//Filename: MockeryABetterWayOfMockingTest.php
require_once '../vendor/autoload.php';
class MockeryVersusPHPUnitGetMockTest extends PHPUnit_Framework_TestCase {
	protected function tearDown() {
		\Mockery::close();
	}
	function testExpectOnce() {
		$someObject = new SomeClass();
		// With PHPUnit
		$phpunitMock = $this-&gt;getMock('AClassToBeMocked');
		$phpunitMock-&gt;expects($this-&gt;once())-&gt;method('someMethod');
		// Exercise for PHPUnit
		$someObject-&gt;doSomething($phpunitMock);
		// With Mockery
		$mockeryMock = \Mockery::mock('AnInexistentClass');
		$mockeryMock-&gt;shouldReceive('someMethod')-&gt;once();
		// Exercise for Mockery
		$someObject-&gt;doSomething($mockeryMock);
	}
}
class AClassToBeMocked {
	function someMethod() {}
}
class SomeClass {
	function doSomething($anotherObject) {
		$anotherObject-&gt;someMethod();
	}
}
</pre><p>This code configures an expectation for both PHPUnit and Mockery. Let&#8217;s start with the former.</p><blockquote
class="pullquote"><p>Some Linux distributions make it easy to install Mockery.</p></blockquote><p>We use the <code>expects()</code> method to define an expectation to call <code>someMethod()</code> once. But in order for PHPUnit to work correctly, we <strong>must</strong> define a class called <code>AClassToBeMocked</code>, and it must have a <code>someMethod()</code> method.</p><p>This is a problem. If you are mocking a lot of objects and developing using TDD principles for a top-down design, you would not want to create all the classes and methods before your test. Your test should fail for the right reason, that the expected method was not called, instead of a critical PHP error with no relation to the real implementation. Go ahead and try to remove the <code>someMethod()</code> definition from <code>AClassToBeMocked</code>, and see what happens.</p><blockquote><p>Mockery, on the other hand, allows you to define mocks for classes that do not exist.</p></blockquote><p>Notice that the above example creates a mock for <code>AnInexistentClass</code>, which as its name implies, does not exist (nor does its <code>someMethod()</code> method).</p><p>At the end of the above example, we define the <code>SomeClass</code> class to exercise our code. We initialize an object, called <code>$someObject</code> in the first line of the test method, and we effectively exercise the code after defining our expectations.</p><div
class="tip-shortcode"><p><strong>Please Note:</strong> Mockery evaluates expectations on its <code>close()</code> method. For this reason, you should always have a <code>tearDown()</code> method on your test that calls <code>\Mockery::close()</code>. Otherwise, Mockery gives false positives.</p></div><h3>Expect More Than One Call</h3><p>As I noted previously, most mocking frameworks have the ability to specify expectations for multiple method calls. PHPUnit uses the <code>$this->exactly()</code> construct for this purpose. The following code defines the expectations for calling a method multiple times:</p><pre class="brush: php; title: ; notranslate">function testExpectMultiple() {
	$someObject = new SomeClass();
	// With PHPUnit 2 times
	$phpunitMock = $this-&gt;getMock('AClassToBeMocked');
	$phpunitMock-&gt;expects($this-&gt;exactly(2))-&gt;method('someMethod');
	// Exercise for PHPUnit
	$someObject-&gt;doSomething($phpunitMock);
	$someObject-&gt;doSomething($phpunitMock);
	// With Mockery 2 times
	$mockeryMock = \Mockery::mock('AnInexistentClass');
	$mockeryMock-&gt;shouldReceive('someMethod')-&gt;twice();
	// Exercise for Mockery
	$someObject-&gt;doSomething($mockeryMock);
	$someObject-&gt;doSomething($mockeryMock);
	// With Mockery 3 times
	$mockeryMock = \Mockery::mock('AnInexistentClass');
	$mockeryMock-&gt;shouldReceive('someMethod')-&gt;times(3);
	// Exercise for Mockery
	$someObject-&gt;doSomething($mockeryMock);
	$someObject-&gt;doSomething($mockeryMock);
	$someObject-&gt;doSomething($mockeryMock);
}</pre><p>Mockery provides two different methods to better suit your needs. The first method, <code>twice()</code>, expects two method calls. The other method is <code>times()</code>, which lets you specify an amount. Mockery&#8217;s approach is much cleaner and easier to read.</p><hr
/><h2>Returning Values</h2><p>Another common use for mocks is to test a method&#8217;s return value. Naturally, both PHPUnit and Mockery have the means to verify return values. Once again, let&#8217;s start with something simple.</p><h3>Simple Return Values</h3><p>The following code contains both PHPUnit and Mockery code. I also updated <code>SomeClass</code> to provide a testable return value.</p><pre class="brush: php; title: ; notranslate">class MockeryVersusPHPUnitGetMockTest extends PHPUnit_Framework_TestCase {
	protected function tearDown() {
		\Mockery::close();
	}
	// [...] //
	function testSimpleReturnValue() {
		$someObject = new SomeClass();
		$someValue = 'some value';
		// With PHPUnit
		$phpunitMock = $this-&gt;getMock('AClassToBeMocked');
		$phpunitMock-&gt;expects($this-&gt;once())-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($someValue));
		// Expect the returned value
		$this-&gt;assertEquals($someValue, $someObject-&gt;doSomething($phpunitMock));
		// With Mockery
		$mockeryMock = \Mockery::mock('AnInexistentClass');
		$mockeryMock-&gt;shouldReceive('someMethod')-&gt;once()-&gt;andReturn($someValue);
		// Expect the returned value
		$this-&gt;assertEquals($someValue, $someObject-&gt;doSomething($mockeryMock));
	}
}
class AClassToBeMocked {
	function someMethod() {
	}
}
class SomeClass {
	function doSomething($anotherObject) {
		return $anotherObject-&gt;someMethod();
	}
}</pre><p>Both PHPUnit&#8217;s and Mockery&#8217;s API is straight-forward and easy to use, but I still find Mockery to be cleaner and more readable.</p><h3>Returning Different Values</h3><p>Frequent unit testers can testify to complications with methods that return different values. Unfortunately, PHPUnit&#8217;s limited <code>$this->at($index)</code> method is the <strong>only</strong> way to return different values from the same method. The following code demonstrates the <code>at()</code> method:</p><pre class="brush: php; title: ; notranslate">function testDemonstratePHPUnitCallIndexing() {
	$someObject = new SomeClass();
	$firstValue = 'first value';
	$secondValue = 'second value';
	// With PHPUnit
	$phpunitMock = $this-&gt;getMock('AClassToBeMocked');
	$phpunitMock-&gt;expects($this-&gt;at(0))-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($firstValue));
	$phpunitMock-&gt;expects($this-&gt;at(1))-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($secondValue));
	// Expect the returned value
	$this-&gt;assertEquals($firstValue, $someObject-&gt;doSomething($phpunitMock));
	$this-&gt;assertEquals($secondValue, $someObject-&gt;doSomething($phpunitMock));
}</pre><p>This code defines two separate expectations and makes two different calls to <code>someMethod()</code>; so, this test passes. But let&#8217;s introduce a twist and add a double call in the tested class:</p><pre class="brush: php; title: ; notranslate">
// [...] //
function testDemonstratePHPUnitCallIndexingOnTheSameClass() {
	$someObject = new SomeClass();
	$firstValue = 'first value';
	$secondValue = 'second value';
	// With PHPUnit
	$phpunitMock = $this-&gt;getMock('AClassToBeMocked');
	$phpunitMock-&gt;expects($this-&gt;at(0))-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($firstValue));
	$phpunitMock-&gt;expects($this-&gt;at(1))-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($secondValue));
	// Expect the returned value
	$this-&gt;assertEquals('first value second value', $someObject-&gt;concatenate($phpunitMock));
}
class SomeClass {
	function doSomething($anotherObject) {
		return $anotherObject-&gt;someMethod();
	}
	function concatenate($anotherObject) {
		return $anotherObject-&gt;someMethod() . ' ' . $anotherObject-&gt;someMethod();
	}
}</pre><p>The test still passes. PHPUnit expects two calls to <code>someMethod()</code> that happen inside the tested class when performing the concatenation via the <code>concatenate()</code> method. The first call returns the first value, and the second call returns the second value. But, here&#8217;s the catch: what would happen if you double the assertion? Here&#8217;s the code:</p><pre class="brush: php; title: ; notranslate">function testDemonstratePHPUnitCallIndexingOnTheSameClass() {
	$someObject = new SomeClass();
	$firstValue = 'first value';
	$secondValue = 'second value';
	// With PHPUnit
	$phpunitMock = $this-&gt;getMock('AClassToBeMocked');
	$phpunitMock-&gt;expects($this-&gt;at(0))-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($firstValue));
	$phpunitMock-&gt;expects($this-&gt;at(1))-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($secondValue));
	// Expect the returned value
	$this-&gt;assertEquals('first value second value', $someObject-&gt;concatenate($phpunitMock));
	$this-&gt;assertEquals('first value second value', $someObject-&gt;concatenate($phpunitMock));
}</pre><p>It returns the following error:</p><pre class="brush: xml; title: ; notranslate">Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'first value second value'
+' '</pre><p>PHPUnit continues counting between distinct calls to <code>concatenate()</code>. By the time the second call in the last assertion occurs, <code>$index</code> is at the values <code>2</code> and <code>3</code>. You can make the test pass by modifying your expectations to consider the two new steps, like this:</p><pre class="brush: php; title: ; notranslate">function testDemonstratePHPUnitCallIndexingOnTheSameClass() {
	$someObject = new SomeClass();
	$firstValue = 'first value';
	$secondValue = 'second value';
	// With PHPUnit
	$phpunitMock = $this-&gt;getMock('AClassToBeMocked');
	$phpunitMock-&gt;expects($this-&gt;at(0))-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($firstValue));
	$phpunitMock-&gt;expects($this-&gt;at(1))-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($secondValue));
	$phpunitMock-&gt;expects($this-&gt;at(2))-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($firstValue));
	$phpunitMock-&gt;expects($this-&gt;at(3))-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($secondValue));
	// Expect the returned value
	$this-&gt;assertEquals('first value second value', $someObject-&gt;concatenate($phpunitMock));
	$this-&gt;assertEquals('first value second value', $someObject-&gt;concatenate($phpunitMock));
}</pre><p>You can probably live with this code, but Mockery makes this scenario trivial. Don&#8217;t believe me? Take a look:</p><pre class="brush: php; title: ; notranslate">function testMultipleReturnValuesWithMockery() {
	$someObject = new SomeClass();
	$firstValue = 'first value';
	$secondValue = 'second value';
	// With Mockery
	$mockeryMock = \Mockery::mock('AnInexistentClass');
	$mockeryMock-&gt;shouldReceive('someMethod')-&gt;andReturn($firstValue, $secondValue, $firstValue, $secondValue);
	// Expect the returned value
	$this-&gt;assertEquals('first value second value', $someObject-&gt;concatenate($mockeryMock));
	$this-&gt;assertEquals('first value second value', $someObject-&gt;concatenate($mockeryMock));
}</pre><p>Like PHPUnit, Mockery uses index counting, but we don&#8217;t have to worry about indices. Instead, we simply list all the expected values, and Mockery returns them in order.</p><p>Additionally, PHPUnit returns <code>NULL</code> for unspecified indexes, but Mockery always returns the last specified value. That&#8217;s a nice touch.</p><h3>Try Multiple Methods with Indexing</h3><p>Let&#8217;s introduce a second method into our code, the <code>concatWithMinus()</code> method:</p><pre class="brush: php; title: ; notranslate">class SomeClass {
	function doSomething($anotherObject) {
		return $anotherObject-&gt;someMethod();
	}
	function concatenate($anotherObject) {
		return $anotherObject-&gt;someMethod() . ' ' . $anotherObject-&gt;someMethod();
	}
	function concatWithMinus($anotherObject) {
		return $anotherObject-&gt;anotherMethod() . ' - ' . $anotherObject-&gt;anotherMethod();
	}
}</pre><p>This method behaves similarly to <code>concatenate()</code>, but it concatenates the string values with &#8220;<code> - </code>&#8221; as opposed to a single space. Because these two methods perform similar tasks, it makes sense to to test them inside the same test method to avoid duplicate testing.</p><p>As demonstrated in the above code, the second function uses a different mocked method called <code>anotherMethod()</code>. I made this change to force us to mock both methods in our tests. Our mockable class now looks like this:</p><pre class="brush: php; title: ; notranslate">class AClassToBeMocked {
	function someMethod() {
	}
	function anotherMethod() {
	}
}</pre><p>Testing this with PHPUnit might look like the following:</p><pre class="brush: php; title: ; notranslate">function testPHPUnitIndexingOnMultipleMethods() {
	$someObject = new SomeClass();
	$firstValue = 'first value';
	$secondValue = 'second value';
	// With PHPUnit
	$phpunitMock = $this-&gt;getMock('AClassToBeMocked');
	// First and second call on the semeMethod:
	$phpunitMock-&gt;expects($this-&gt;at(0))-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($firstValue));
	$phpunitMock-&gt;expects($this-&gt;at(1))-&gt;method('someMethod')-&gt;will($this-&gt;returnValue($secondValue));
	// Expect the returned value
	$this-&gt;assertEquals('first value second value', $someObject-&gt;concatenate($phpunitMock));
	// First and second call on the anotherMethod:
	$phpunitMock-&gt;expects($this-&gt;at(0))-&gt;method('anotherMethod')-&gt;will($this-&gt;returnValue($firstValue));
	$phpunitMock-&gt;expects($this-&gt;at(1))-&gt;method('anotherMethod')-&gt;will($this-&gt;returnValue($secondValue));
	// Expect the returned value
	$this-&gt;assertEquals('first value - second value', $someObject-&gt;concatWithMinus($phpunitMock));
}</pre><p>The logic is sound. Define two different expectations for each method and specify the return value. This works only with PHPUnit 3.6 or newer.</p><div
class="tip-shortcode"><p><strong>Please Note:</strong> PHPunit 3.5 and older had a bug which did not reset the index for each method, resulting in unexpected return values for mocked methods.</p></div><p>Let&#8217;s look at the same scenario with Mockery. Once again, we get much cleaner code. See for yourself:</p><pre class="brush: php; title: ; notranslate">function testMultipleReturnValuesForDifferentFunctionsWithMockery() {
	$someObject = new SomeClass();
	$firstValue = 'first value';
	$secondValue = 'second value';
	// With Mockery
	$mockeryMock = \Mockery::mock('AnInexistentClass');
	$mockeryMock-&gt;shouldReceive('someMethod')-&gt;andReturn($firstValue, $secondValue);
	$mockeryMock-&gt;shouldReceive('anotherMethod')-&gt;andReturn($firstValue, $secondValue);
	// Expect the returned value
	$this-&gt;assertEquals('first value second value', $someObject-&gt;concatenate($mockeryMock));
	$this-&gt;assertEquals('first value - second value', $someObject-&gt;concatWithMinus($mockeryMock));
}</pre><hr
/><h2>Return Values Based on Given Parameter</h2><p>Honestly, this is something PHPUnit simply cannot do. At the time of this writing, PHPUnit does not permit you to return different values from the same function based on the function&#8217;s parameter. Therefore, the following test fails:</p><pre class="brush: php; title: ; notranslate">
// [...] //
function testPHUnitCandDecideByParameter() {
	$someObject = new SomeClass();
	// With PHPUnit
	$phpunitMock = $this-&gt;getMock('AClassToBeMocked');
	$phpunitMock-&gt;expects($this-&gt;any())-&gt;method('getNumber')-&gt;with(2)-&gt;will($this-&gt;returnValue(2));
	$phpunitMock-&gt;expects($this-&gt;any())-&gt;method('getNumber')-&gt;with(3)-&gt;will($this-&gt;returnValue(3));
	$this-&gt;assertEquals(4, $someObject-&gt;doubleNumber($phpunitMock, 2));
	$this-&gt;assertEquals(6, $someObject-&gt;doubleNumber($phpunitMock, 3));
}
class AClassToBeMocked {
// [...] //
	function getNumber($number) {
		return $number;
	}
}
class SomeClass {
	// [...] //
	function doubleNumber($anotherObject, $number) {
		return $anotherObject-&gt;getNumber($number) * 2;
	}
}</pre><p>Please ignore the fact that there is no logic in this example; it would fail even if it was present. This code, however, does help illustrate the idea.</p><p>This test fails because PHPUnit cannot differentiate between the two expectations in the test. The second expectation, expecting parameter <code>3</code>, simply overrides the first expecting parameter <code>2</code>. If you attempt to run this test, you get the following error:</p><pre class="brush: xml; title: ; notranslate">Expectation failed for method name is equal to &lt;string:getNumber&gt; when invoked zero or more times
Parameter 0 for invocation AClassToBeMocked::getNumber(2) does not match expected value.
Failed asserting that 2 matches expected 3.</pre><p>Mockery can do this, and the code below works exactly as you would expect it to work. The method returns different values based on its provided parameters:</p><pre class="brush: php; title: ; notranslate">function testMockeryReturningDifferentValuesBasedOnParameter() {
	$someObject = new SomeClass();
	// Mockery
	$mockeryMock = \Mockery::mock('AnInexistentClass');
	$mockeryMock-&gt;shouldReceive('getNumber')-&gt;with(2)-&gt;andReturn(2);
	$mockeryMock-&gt;shouldReceive('getNumber')-&gt;with(3)-&gt;andReturn(3);
	$this-&gt;assertEquals(4, $someObject-&gt;doubleNumber($mockeryMock, 2));
	$this-&gt;assertEquals(6, $someObject-&gt;doubleNumber($mockeryMock, 3));
}</pre><hr
/><h2>Partial Mocks</h2><p>Sometimes, you want to mock only specific methods on your object (as opposed to mocking an entire object). The following <code>Calculator</code> class already exists; we want to only mock certain methods:</p><pre class="brush: php; title: ; notranslate">class Calculator {
	function add($firstNo, $secondNo) {
		return $firstNo + $secondNo;
	}
	function subtract($firstNo, $secondNo) {
		return $firstNo - $secondNo;
	}
	function multiply($value, $multiplier) {
		$newValue = 0;
		for($i=0;$i&lt;$multiplier;$i++)
			$newValue = $this-&gt;add($newValue, $value);
		return $newValue;
	}
}</pre><p>This <code>Calculator</code> class has three methods: <code>add()</code>, <code>subtract()</code>, and <code>multiply()</code>. Multiply uses a loop to perform the multiplication by calling the <code>add()</code> for a specified amount of times (e.g. <code>2 x 3</code> is really <code>2 + 2 + 2</code>).</p><p>Let&#8217;s assume that we want to test <code>multiply()</code> in total isolation; so, we&#8217;ll mock <code>add()</code> and check for specific behavior on <code>multiply()</code>. Here are some possible tests:</p><pre class="brush: php; title: ; notranslate">function testPartialMocking() {
	$value = 3;
	$multiplier = 2;
	$result = 6;
	// PHPUnit
	$phpMock = $this-&gt;getMock('Calculator', array('add'));
	$phpMock-&gt;expects($this-&gt;exactly(2))-&gt;method('add')-&gt;will($this-&gt;returnValue($result));
	$this-&gt;assertEquals($result, $phpMock-&gt;multiply($value,$multiplier));
	// Mockery
	$mockeryMock = \Mockery::mock(new Calculator);
	$mockeryMock-&gt;shouldReceive('add')-&gt;andReturn($result);
	$this-&gt;assertEquals($result, $mockeryMock-&gt;multiply($value,$multiplier));
	// Mockery extended test checking parameters
	$mockeryMock2 = \Mockery::mock(new Calculator);
	$mockeryMock2-&gt;shouldReceive('add')-&gt;with(0,3)-&gt;andReturn(3);
	$mockeryMock2-&gt;shouldReceive('add')-&gt;with(3,3)-&gt;andReturn(6);
	$this-&gt;assertEquals($result, $mockeryMock2-&gt;multiply($value,$multiplier));
}</pre><blockquote
class="pullquote"><p>Mockery offers&#8230;a very natural way to express mocked expectations.</p></blockquote><p>The first PHPUnit test is anemic; it simply tests that the method <code>add()</code> is called twice and it returns the final value on each call. It gets the job done, but it&#8217;s also a little complicated. PHPUnit forces you to pass the list of methods that you want to mock as second parameter to <code>$this->getMock()</code>. Otherwise, PHPUnit would mock all methods, each returning <code>NULL</code> by default. This list <strong>must</strong> be kept in concordance with the expectations you define on your mocked object.</p><p>For example, if I add a second expectation to <code>$phpMock</code>&#8216;s <code>substract()</code> method, PHPUnit would ignore it and call the original <code>substract()</code> method. That is, unless I explicitly specify the name of the method (<code>substract</code>) in the <code>$this->getmock()</code> statement.</p><p>Of course, Mockery is different by allowing you to provide a real object to <code>\Mockery::mock()</code>, and it automatically creates a partial mock. It achieves this by implementing a proxy-like solution for mocking. All the expectations you define are used, but Mockery falls back to the original method if you do not specify an expectation for that method.</p><div
class="tip-shortcode"><p><strong>Please Note:</strong> Mockery&#8217;s approach is very simple, but internal method calls do not pass through the mocked object.</p></div><p>This example is misleading, but it illustrates <strong>how not to use</strong> Mockery&#8217;s partial mocks. Yes, Mockery creates a partial mock if you pass a real object, but it only mocks <strong>only external calls</strong>. For example, based on the previous code, the <code>multiply()</code> method calls the real <code>add()</code> method. Go ahead and try to change the last expectation from <code>...->andReturn(6)</code> to <code>...->andReturn(7)</code>. The test should obviously fail, but it doesn&#8217;t because the real <code>add()</code> executes instead of the mocked <code>add()</code> method.</p><p>But we can circumvent this issue by creating mocks like this:</p><pre class="brush: php; title: ; notranslate">//Instead of
$mockeryMock = \Mockery::mock(new Calculator);
// Create the mock like this
$mockeryMock = \Mockery::mock('Calculator[add]');</pre><p>While syntactically different, the concept is similar to PHPUnit&#8217;s approach: you have to list the mocked methods in two places. But for any other test, you can just simply pass the real object, which is much easier&#8211;especially when dealing with constructor parameters.</p><hr
/><h2>Dealing with Constructor Parameters</h2><p>Let&#8217;s add a constructor with two parameters to the <code>Calculator</code> class. The revised code:</p><pre class="brush: php; title: ; notranslate">class Calculator {
	public $myNumbers = array();
	function __construct($firstNo, $secondNo) {
		$this-&gt;myNumbers[]=$firstNo;
		$this-&gt;myNumbers[]=$secondNo;
	}
	// [...] //
}</pre><p>Every test in this article will fail after adding this constructor. More precisely, the <code>testPartialMock()</code> test results in the following error:</p><pre class="brush: xml; title: ; notranslate">Missing argument 1 for Calculator::__construct(),
called in /usr/share/php/PHPUnit/Framework/MockObject/Generator.php
on line 224 and defined</pre><p>PHPUnit tries to mock the real object by automatically calling the constructor, expecting to have the parameters correctly set. There are two ways around this problem: either set the parameters, or don&#8217;t call the constructor.</p><pre class="brush: php; title: ; notranslate">//Specify Constructor Parameters
$phpMock = $this-&gt;getMock('Calculator', array('add'), array(1,2));
//Do not call original constructor
$phpMock = $this-&gt;getMock('Calculator', array('add'), array(), '', false);</pre><p>Mockery <em>automagically</em> works around this problem. It&#8217;s okay not to specify a constructor parameter; Mockery will simply not call the constructor. But you can specify a list of constructor parameters for Mockery to use. For example:</p><pre class="brush: php; title: ; notranslate">function testMockeryConstructorParameters() {
	$result = 6;
	// Mockery
	// Do not call constructor
	$noConstrucCall = \Mockery::mock('Calculator[add]');
	$noConstrucCall-&gt;shouldReceive('add')-&gt;andReturn($result);
	// Use constructor parameters
	$withConstructParams = \Mockery::mock('Calculator[add]', array(1,2));
	$withConstructParams-&gt;shouldReceive('add')-&gt;andReturn($result);
	// User real object with real values and mock over it
	$realCalculator = new Calculator(1,2);
	$mockRealObj = \Mockery::mock($realCalculator);
	$mockRealObj-&gt;shouldReceive('add')-&gt;andReturn($result);
}</pre><hr
/><h2>Technical Considerations</h2><p>Mockery is another library that integrates your tests, and you may want to consider what technical implications this may have.</p><ul><li>Mockery uses a lot of memory. You will have to increase the maximum memory to 512MB if you want to run many tests(say over 1000 tests with more than 3000 assertions). See <code>php.ini</code> documentation for further details.</li><li>You have to organize your tests to run in separate processes, when mocking static methods and static method calls.</li><li>You can auto-load Mockery into every test by using PHPUnit&#8217;s bootstrap functionality (helpful when you have many tests and you don&#8217;t want to repeat yourself).</li><li>You can automate the call to <code>\Mockery::close()</code> in each test&#8217;s <code>tearDown()</code> by editing <code>phpunit.xml</code>.</li></ul><hr
/><h2>Final Conclusions</h2><p>PHPUnit certainly has its issues, especially when it comes to functionality and expressiveness. Mockery can greatly improve your mocking experience by making your tests easy to write and understand &#8211; but it&#8217;s not perfect (there&#8217;s no such thing!).</p><p>This tutorial has highlighted many key aspects of Mockery, but, honestly, we&#8217;ve barely scratched the surface. Be sure to explore the <a
href="https://github.com/padraic/Mockery">project&#8217;s Github repository</a> to learn more.</p><p>Thanks for reading!</p>
<p><a href="http://feedads.g.doubleclick.net/~a/liB_MlxAy3GFaYfAxEUxGaJGmfo/0/da"><img src="http://feedads.g.doubleclick.net/~a/liB_MlxAy3GFaYfAxEUxGaJGmfo/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/liB_MlxAy3GFaYfAxEUxGaJGmfo/1/da"><img src="http://feedads.g.doubleclick.net/~a/liB_MlxAy3GFaYfAxEUxGaJGmfo/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=Fz9EiD5jKew:jb7HtXeNL7M:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=Fz9EiD5jKew:jb7HtXeNL7M:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=Fz9EiD5jKew:jb7HtXeNL7M:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=Fz9EiD5jKew:jb7HtXeNL7M:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=Fz9EiD5jKew:jb7HtXeNL7M:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=Fz9EiD5jKew:jb7HtXeNL7M:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=Fz9EiD5jKew:jb7HtXeNL7M:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=Fz9EiD5jKew:jb7HtXeNL7M:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/Fz9EiD5jKew" height="1" width="1"/>";s:14:"date_timestamp";i:1353517004;}i:4;a:13:{s:5:"title";s:41:"Get Connected to the Backbone: New Course";s:4:"link";s:54:"http://feedproxy.google.com/~r/nettuts/~3/ndnyFSkqyJ0/";s:8:"comments";s:100:"http://net.tutsplus.com/tutorials/javascript-ajax/get-connected-to-the-backbone-new-course/#comments";s:7:"pubdate";s:31:"Wed, 21 Nov 2012 01:14:41 +0000";s:2:"dc";a:1:{s:7:"creator";s:11:"Jeffrey Way";}s:8:"category";s:48:"JavaScript & AJAXbackbone.jslaravelPremiumVideos";s:4:"guid";s:32:"http://net.tutsplus.com/?p=28168";s:11:"description";s:5759:"<a
href='http://rss.buysellads.com/click.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28168&c=253727041' target='_blank'><img
src='http://rss.buysellads.com/img.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28168&c=253727041' border='0' alt='' /></a><p>I&#8217;m pleased to announce that, after many hours of work, my newest <a
href="https://tutsplus.com/course/connected-to-the-backbone/">Tuts+ Premium</a> course on <a
href="http://backbonejs.org">Backbone</a> is now available &#8211; and the first eight lessons are free to all! See the lesson outline after the jump.<br
/> <span
id="more-28168"></span></p><hr
/><h2>Lesson Outline</h2><ul><li><a
href="https://tutsplus.com/lesson/introduction-35/">Introduction</a> <strong>(Free)</strong><li><a
href="https://tutsplus.com/lesson/installation-3/">Installation</a> <strong>(Free)</strong><li><a
href="https://tutsplus.com/lesson/data-types-primer/">Data Types Primer</a> <strong>(Free)</strong><li><a
href="https://tutsplus.com/lesson/your-first-backbone-model/">Your First Backbone Model</a> <strong>(Free)</strong><li><a
href="https://tutsplus.com/lesson/validating-models/">Validating Models</a> <strong>(Free)</strong><li><a
href="https://tutsplus.com/lesson/views/">Views</a> <strong>(Free)</strong><li><a
href="https://tutsplus.com/lesson/inline-templates/">Inline Templates</a> <strong>(Free)</strong><li><a
href="https://tutsplus.com/lesson/external-templates/">External Templates</a> <strong>(Free)</strong><li><a
href="https://tutsplus.com/lesson/collections/">Collections</a> <strong>(Free)</strong><li><a
href="https://tutsplus.com/lesson/collection-views/">Collection Views</a><li><a
href="https://tutsplus.com/lesson/template-helpers/">Template Helpers</a><li><a
href="https://tutsplus.com/lesson/namespacing-2/">Namespacing</a><li><a
href="https://tutsplus.com/lesson/dom-events/">DOM Events</a><li><a
href="https://tutsplus.com/lesson/custom-events/">Custom Events</a><li><a
href="https://tutsplus.com/lesson/destroying-models/">Destroying Models</a><li><a
href="https://tutsplus.com/lesson/creating-new-tasks/">Creating New Tasks</a><li><a
href="https://tutsplus.com/lesson/routes-101/">Routes 101</a><li><a
href="https://tutsplus.com/lesson/wildcards-and-splats/">Wildcards and Splats</a><li><a
href="https://tutsplus.com/lesson/triggering-custom-events/">Triggering Custom Events</a><li><a
href="https://tutsplus.com/lesson/backbone-and-the-server-laravel-4/">Backbone And The Server (Laravel 4)</a><li><a
href="https://tutsplus.com/lesson/updating-rows/">Updating Rows</a><li><a
href="https://tutsplus.com/lesson/deleting-rows/">Deleting Rows</a><li><a
href="https://tutsplus.com/lesson/creating-records/">Creating Records</a><li><a
href="https://tutsplus.com/lesson/fetching-rows-into-a-collection/">Fetching Rows Into A Collection</a><li><a
href="https://tutsplus.com/lesson/laravel-setup/">Laravel Setup</a><li><a
href="https://tutsplus.com/lesson/models-views-and-collections/">Models, Views, and Collections</a><li><a
href="https://tutsplus.com/lesson/creating-new-contacts/">Creating New Contacts</a><li><a
href="https://tutsplus.com/lesson/displaying-contacts/">Displaying Contacts</a><li><a
href="https://tutsplus.com/lesson/editing-and-deleting-contacts/">Editing and Deleting Contacts</a><li><a
href="https://tutsplus.com/lesson/coffeescript-and-backbone/">CoffeeScript and Backbone</a><li><a
href="https://tutsplus.com/lesson/further-learning/">Further Learning</a></ul><hr
/><h2>Tuts+ Premium</h2><p><a
style="float: right; margin-left: 20px;" href="http://tutsplus.com/take-the-tour/"><img
src="https://tutsplus.s3.amazonaws.com/banners/250x250.jpg" style="width: 200px;"></a>You&#8217;re already familiar with us, thanks to our various hugely popular free courses, such as <a
href="https://tutsplus.com/course/30-days-to-learn-jquery/">30 Days to Learn jQuery</a> and <a
href="https://tutsplus.com/course/30-days-to-learn-html-and-css/">30 Days To Learn HTML and CSS</a>; however, did you know that we&#8217;re releasing as many as fifteen new courses every single month?</p><p>In December alone, we&#8217;ll be releasing new courses on Sinatra, Mac Application Development, Agile Design Patterns, Laravel, and much more! If that sounds good, <a
href="http://tutsplus.com">come and say hi</a>!</p>
<p><a href="http://feedads.g.doubleclick.net/~a/ob6dz8QrsScC3CwzFeLBS_JMwo8/0/da"><img src="http://feedads.g.doubleclick.net/~a/ob6dz8QrsScC3CwzFeLBS_JMwo8/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/ob6dz8QrsScC3CwzFeLBS_JMwo8/1/da"><img src="http://feedads.g.doubleclick.net/~a/ob6dz8QrsScC3CwzFeLBS_JMwo8/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=ndnyFSkqyJ0:4-REXlIklIY:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=ndnyFSkqyJ0:4-REXlIklIY:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=ndnyFSkqyJ0:4-REXlIklIY:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=ndnyFSkqyJ0:4-REXlIklIY:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=ndnyFSkqyJ0:4-REXlIklIY:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=ndnyFSkqyJ0:4-REXlIklIY:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=ndnyFSkqyJ0:4-REXlIklIY:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=ndnyFSkqyJ0:4-REXlIklIY:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/ndnyFSkqyJ0" height="1" width="1"/>";s:3:"wfw";a:1:{s:10:"commentrss";s:96:"http://net.tutsplus.com/tutorials/javascript-ajax/get-connected-to-the-backbone-new-course/feed/";}s:5:"slash";a:1:{s:8:"comments";s:2:"16";}s:10:"feedburner";a:1:{s:8:"origlink";s:91:"http://net.tutsplus.com/tutorials/javascript-ajax/get-connected-to-the-backbone-new-course/";}s:7:"summary";s:5759:"<a
href='http://rss.buysellads.com/click.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28168&c=253727041' target='_blank'><img
src='http://rss.buysellads.com/img.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28168&c=253727041' border='0' alt='' /></a><p>I&#8217;m pleased to announce that, after many hours of work, my newest <a
href="https://tutsplus.com/course/connected-to-the-backbone/">Tuts+ Premium</a> course on <a
href="http://backbonejs.org">Backbone</a> is now available &#8211; and the first eight lessons are free to all! See the lesson outline after the jump.<br
/> <span
id="more-28168"></span></p><hr
/><h2>Lesson Outline</h2><ul><li><a
href="https://tutsplus.com/lesson/introduction-35/">Introduction</a> <strong>(Free)</strong><li><a
href="https://tutsplus.com/lesson/installation-3/">Installation</a> <strong>(Free)</strong><li><a
href="https://tutsplus.com/lesson/data-types-primer/">Data Types Primer</a> <strong>(Free)</strong><li><a
href="https://tutsplus.com/lesson/your-first-backbone-model/">Your First Backbone Model</a> <strong>(Free)</strong><li><a
href="https://tutsplus.com/lesson/validating-models/">Validating Models</a> <strong>(Free)</strong><li><a
href="https://tutsplus.com/lesson/views/">Views</a> <strong>(Free)</strong><li><a
href="https://tutsplus.com/lesson/inline-templates/">Inline Templates</a> <strong>(Free)</strong><li><a
href="https://tutsplus.com/lesson/external-templates/">External Templates</a> <strong>(Free)</strong><li><a
href="https://tutsplus.com/lesson/collections/">Collections</a> <strong>(Free)</strong><li><a
href="https://tutsplus.com/lesson/collection-views/">Collection Views</a><li><a
href="https://tutsplus.com/lesson/template-helpers/">Template Helpers</a><li><a
href="https://tutsplus.com/lesson/namespacing-2/">Namespacing</a><li><a
href="https://tutsplus.com/lesson/dom-events/">DOM Events</a><li><a
href="https://tutsplus.com/lesson/custom-events/">Custom Events</a><li><a
href="https://tutsplus.com/lesson/destroying-models/">Destroying Models</a><li><a
href="https://tutsplus.com/lesson/creating-new-tasks/">Creating New Tasks</a><li><a
href="https://tutsplus.com/lesson/routes-101/">Routes 101</a><li><a
href="https://tutsplus.com/lesson/wildcards-and-splats/">Wildcards and Splats</a><li><a
href="https://tutsplus.com/lesson/triggering-custom-events/">Triggering Custom Events</a><li><a
href="https://tutsplus.com/lesson/backbone-and-the-server-laravel-4/">Backbone And The Server (Laravel 4)</a><li><a
href="https://tutsplus.com/lesson/updating-rows/">Updating Rows</a><li><a
href="https://tutsplus.com/lesson/deleting-rows/">Deleting Rows</a><li><a
href="https://tutsplus.com/lesson/creating-records/">Creating Records</a><li><a
href="https://tutsplus.com/lesson/fetching-rows-into-a-collection/">Fetching Rows Into A Collection</a><li><a
href="https://tutsplus.com/lesson/laravel-setup/">Laravel Setup</a><li><a
href="https://tutsplus.com/lesson/models-views-and-collections/">Models, Views, and Collections</a><li><a
href="https://tutsplus.com/lesson/creating-new-contacts/">Creating New Contacts</a><li><a
href="https://tutsplus.com/lesson/displaying-contacts/">Displaying Contacts</a><li><a
href="https://tutsplus.com/lesson/editing-and-deleting-contacts/">Editing and Deleting Contacts</a><li><a
href="https://tutsplus.com/lesson/coffeescript-and-backbone/">CoffeeScript and Backbone</a><li><a
href="https://tutsplus.com/lesson/further-learning/">Further Learning</a></ul><hr
/><h2>Tuts+ Premium</h2><p><a
style="float: right; margin-left: 20px;" href="http://tutsplus.com/take-the-tour/"><img
src="https://tutsplus.s3.amazonaws.com/banners/250x250.jpg" style="width: 200px;"></a>You&#8217;re already familiar with us, thanks to our various hugely popular free courses, such as <a
href="https://tutsplus.com/course/30-days-to-learn-jquery/">30 Days to Learn jQuery</a> and <a
href="https://tutsplus.com/course/30-days-to-learn-html-and-css/">30 Days To Learn HTML and CSS</a>; however, did you know that we&#8217;re releasing as many as fifteen new courses every single month?</p><p>In December alone, we&#8217;ll be releasing new courses on Sinatra, Mac Application Development, Agile Design Patterns, Laravel, and much more! If that sounds good, <a
href="http://tutsplus.com">come and say hi</a>!</p>
<p><a href="http://feedads.g.doubleclick.net/~a/ob6dz8QrsScC3CwzFeLBS_JMwo8/0/da"><img src="http://feedads.g.doubleclick.net/~a/ob6dz8QrsScC3CwzFeLBS_JMwo8/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/ob6dz8QrsScC3CwzFeLBS_JMwo8/1/da"><img src="http://feedads.g.doubleclick.net/~a/ob6dz8QrsScC3CwzFeLBS_JMwo8/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=ndnyFSkqyJ0:4-REXlIklIY:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=ndnyFSkqyJ0:4-REXlIklIY:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=ndnyFSkqyJ0:4-REXlIklIY:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=ndnyFSkqyJ0:4-REXlIklIY:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=ndnyFSkqyJ0:4-REXlIklIY:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=ndnyFSkqyJ0:4-REXlIklIY:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=ndnyFSkqyJ0:4-REXlIklIY:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=ndnyFSkqyJ0:4-REXlIklIY:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/ndnyFSkqyJ0" height="1" width="1"/>";s:14:"date_timestamp";i:1353460481;}i:5;a:13:{s:5:"title";s:50:"Building Single Page Web Apps With Sinatra: Part 2";s:4:"link";s:54:"http://feedproxy.google.com/~r/nettuts/~3/9gJ5KPZax8Q/";s:8:"comments";s:109:"http://net.tutsplus.com/tutorials/javascript-ajax/building-single-page-web-apps-with-sinatra-part-2/#comments";s:7:"pubdate";s:31:"Mon, 19 Nov 2012 21:40:12 +0000";s:2:"dc";a:1:{s:7:"creator";s:16:"Jonathan Cutrell";}s:8:"category";s:45:"JavaScript & AJAXRubyTutorialsknockoutsinatra";s:4:"guid";s:32:"http://net.tutsplus.com/?p=28129";s:11:"description";s:28571:"<a
href='http://rss.buysellads.com/click.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28129&c=1533308860' target='_blank'><img
src='http://rss.buysellads.com/img.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28129&c=1533308860' border='0' alt='' /></a><p>In the <a
href="http://net.tutsplus.com/tutorials/javascript-ajax/building-single-page-web-apps-with-sinatra-part-1/">first part</a> of this mini-series, we created the basic structure of a to-do application using a Sinatra JSON interface to a SQLite database, and a Knockout-powered front-end that allows us to add tasks to our database. In this final part, we&#8217;ll cover some slightly more advanced functionality in Knockout, including sorting, searching, updating, and deleting.</p><p><span
id="more-28129"></span></p><p>Let&#8217;s start where we left off; here is the relevant portion of our <code>index.erb</code> file.</p><pre class="brush: xml; title: ; notranslate">&lt;div id=&quot;container&quot;&gt;
            &lt;section id=&quot;taskforms&quot; class=&quot;clearfix&quot;&gt;
                &lt;div id=&quot;newtaskform&quot; class=&quot;floatleft fifty&quot;&gt;
                    &lt;h2&gt;Create a New Task&lt;/h2&gt;
                    &lt;form id=&quot;addtask&quot; data-bind=&quot;submit: addTask&quot;&gt;
                        &lt;input data-bind=&quot;value: newTaskDesc&quot;&gt;
                        &lt;input type=&quot;submit&quot;&gt;
                    &lt;/form&gt;
                &lt;/div&gt;
                &lt;div id=&quot;tasksearchform&quot; class=&quot;floatright fifty&quot;&gt;
                    &lt;h2&gt;Search Tasks&lt;/h2&gt;
                    &lt;form id=&quot;searchtask&quot;&gt;
                        &lt;input&gt;
                    &lt;/form&gt;
                &lt;/div&gt;
            &lt;/section&gt;
            &lt;section id=&quot;tasktable&quot;&gt;
                &lt;h2&gt;Incomplete Tasks remaining: &lt;span&gt;&lt;/span&gt;&lt;/h2&gt;
                &lt;a&gt;Delete All Complete Tasks&lt;/a&gt;
                &lt;table&gt;
                    &lt;tbody&gt;&lt;tr&gt;
                        &lt;th&gt;DB ID&lt;/th&gt;
                        &lt;th&gt;Description&lt;/th&gt;
                        &lt;th&gt;Date Added&lt;/th&gt;
                        &lt;th&gt;Date Modified&lt;/th&gt;
                        &lt;th&gt;Complete?&lt;/th&gt;
                        &lt;th&gt;Delete&lt;/th&gt;
                    &lt;/tr&gt;
                    &lt;!-- ko foreach: tasks --&gt;
                    &lt;tr&gt;
                        &lt;td data-bind=&quot;text: id&quot;&gt;&lt;/td&gt;
                        &lt;td data-bind=&quot;text: description&quot;&gt;&lt;/td&gt;
                        &lt;td data-bind=&quot;text: created_at&quot;&gt;&lt;/td&gt;
                        &lt;td data-bind=&quot;text: updated_at&quot;&gt;&lt;/td&gt;
                        &lt;td&gt;&lt;input type=&quot;checkbox&quot; data-bind=&quot;checked: complete, click: $parent.markAsComplete&quot;&gt; &lt;/td&gt;
                        &lt;td data-bind=&quot;click: $parent.destroyTask&quot; class=&quot;destroytask&quot;&gt;&lt;a&gt;X&lt;/a&gt;&lt;/td&gt;
                    &lt;/tr&gt;
                    &lt;!-- /ko --&gt;
                &lt;/tbody&gt;&lt;/table&gt;
            &lt;/section&gt;
        &lt;/div&gt;</pre><hr/><h2>Sort</h2><p>Sorting is a common task used in many applications. In our case, we want to sort the task list by any header field in our task-list table. We will start by adding the following code to the <code>TaskViewModel</code>:</p><pre class="brush: jscript; title: ; notranslate">t.sortedBy = [];
t.sort = function(field){
    if (t.sortedBy.length &amp;&amp; t.sortedBy[0] == field &amp;&amp; t.sortedBy[1]==1){
            t.sortedBy[1]=0;
            t.tasks.sort(function(first,next){
                if (!next[field].call()){ return 1; }
                return (next[field].call() &lt; first[field].call()) ? 1 : (next[field].call() == first[field].call()) ? 0 : -1;
            });
    } else {
        t.sortedBy[0] = field;
        t.sortedBy[1] = 1;
        t.tasks.sort(function(first,next){
            if (!first[field].call()){ return 1; }
            return (first[field].call() &lt; next[field].call()) ? 1 : (first[field].call() == next[field].call()) ? 0 : -1;
        });
    }
}</pre><blockquote
class="pullquote"><p>Knockout provides a sort function for observable arrays</p></blockquote><p>First, we define a <code>sortedBy</code> array as a property of our view model. This allows us to store if and how the collection is sorted.</p><p>Next is the <code>sort()</code> function. It accepts a <code>field</code> argument (the field we want to sort by) and checks if the tasks are sorted by the current sorting scheme. We want to sort using a &#8220;toggle&#8221; type of process. For example, sort by description once, and the tasks arrange in alphabetical order. Sort by description again, and the tasks arrange in reverse-alphabetical order. This <code>sort()</code> function supports this behavior by checking the most recent sort scheme and comparing it to what the user wants to sort by.</p><p>Knockout provides a sort function for observable arrays. It accepts a function as an argument that controls how the array should be sorted. This function compares two elements from the array and returns <code>1</code>, <code>0</code>, or <code>-1</code> as a result of that comparison. All like values are grouped together (which will be useful for grouping complete and incomplete tasks together).</p><p>Note: the properties of the array elements must be called rather than simply accessed; these properties are actually functions that return the value of the property if called without any arguments.</p><p>Next, we define the bindings on the table headers in our view.</p><pre class="brush: xml; title: ; notranslate">&lt;th data-bind=&quot;click: function(){ sort('id') }&quot;&gt;DB ID&lt;/th&gt;
&lt;th data-bind=&quot;click: function(){ sort('description') }&quot;&gt;Description&lt;/th&gt;
&lt;th data-bind=&quot;click: function(){ sort('created_at') }&quot;&gt;Date Added&lt;/th&gt;
&lt;th data-bind=&quot;click: function(){ sort('updated_at') }&quot;&gt;Date Modified&lt;/th&gt;
&lt;th data-bind=&quot;click: function(){ sort('complete') }&quot;&gt;Complete?&lt;/th&gt;
&lt;th&gt;Delete&lt;/th&gt;</pre><p>These bindings allow each of the headers to trigger a sort based on the passed string value; each of these directly maps to the <code>Task</code> model.</p><hr/><h2>Mark As Complete</h2><p>Next, we want to be able to mark a task as complete, and we&#8217;ll accomplish this by simply clicking the checkbox associated with a particular task. Let&#8217;s start by defining a method in the <code>TaskViewModel</code>:</p><pre class="brush: jscript; title: ; notranslate">t.markAsComplete = function(task) {
    if (task.complete() == true){
        task.complete(true);
    } else {
        task.complete(false);
    }
    task._method = &quot;put&quot;;
    t.saveTask(task);
    return true;
}</pre><p>The <code>markAsComplete()</code> method accepts the task as an argument, which is automatically passed by Knockout when iterating over a collection of items. We then toggle the <code>complete</code> property, and add a <code>._method="put"</code> property to the task. This allows <code>DataMapper</code> to use the HTTP <code>PUT</code> verb as opposed to <code>POST</code>. We then use our convenient <code>t.saveTask()</code> method to save the changes to the database. Finally, we return <code>true</code> because returning <code>false</code> prevents the checkbox from changing state.</p><p>Next, we change the view by replacing the checkbox code inside the task loop with the following:</p><pre class="brush: xml; title: ; notranslate">&lt;input type=&quot;checkbox&quot; data-bind=&quot;checked: complete, click: $parent.markAsComplete&quot;&gt;</pre><p>This tells us two things:</p><ol><li>The box is checked if <code>complete</code> is true.</li><li>On click, run the <code>markAsComplete()</code> function from the parent (<code>TaskViewModel</code> in this case). This automatically passes the current task in the loop.</p></ol><hr/><h2>Deleting Tasks</h2><p>To delete a task, we simply use a few convenience methods and call <code>saveTask()</code>. In our <code>TaskViewModel</code>, add the following:</p><pre class="brush: jscript; title: ; notranslate">t.destroyTask = function(task) {
    task._method = &quot;delete&quot;;
    t.tasks.destroy(task);
    t.saveTask(task);
};</pre><p>This function adds a property similar to the &#8220;put&#8221; method for completing a task. The built-in <code>destroy()</code> method removes the passed-in task from the observable array. Finally, calling <code>saveTask()</code> destroys the task; that is, as long as the <code>._method</code> is set to &#8220;delete&#8221;.</p><p>Now we need to modify our view; add the following:</p><pre class="brush: xml; title: ; notranslate">&lt;td data-bind=&quot;click: $parent.destroyTask&quot; class=&quot;destroytask&quot;&gt;&lt;a&gt;X&lt;/a&gt;&lt;/td&gt;</pre><p>This is very similar in functionality to the complete checkbox. Note that the <code>class="destroytask"</code> is purely for styling purposes.</p><hr/><h2>Delete All Completed</h2><p>Next, we want to add the &#8220;delete all complete tasks&#8221; functionality. First, add the following code to the <code>TaskViewModel</code>:</p><pre class="brush: jscript; title: ; notranslate">t.removeAllComplete = function() {
    ko.utils.arrayForEach(t.tasks(), function(task){
        if (task.complete()){
            t.destroyTask(task);
        }
    });
}</pre><p>This function simply iterates over the tasks to determine which of them are complete, and we call the <code>destroyTask()</code> method for each complete task. In our view, add the following for the &#8220;delete all complete&#8221; link.</p><pre class="brush: xml; title: ; notranslate">&lt;a data-bind=&quot;click: removeAllComplete, visible: completeTasks().length &gt; 0 &quot;&gt;Delete All Complete Tasks&lt;/a&gt;</pre><p>Our click binding will work correctly, but we need to define <code>completeTasks()</code>. Add the following to our <code>TaskViewModel</code>:</p><pre class="brush: jscript; title: ; notranslate">t.completeTasks = ko.computed(function() {
    return ko.utils.arrayFilter(t.tasks(), function(task) { return (task.complete() &amp;&amp; task._method != &quot;delete&quot;) });
});</pre><p>This method is a <em>computed</em> property. These properties return a value that is computed &#8220;on the fly&#8221; when the model is updated. In this case, we return a filtered array that contains only complete tasks that are not marked for deletion. Then, we simply use this array&#8217;s <code>length</code> property to hide or show the &#8220;Delete All Completed Tasks&#8221; link.</p><hr/><h2>Incomplete Tasks Remaining</h2><p>Our interface should also display the amount of incomplete tasks. Similar to our <code>completeTasks()</code> function above, we define an <code>incompleteTasks()</code> function in <code>TaskViewModel</code>:</p><pre class="brush: jscript; title: ; notranslate">t.incompleteTasks = ko.computed(function() {
    return ko.utils.arrayFilter(t.tasks(), function(task) { return (!task.complete() &amp;&amp; task._method != &quot;delete&quot;) });
});</pre><p>We then access this computed filtered array in our view, like this:</p><pre class="brush: xml; title: ; notranslate">&lt;h2&gt;Incomplete Tasks remaining: &lt;span data-bind=&quot;text: incompleteTasks().length&quot;&gt;&lt;/span&gt;&lt;/h2&gt;</pre><hr/><h2>Style Completed Tasks</h2><p>We want to style the completed items differently from the tasks in the list, and we can do this in our view with Knockout&#8217;s <code>css</code> binding. Modify the <code>tr</code> opening tag in our task <code>arrayForEach()</code> loop to the following.</p><pre class="brush: xml; title: ; notranslate">&lt;tr data-bind=&quot;css: { 'complete': complete }, visible: isvisible&quot;&gt;</pre><p>This adds a <code>complete</code> CSS class to the table row for each task if its <code>complete</code> property is <code>true</code>.</p><hr/><h2>Clean Up Dates</h2><p>Let&#8217;s get rid of those ugly Ruby date strings. We&#8217;ll start by defining a <code>dateFormat</code> function in our <code>TaskViewModel</code>:</p><pre class="brush: jscript; title: ; notranslate">t.MONTHS = [&quot;Jan&quot;, &quot;Feb&quot;, &quot;Mar&quot;, &quot;Apr&quot;, &quot;May&quot;, &quot;Jun&quot;, &quot;Jul&quot;, &quot;Aug&quot;, &quot;Sep&quot;, &quot;Oct&quot;, &quot;Nov&quot;, &quot;Dec&quot;];
t.dateFormat = function(date){
    if (!date) { return &quot;refresh to see server date&quot;; }
    var d = new Date(date);
    return d.getHours() + &quot;:&quot; + d.getMinutes() + &quot;, &quot; + d.getDate() + &quot; &quot; + t.MONTHS[d.getMonth()] + &quot;, &quot; + d.getFullYear();
}</pre><p>This function is fairly straightforward. If for any reason the date is not defined, we simply need to refresh the browser to pull in the date in the initial <code>Task</code> fetching function. Otherwise, we create a human readable date with the plain JavaScript <code>Date</code> object with the help of the <code>MONTHS</code> array. (Note: it is not necessary to capitalize the name of the array <code>MONTHS</code>, of course; this is simply a way of knowing that this is a constant value that shouldn&#8217;t be changed.)</p><p>Next, we add the following changes to our view for the <code>created_at</code> and <code>updated_at</code> properties:</p><pre class="brush: xml; title: ; notranslate">&lt;td data-bind=&quot;text: $root.dateFormat(created_at())&quot;&gt;&lt;/td&gt;
&lt;td data-bind=&quot;text: $root.dateFormat(updated_at())&quot;&gt;&lt;/td&gt;</pre><p>This passes the <code>created_at</code> and <code>updated_at</code> properties to the <code>dateFormat()</code> function. Once again, it&#8217;s important to remember that properties of each task are not normal properties; they are functions. In order to retrieve their value, you must call the function (as shown in the above example). Note: <code>$root</code> is a keyword, defined by Knockout, that refers to the ViewModel. The <code>dateFormat()</code> method, for instance, is defined as a method of the root ViewModel (<code>TaskViewModel</code>).</p><hr/><h2>Searching Tasks</h2><p>We can search our tasks in a variety of ways, but we&#8217;ll keep things simple and perform a front-end search. Keep in mind, however, that it is likely that these search results will be database driven as the data grows for the sake of pagination. But for now, let&#8217;s define our <code>search()</code> method on <code>TaskViewModel</code>:</p><pre class="brush: jscript; title: ; notranslate">t.query = ko.observable('');
t.search = function(task){
    ko.utils.arrayForEach(t.tasks(), function(task){
        if (task.description() &amp;&amp; t.query() != &quot;&quot;){
            task.isvisible(task.description().toLowerCase().indexOf(t.query().toLowerCase()) &gt;= 0);
        } else if (t.query() == &quot;&quot;) {
            task.isvisible(true);
        } else {
            task.isvisible(false);
        }
    })
    return true;
}</pre><p>We can see that this iterates through the array of tasks and checks to see if <code>t.query()</code> (a regular observable value) is in the task description. Note that this check actually runs inside the <em>setter</em> function for the <code>task.isvisible</code> property. If the evaluation is <code>false</code>, the task isn&#8217;t found and the <code>isvisible</code> property is set to <code>false</code>. If the query is equal to an empty string, all tasks are set to be visible. If the task doesn&#8217;t have a description and the query is a non-empty value, the task is not a part of the returned data set and is hidden.</p><p>In our <code>index.erb</code> file, we set up our searching interface with the following code:</p><pre class="brush: xml; title: ; notranslate">&lt;form id=&quot;searchtask&quot;&gt;
    &lt;input data-bind=&quot;value: query, valueUpdate: 'keyup', event : { keyup : search}&quot;&gt;
&lt;/form&gt;</pre><p>The input value is set to the <code>ko.observable query</code>. Next, we see that the <code>keyup</code> event is specifically identified as a <code>valueUpdate</code> event. Lastly, we set a manual event binding to <code>keyup</code> to execute the search (<code>t.search()</code>) function. No form submission is necessary; the list of matching items will display and can still be sortable, deletable, etc. Therefore, all interactions work at all times.</p><hr/><h2>Final Code</h2><h4>index.erb</h4><pre class="brush: xml; title: ; notranslate">&lt;!DOCTYPE html &gt;
&lt;html&gt;
&lt;!--[if lt IE 7]&gt;      &lt;html class=&quot;no-js lt-ie9 lt-ie8 lt-ie7&quot;&gt; &lt;![endif]--&gt;
&lt;!--[if IE 7]&gt;         &lt;html class=&quot;no-js lt-ie9 lt-ie8&quot;&gt; &lt;![endif]--&gt;
&lt;!--[if IE 8]&gt;         &lt;html class=&quot;no-js lt-ie9&quot;&gt; &lt;![endif]--&gt;
&lt;!--[if gt IE 8]&gt;&lt;!--&gt;  &lt;!--&lt;![endif]--&gt;
    &lt;body&gt;
        &lt;meta charset=&quot;utf-8&quot;&gt;
        &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge,chrome=1&quot;&gt;
        &lt;title&gt;ToDo&lt;/title&gt;
        &lt;meta name=&quot;description&quot; content=&quot;&quot;&gt;
        &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width&quot;&gt;
        &lt;!-- Place favicon.ico and apple-touch-icon.png in the root directory --&gt;
        &lt;link rel=&quot;stylesheet&quot; href=&quot;styles/styles.css&quot;&gt;
        &lt;script src=&quot;scripts/modernizr-2.6.2.min.js&quot;&gt;&lt;/script&gt;
        &lt;!--[if lt IE 7]&gt;
            &lt;p class=&quot;chromeframe&quot;&gt;You are using an outdated browser. &lt;a href=&quot;http://browsehappy.com/&quot;&gt;Upgrade your browser today&lt;/a&gt; or &lt;a href=&quot;http://www.google.com/chromeframe/?redirect=true&quot;&gt;install Google Chrome Frame&lt;/a&gt; to better experience this site.&lt;/p&gt;
        &lt;![endif]--&gt;
        &lt;!-- Add your site or application content here --&gt;
        &lt;div id=&quot;container&quot;&gt;
            &lt;section id=&quot;taskforms&quot; class=&quot;clearfix&quot;&gt;
                &lt;div id=&quot;newtaskform&quot; class=&quot;floatleft fifty&quot;&gt;
                    &lt;h2&gt;Create a New Task&lt;/h2&gt;
                    &lt;form id=&quot;addtask&quot; data-bind=&quot;submit: addTask&quot;&gt;
                        &lt;input data-bind=&quot;value: newTaskDesc&quot;&gt;
                        &lt;input type=&quot;submit&quot;&gt;
                    &lt;/form&gt;
                &lt;/div&gt;
                &lt;div id=&quot;tasksearchform&quot; class=&quot;floatright fifty&quot;&gt;
                    &lt;h2&gt;Search Tasks&lt;/h2&gt;
                    &lt;form id=&quot;searchtask&quot;&gt;
                        &lt;input data-bind=&quot;value: query, valueUpdate: 'keyup', event : { keyup : search}&quot;&gt;
                    &lt;/form&gt;
                &lt;/div&gt;
            &lt;/section&gt;
            &lt;section id=&quot;tasktable&quot;&gt;
                &lt;h2&gt;Incomplete Tasks remaining: &lt;span data-bind=&quot;text: incompleteTasks().length&quot;&gt;&lt;/span&gt;&lt;/h2&gt;
                &lt;a data-bind=&quot;click: removeAllComplete, visible: completeTasks().length &gt; 0 &quot;&gt;Delete All Complete Tasks&lt;/a&gt;
                &lt;table&gt;
                    &lt;tbody&gt;&lt;tr&gt;
                        &lt;th data-bind=&quot;click: function(){ sort('id') }&quot;&gt;DB ID&lt;/th&gt;
                        &lt;th data-bind=&quot;click: function(){ sort('description') }&quot;&gt;Description&lt;/th&gt;
                        &lt;th data-bind=&quot;click: function(){ sort('created_at') }&quot;&gt;Date Added&lt;/th&gt;
                        &lt;th data-bind=&quot;click: function(){ sort('updated_at') }&quot;&gt;Date Modified&lt;/th&gt;
                        &lt;th data-bind=&quot;click: function(){ sort('complete') }&quot;&gt;Complete?&lt;/th&gt;
                        &lt;th&gt;Delete&lt;/th&gt;
                    &lt;/tr&gt;
                    &lt;!-- ko foreach: tasks --&gt;
                    &lt;tr data-bind=&quot;css: { 'complete': complete }, visible: isvisible&quot;&gt;
                        &lt;td data-bind=&quot;text: id&quot;&gt;&lt;/td&gt;
                        &lt;td data-bind=&quot;text: description&quot;&gt;&lt;/td&gt;
                        &lt;td data-bind=&quot;text: $root.dateFormat(created_at())&quot;&gt;&lt;/td&gt;
                        &lt;td data-bind=&quot;text: $root.dateFormat(updated_at())&quot;&gt;&lt;/td&gt;
                        &lt;td&gt;&lt;input type=&quot;checkbox&quot; data-bind=&quot;checked: complete, click: $parent.markAsComplete&quot;&gt; &lt;/td&gt;
                        &lt;td data-bind=&quot;click: $parent.destroyTask&quot; class=&quot;destroytask&quot;&gt;&lt;a&gt;X&lt;/a&gt;&lt;/td&gt;
                    &lt;/tr&gt;
                    &lt;!-- /ko --&gt;
                &lt;/tbody&gt;&lt;/table&gt;
            &lt;/section&gt;
        &lt;/div&gt;
        &lt;script src=&quot;http://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js&quot;&gt;&lt;/script&gt;
        &lt;script&gt;window.jQuery || document.write('&lt;script src=&quot;scripts/jquery.js&quot;&gt;&lt;\/script&gt;')&lt;/script&gt;
        &lt;script src=&quot;scripts/knockout.js&quot;&gt;&lt;/script&gt;
        &lt;script src=&quot;scripts/app.js&quot;&gt;&lt;/script&gt;
        &lt;!-- Google Analytics: change UA-XXXXX-X to be your site's ID. --&gt;
        &lt;script&gt;
            var _gaq=[['_setAccount','UA-XXXXX-X'],['_trackPageview']];
            (function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
            g.src=('https:'==location.protocol?'//ssl':'//www')+'.google-analytics.com/ga.js';
            s.parentNode.insertBefore(g,s)}(document,'script'));
        &lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;</pre><h4>app.js</h4><pre class="brush: jscript; title: ; notranslate">function Task(data) {
    this.description = ko.observable(data.description);
    this.complete = ko.observable(data.complete);
    this.created_at = ko.observable(data.created_at);
    this.updated_at = ko.observable(data.updated_at);
    this.id = ko.observable(data.id);
    this.isvisible = ko.observable(true);
}
function TaskViewModel() {
    var t = this;
    t.tasks = ko.observableArray([]);
    t.newTaskDesc = ko.observable();
    t.sortedBy = [];
    t.query = ko.observable('');
    t.MONTHS = [&quot;Jan&quot;, &quot;Feb&quot;, &quot;Mar&quot;, &quot;Apr&quot;, &quot;May&quot;, &quot;Jun&quot;, &quot;Jul&quot;, &quot;Aug&quot;, &quot;Sep&quot;, &quot;Oct&quot;, &quot;Nov&quot;, &quot;Dec&quot;];
    $.getJSON(&quot;http://localhost:9393/tasks&quot;, function(raw) {
        var tasks = $.map(raw, function(item) { return new Task(item) });
        t.tasks(tasks);
    });
    t.incompleteTasks = ko.computed(function() {
        return ko.utils.arrayFilter(t.tasks(), function(task) { return (!task.complete() &amp;&amp; task._method != &quot;delete&quot;) });
    });
    t.completeTasks = ko.computed(function() {
        return ko.utils.arrayFilter(t.tasks(), function(task) { return (task.complete() &amp;&amp; task._method != &quot;delete&quot;) });
    });
    // Operations
    t.dateFormat = function(date){
        if (!date) { return &quot;refresh to see server date&quot;; }
        var d = new Date(date);
        return d.getHours() + &quot;:&quot; + d.getMinutes() + &quot;, &quot; + d.getDate() + &quot; &quot; + t.MONTHS[d.getMonth()] + &quot;, &quot; + d.getFullYear();
    }
    t.addTask = function() {
        var newtask = new Task({ description: this.newTaskDesc() });
        $.getJSON(&quot;/getdate&quot;, function(data){
            newtask.created_at(data.date);
            newtask.updated_at(data.date);
            t.tasks.push(newtask);
            t.saveTask(newtask);
            t.newTaskDesc(&quot;&quot;);
        })
    };
    t.search = function(task){
        ko.utils.arrayForEach(t.tasks(), function(task){
            if (task.description() &amp;&amp; t.query() != &quot;&quot;){
                task.isvisible(task.description().toLowerCase().indexOf(t.query().toLowerCase()) &gt;= 0);
            } else if (t.query() == &quot;&quot;) {
                task.isvisible(true);
            } else {
                task.isvisible(false);
            }
        })
        return true;
    }
    t.sort = function(field){
        if (t.sortedBy.length &amp;&amp; t.sortedBy[0] == field &amp;&amp; t.sortedBy[1]==1){
                t.sortedBy[1]=0;
                t.tasks.sort(function(first,next){
                    if (!next[field].call()){ return 1; }
                    return (next[field].call() &lt; first[field].call()) ? 1 : (next[field].call() == first[field].call()) ? 0 : -1;
                });
        } else {
            t.sortedBy[0] = field;
            t.sortedBy[1] = 1;
            t.tasks.sort(function(first,next){
                if (!first[field].call()){ return 1; }
                return (first[field].call() &lt; next[field].call()) ? 1 : (first[field].call() == next[field].call()) ? 0 : -1;
            });
        }
    }
    t.markAsComplete = function(task) {
        if (task.complete() == true){
            task.complete(true);
        } else {
            task.complete(false);
        }
        task._method = &quot;put&quot;;
        t.saveTask(task);
        return true;
    }
    t.destroyTask = function(task) {
        task._method = &quot;delete&quot;;
        t.tasks.destroy(task);
        t.saveTask(task);
    };
    t.removeAllComplete = function() {
        ko.utils.arrayForEach(t.tasks(), function(task){
            if (task.complete()){
                t.destroyTask(task);
            }
        });
    }
    t.saveTask = function(task) {
        var t = ko.toJS(task);
        $.ajax({
             url: &quot;http://localhost:9393/tasks&quot;,
             type: &quot;POST&quot;,
             data: t
        }).done(function(data){
            task.id(data.task.id);
        });
    }
}
ko.applyBindings(new TaskViewModel());</pre><p><em>Note the rearrangement of property declarations on the <code>TaskViewModel</code>.</em></p><hr/><h2>Conclusion</h2><blockquote
class="pullquote"><p>You now have the techniques to create more complex applications!</p></blockquote><p>These two tutorials have taken you through the process of creating a single-page application with Knockout.js and Sinatra. The application can write and retrieve data, via a simple JSON interface, and it has features beyond simple CRUD actions, like mass deletion, sorting, and searching. With these tools and examples, you now have the techniques to create much more complex applications!</p>
<p><a href="http://feedads.g.doubleclick.net/~a/CGyCfixkrEto1OFR8ztho_VNXqQ/0/da"><img src="http://feedads.g.doubleclick.net/~a/CGyCfixkrEto1OFR8ztho_VNXqQ/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/CGyCfixkrEto1OFR8ztho_VNXqQ/1/da"><img src="http://feedads.g.doubleclick.net/~a/CGyCfixkrEto1OFR8ztho_VNXqQ/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=9gJ5KPZax8Q:kn3lELDwm2E:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=9gJ5KPZax8Q:kn3lELDwm2E:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=9gJ5KPZax8Q:kn3lELDwm2E:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=9gJ5KPZax8Q:kn3lELDwm2E:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=9gJ5KPZax8Q:kn3lELDwm2E:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=9gJ5KPZax8Q:kn3lELDwm2E:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=9gJ5KPZax8Q:kn3lELDwm2E:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=9gJ5KPZax8Q:kn3lELDwm2E:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/9gJ5KPZax8Q" height="1" width="1"/>";s:3:"wfw";a:1:{s:10:"commentrss";s:105:"http://net.tutsplus.com/tutorials/javascript-ajax/building-single-page-web-apps-with-sinatra-part-2/feed/";}s:5:"slash";a:1:{s:8:"comments";s:1:"5";}s:10:"feedburner";a:1:{s:8:"origlink";s:100:"http://net.tutsplus.com/tutorials/javascript-ajax/building-single-page-web-apps-with-sinatra-part-2/";}s:7:"summary";s:28571:"<a
href='http://rss.buysellads.com/click.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28129&c=1533308860' target='_blank'><img
src='http://rss.buysellads.com/img.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28129&c=1533308860' border='0' alt='' /></a><p>In the <a
href="http://net.tutsplus.com/tutorials/javascript-ajax/building-single-page-web-apps-with-sinatra-part-1/">first part</a> of this mini-series, we created the basic structure of a to-do application using a Sinatra JSON interface to a SQLite database, and a Knockout-powered front-end that allows us to add tasks to our database. In this final part, we&#8217;ll cover some slightly more advanced functionality in Knockout, including sorting, searching, updating, and deleting.</p><p><span
id="more-28129"></span></p><p>Let&#8217;s start where we left off; here is the relevant portion of our <code>index.erb</code> file.</p><pre class="brush: xml; title: ; notranslate">&lt;div id=&quot;container&quot;&gt;
            &lt;section id=&quot;taskforms&quot; class=&quot;clearfix&quot;&gt;
                &lt;div id=&quot;newtaskform&quot; class=&quot;floatleft fifty&quot;&gt;
                    &lt;h2&gt;Create a New Task&lt;/h2&gt;
                    &lt;form id=&quot;addtask&quot; data-bind=&quot;submit: addTask&quot;&gt;
                        &lt;input data-bind=&quot;value: newTaskDesc&quot;&gt;
                        &lt;input type=&quot;submit&quot;&gt;
                    &lt;/form&gt;
                &lt;/div&gt;
                &lt;div id=&quot;tasksearchform&quot; class=&quot;floatright fifty&quot;&gt;
                    &lt;h2&gt;Search Tasks&lt;/h2&gt;
                    &lt;form id=&quot;searchtask&quot;&gt;
                        &lt;input&gt;
                    &lt;/form&gt;
                &lt;/div&gt;
            &lt;/section&gt;
            &lt;section id=&quot;tasktable&quot;&gt;
                &lt;h2&gt;Incomplete Tasks remaining: &lt;span&gt;&lt;/span&gt;&lt;/h2&gt;
                &lt;a&gt;Delete All Complete Tasks&lt;/a&gt;
                &lt;table&gt;
                    &lt;tbody&gt;&lt;tr&gt;
                        &lt;th&gt;DB ID&lt;/th&gt;
                        &lt;th&gt;Description&lt;/th&gt;
                        &lt;th&gt;Date Added&lt;/th&gt;
                        &lt;th&gt;Date Modified&lt;/th&gt;
                        &lt;th&gt;Complete?&lt;/th&gt;
                        &lt;th&gt;Delete&lt;/th&gt;
                    &lt;/tr&gt;
                    &lt;!-- ko foreach: tasks --&gt;
                    &lt;tr&gt;
                        &lt;td data-bind=&quot;text: id&quot;&gt;&lt;/td&gt;
                        &lt;td data-bind=&quot;text: description&quot;&gt;&lt;/td&gt;
                        &lt;td data-bind=&quot;text: created_at&quot;&gt;&lt;/td&gt;
                        &lt;td data-bind=&quot;text: updated_at&quot;&gt;&lt;/td&gt;
                        &lt;td&gt;&lt;input type=&quot;checkbox&quot; data-bind=&quot;checked: complete, click: $parent.markAsComplete&quot;&gt; &lt;/td&gt;
                        &lt;td data-bind=&quot;click: $parent.destroyTask&quot; class=&quot;destroytask&quot;&gt;&lt;a&gt;X&lt;/a&gt;&lt;/td&gt;
                    &lt;/tr&gt;
                    &lt;!-- /ko --&gt;
                &lt;/tbody&gt;&lt;/table&gt;
            &lt;/section&gt;
        &lt;/div&gt;</pre><hr/><h2>Sort</h2><p>Sorting is a common task used in many applications. In our case, we want to sort the task list by any header field in our task-list table. We will start by adding the following code to the <code>TaskViewModel</code>:</p><pre class="brush: jscript; title: ; notranslate">t.sortedBy = [];
t.sort = function(field){
    if (t.sortedBy.length &amp;&amp; t.sortedBy[0] == field &amp;&amp; t.sortedBy[1]==1){
            t.sortedBy[1]=0;
            t.tasks.sort(function(first,next){
                if (!next[field].call()){ return 1; }
                return (next[field].call() &lt; first[field].call()) ? 1 : (next[field].call() == first[field].call()) ? 0 : -1;
            });
    } else {
        t.sortedBy[0] = field;
        t.sortedBy[1] = 1;
        t.tasks.sort(function(first,next){
            if (!first[field].call()){ return 1; }
            return (first[field].call() &lt; next[field].call()) ? 1 : (first[field].call() == next[field].call()) ? 0 : -1;
        });
    }
}</pre><blockquote
class="pullquote"><p>Knockout provides a sort function for observable arrays</p></blockquote><p>First, we define a <code>sortedBy</code> array as a property of our view model. This allows us to store if and how the collection is sorted.</p><p>Next is the <code>sort()</code> function. It accepts a <code>field</code> argument (the field we want to sort by) and checks if the tasks are sorted by the current sorting scheme. We want to sort using a &#8220;toggle&#8221; type of process. For example, sort by description once, and the tasks arrange in alphabetical order. Sort by description again, and the tasks arrange in reverse-alphabetical order. This <code>sort()</code> function supports this behavior by checking the most recent sort scheme and comparing it to what the user wants to sort by.</p><p>Knockout provides a sort function for observable arrays. It accepts a function as an argument that controls how the array should be sorted. This function compares two elements from the array and returns <code>1</code>, <code>0</code>, or <code>-1</code> as a result of that comparison. All like values are grouped together (which will be useful for grouping complete and incomplete tasks together).</p><p>Note: the properties of the array elements must be called rather than simply accessed; these properties are actually functions that return the value of the property if called without any arguments.</p><p>Next, we define the bindings on the table headers in our view.</p><pre class="brush: xml; title: ; notranslate">&lt;th data-bind=&quot;click: function(){ sort('id') }&quot;&gt;DB ID&lt;/th&gt;
&lt;th data-bind=&quot;click: function(){ sort('description') }&quot;&gt;Description&lt;/th&gt;
&lt;th data-bind=&quot;click: function(){ sort('created_at') }&quot;&gt;Date Added&lt;/th&gt;
&lt;th data-bind=&quot;click: function(){ sort('updated_at') }&quot;&gt;Date Modified&lt;/th&gt;
&lt;th data-bind=&quot;click: function(){ sort('complete') }&quot;&gt;Complete?&lt;/th&gt;
&lt;th&gt;Delete&lt;/th&gt;</pre><p>These bindings allow each of the headers to trigger a sort based on the passed string value; each of these directly maps to the <code>Task</code> model.</p><hr/><h2>Mark As Complete</h2><p>Next, we want to be able to mark a task as complete, and we&#8217;ll accomplish this by simply clicking the checkbox associated with a particular task. Let&#8217;s start by defining a method in the <code>TaskViewModel</code>:</p><pre class="brush: jscript; title: ; notranslate">t.markAsComplete = function(task) {
    if (task.complete() == true){
        task.complete(true);
    } else {
        task.complete(false);
    }
    task._method = &quot;put&quot;;
    t.saveTask(task);
    return true;
}</pre><p>The <code>markAsComplete()</code> method accepts the task as an argument, which is automatically passed by Knockout when iterating over a collection of items. We then toggle the <code>complete</code> property, and add a <code>._method="put"</code> property to the task. This allows <code>DataMapper</code> to use the HTTP <code>PUT</code> verb as opposed to <code>POST</code>. We then use our convenient <code>t.saveTask()</code> method to save the changes to the database. Finally, we return <code>true</code> because returning <code>false</code> prevents the checkbox from changing state.</p><p>Next, we change the view by replacing the checkbox code inside the task loop with the following:</p><pre class="brush: xml; title: ; notranslate">&lt;input type=&quot;checkbox&quot; data-bind=&quot;checked: complete, click: $parent.markAsComplete&quot;&gt;</pre><p>This tells us two things:</p><ol><li>The box is checked if <code>complete</code> is true.</li><li>On click, run the <code>markAsComplete()</code> function from the parent (<code>TaskViewModel</code> in this case). This automatically passes the current task in the loop.</p></ol><hr/><h2>Deleting Tasks</h2><p>To delete a task, we simply use a few convenience methods and call <code>saveTask()</code>. In our <code>TaskViewModel</code>, add the following:</p><pre class="brush: jscript; title: ; notranslate">t.destroyTask = function(task) {
    task._method = &quot;delete&quot;;
    t.tasks.destroy(task);
    t.saveTask(task);
};</pre><p>This function adds a property similar to the &#8220;put&#8221; method for completing a task. The built-in <code>destroy()</code> method removes the passed-in task from the observable array. Finally, calling <code>saveTask()</code> destroys the task; that is, as long as the <code>._method</code> is set to &#8220;delete&#8221;.</p><p>Now we need to modify our view; add the following:</p><pre class="brush: xml; title: ; notranslate">&lt;td data-bind=&quot;click: $parent.destroyTask&quot; class=&quot;destroytask&quot;&gt;&lt;a&gt;X&lt;/a&gt;&lt;/td&gt;</pre><p>This is very similar in functionality to the complete checkbox. Note that the <code>class="destroytask"</code> is purely for styling purposes.</p><hr/><h2>Delete All Completed</h2><p>Next, we want to add the &#8220;delete all complete tasks&#8221; functionality. First, add the following code to the <code>TaskViewModel</code>:</p><pre class="brush: jscript; title: ; notranslate">t.removeAllComplete = function() {
    ko.utils.arrayForEach(t.tasks(), function(task){
        if (task.complete()){
            t.destroyTask(task);
        }
    });
}</pre><p>This function simply iterates over the tasks to determine which of them are complete, and we call the <code>destroyTask()</code> method for each complete task. In our view, add the following for the &#8220;delete all complete&#8221; link.</p><pre class="brush: xml; title: ; notranslate">&lt;a data-bind=&quot;click: removeAllComplete, visible: completeTasks().length &gt; 0 &quot;&gt;Delete All Complete Tasks&lt;/a&gt;</pre><p>Our click binding will work correctly, but we need to define <code>completeTasks()</code>. Add the following to our <code>TaskViewModel</code>:</p><pre class="brush: jscript; title: ; notranslate">t.completeTasks = ko.computed(function() {
    return ko.utils.arrayFilter(t.tasks(), function(task) { return (task.complete() &amp;&amp; task._method != &quot;delete&quot;) });
});</pre><p>This method is a <em>computed</em> property. These properties return a value that is computed &#8220;on the fly&#8221; when the model is updated. In this case, we return a filtered array that contains only complete tasks that are not marked for deletion. Then, we simply use this array&#8217;s <code>length</code> property to hide or show the &#8220;Delete All Completed Tasks&#8221; link.</p><hr/><h2>Incomplete Tasks Remaining</h2><p>Our interface should also display the amount of incomplete tasks. Similar to our <code>completeTasks()</code> function above, we define an <code>incompleteTasks()</code> function in <code>TaskViewModel</code>:</p><pre class="brush: jscript; title: ; notranslate">t.incompleteTasks = ko.computed(function() {
    return ko.utils.arrayFilter(t.tasks(), function(task) { return (!task.complete() &amp;&amp; task._method != &quot;delete&quot;) });
});</pre><p>We then access this computed filtered array in our view, like this:</p><pre class="brush: xml; title: ; notranslate">&lt;h2&gt;Incomplete Tasks remaining: &lt;span data-bind=&quot;text: incompleteTasks().length&quot;&gt;&lt;/span&gt;&lt;/h2&gt;</pre><hr/><h2>Style Completed Tasks</h2><p>We want to style the completed items differently from the tasks in the list, and we can do this in our view with Knockout&#8217;s <code>css</code> binding. Modify the <code>tr</code> opening tag in our task <code>arrayForEach()</code> loop to the following.</p><pre class="brush: xml; title: ; notranslate">&lt;tr data-bind=&quot;css: { 'complete': complete }, visible: isvisible&quot;&gt;</pre><p>This adds a <code>complete</code> CSS class to the table row for each task if its <code>complete</code> property is <code>true</code>.</p><hr/><h2>Clean Up Dates</h2><p>Let&#8217;s get rid of those ugly Ruby date strings. We&#8217;ll start by defining a <code>dateFormat</code> function in our <code>TaskViewModel</code>:</p><pre class="brush: jscript; title: ; notranslate">t.MONTHS = [&quot;Jan&quot;, &quot;Feb&quot;, &quot;Mar&quot;, &quot;Apr&quot;, &quot;May&quot;, &quot;Jun&quot;, &quot;Jul&quot;, &quot;Aug&quot;, &quot;Sep&quot;, &quot;Oct&quot;, &quot;Nov&quot;, &quot;Dec&quot;];
t.dateFormat = function(date){
    if (!date) { return &quot;refresh to see server date&quot;; }
    var d = new Date(date);
    return d.getHours() + &quot;:&quot; + d.getMinutes() + &quot;, &quot; + d.getDate() + &quot; &quot; + t.MONTHS[d.getMonth()] + &quot;, &quot; + d.getFullYear();
}</pre><p>This function is fairly straightforward. If for any reason the date is not defined, we simply need to refresh the browser to pull in the date in the initial <code>Task</code> fetching function. Otherwise, we create a human readable date with the plain JavaScript <code>Date</code> object with the help of the <code>MONTHS</code> array. (Note: it is not necessary to capitalize the name of the array <code>MONTHS</code>, of course; this is simply a way of knowing that this is a constant value that shouldn&#8217;t be changed.)</p><p>Next, we add the following changes to our view for the <code>created_at</code> and <code>updated_at</code> properties:</p><pre class="brush: xml; title: ; notranslate">&lt;td data-bind=&quot;text: $root.dateFormat(created_at())&quot;&gt;&lt;/td&gt;
&lt;td data-bind=&quot;text: $root.dateFormat(updated_at())&quot;&gt;&lt;/td&gt;</pre><p>This passes the <code>created_at</code> and <code>updated_at</code> properties to the <code>dateFormat()</code> function. Once again, it&#8217;s important to remember that properties of each task are not normal properties; they are functions. In order to retrieve their value, you must call the function (as shown in the above example). Note: <code>$root</code> is a keyword, defined by Knockout, that refers to the ViewModel. The <code>dateFormat()</code> method, for instance, is defined as a method of the root ViewModel (<code>TaskViewModel</code>).</p><hr/><h2>Searching Tasks</h2><p>We can search our tasks in a variety of ways, but we&#8217;ll keep things simple and perform a front-end search. Keep in mind, however, that it is likely that these search results will be database driven as the data grows for the sake of pagination. But for now, let&#8217;s define our <code>search()</code> method on <code>TaskViewModel</code>:</p><pre class="brush: jscript; title: ; notranslate">t.query = ko.observable('');
t.search = function(task){
    ko.utils.arrayForEach(t.tasks(), function(task){
        if (task.description() &amp;&amp; t.query() != &quot;&quot;){
            task.isvisible(task.description().toLowerCase().indexOf(t.query().toLowerCase()) &gt;= 0);
        } else if (t.query() == &quot;&quot;) {
            task.isvisible(true);
        } else {
            task.isvisible(false);
        }
    })
    return true;
}</pre><p>We can see that this iterates through the array of tasks and checks to see if <code>t.query()</code> (a regular observable value) is in the task description. Note that this check actually runs inside the <em>setter</em> function for the <code>task.isvisible</code> property. If the evaluation is <code>false</code>, the task isn&#8217;t found and the <code>isvisible</code> property is set to <code>false</code>. If the query is equal to an empty string, all tasks are set to be visible. If the task doesn&#8217;t have a description and the query is a non-empty value, the task is not a part of the returned data set and is hidden.</p><p>In our <code>index.erb</code> file, we set up our searching interface with the following code:</p><pre class="brush: xml; title: ; notranslate">&lt;form id=&quot;searchtask&quot;&gt;
    &lt;input data-bind=&quot;value: query, valueUpdate: 'keyup', event : { keyup : search}&quot;&gt;
&lt;/form&gt;</pre><p>The input value is set to the <code>ko.observable query</code>. Next, we see that the <code>keyup</code> event is specifically identified as a <code>valueUpdate</code> event. Lastly, we set a manual event binding to <code>keyup</code> to execute the search (<code>t.search()</code>) function. No form submission is necessary; the list of matching items will display and can still be sortable, deletable, etc. Therefore, all interactions work at all times.</p><hr/><h2>Final Code</h2><h4>index.erb</h4><pre class="brush: xml; title: ; notranslate">&lt;!DOCTYPE html &gt;
&lt;html&gt;
&lt;!--[if lt IE 7]&gt;      &lt;html class=&quot;no-js lt-ie9 lt-ie8 lt-ie7&quot;&gt; &lt;![endif]--&gt;
&lt;!--[if IE 7]&gt;         &lt;html class=&quot;no-js lt-ie9 lt-ie8&quot;&gt; &lt;![endif]--&gt;
&lt;!--[if IE 8]&gt;         &lt;html class=&quot;no-js lt-ie9&quot;&gt; &lt;![endif]--&gt;
&lt;!--[if gt IE 8]&gt;&lt;!--&gt;  &lt;!--&lt;![endif]--&gt;
    &lt;body&gt;
        &lt;meta charset=&quot;utf-8&quot;&gt;
        &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge,chrome=1&quot;&gt;
        &lt;title&gt;ToDo&lt;/title&gt;
        &lt;meta name=&quot;description&quot; content=&quot;&quot;&gt;
        &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width&quot;&gt;
        &lt;!-- Place favicon.ico and apple-touch-icon.png in the root directory --&gt;
        &lt;link rel=&quot;stylesheet&quot; href=&quot;styles/styles.css&quot;&gt;
        &lt;script src=&quot;scripts/modernizr-2.6.2.min.js&quot;&gt;&lt;/script&gt;
        &lt;!--[if lt IE 7]&gt;
            &lt;p class=&quot;chromeframe&quot;&gt;You are using an outdated browser. &lt;a href=&quot;http://browsehappy.com/&quot;&gt;Upgrade your browser today&lt;/a&gt; or &lt;a href=&quot;http://www.google.com/chromeframe/?redirect=true&quot;&gt;install Google Chrome Frame&lt;/a&gt; to better experience this site.&lt;/p&gt;
        &lt;![endif]--&gt;
        &lt;!-- Add your site or application content here --&gt;
        &lt;div id=&quot;container&quot;&gt;
            &lt;section id=&quot;taskforms&quot; class=&quot;clearfix&quot;&gt;
                &lt;div id=&quot;newtaskform&quot; class=&quot;floatleft fifty&quot;&gt;
                    &lt;h2&gt;Create a New Task&lt;/h2&gt;
                    &lt;form id=&quot;addtask&quot; data-bind=&quot;submit: addTask&quot;&gt;
                        &lt;input data-bind=&quot;value: newTaskDesc&quot;&gt;
                        &lt;input type=&quot;submit&quot;&gt;
                    &lt;/form&gt;
                &lt;/div&gt;
                &lt;div id=&quot;tasksearchform&quot; class=&quot;floatright fifty&quot;&gt;
                    &lt;h2&gt;Search Tasks&lt;/h2&gt;
                    &lt;form id=&quot;searchtask&quot;&gt;
                        &lt;input data-bind=&quot;value: query, valueUpdate: 'keyup', event : { keyup : search}&quot;&gt;
                    &lt;/form&gt;
                &lt;/div&gt;
            &lt;/section&gt;
            &lt;section id=&quot;tasktable&quot;&gt;
                &lt;h2&gt;Incomplete Tasks remaining: &lt;span data-bind=&quot;text: incompleteTasks().length&quot;&gt;&lt;/span&gt;&lt;/h2&gt;
                &lt;a data-bind=&quot;click: removeAllComplete, visible: completeTasks().length &gt; 0 &quot;&gt;Delete All Complete Tasks&lt;/a&gt;
                &lt;table&gt;
                    &lt;tbody&gt;&lt;tr&gt;
                        &lt;th data-bind=&quot;click: function(){ sort('id') }&quot;&gt;DB ID&lt;/th&gt;
                        &lt;th data-bind=&quot;click: function(){ sort('description') }&quot;&gt;Description&lt;/th&gt;
                        &lt;th data-bind=&quot;click: function(){ sort('created_at') }&quot;&gt;Date Added&lt;/th&gt;
                        &lt;th data-bind=&quot;click: function(){ sort('updated_at') }&quot;&gt;Date Modified&lt;/th&gt;
                        &lt;th data-bind=&quot;click: function(){ sort('complete') }&quot;&gt;Complete?&lt;/th&gt;
                        &lt;th&gt;Delete&lt;/th&gt;
                    &lt;/tr&gt;
                    &lt;!-- ko foreach: tasks --&gt;
                    &lt;tr data-bind=&quot;css: { 'complete': complete }, visible: isvisible&quot;&gt;
                        &lt;td data-bind=&quot;text: id&quot;&gt;&lt;/td&gt;
                        &lt;td data-bind=&quot;text: description&quot;&gt;&lt;/td&gt;
                        &lt;td data-bind=&quot;text: $root.dateFormat(created_at())&quot;&gt;&lt;/td&gt;
                        &lt;td data-bind=&quot;text: $root.dateFormat(updated_at())&quot;&gt;&lt;/td&gt;
                        &lt;td&gt;&lt;input type=&quot;checkbox&quot; data-bind=&quot;checked: complete, click: $parent.markAsComplete&quot;&gt; &lt;/td&gt;
                        &lt;td data-bind=&quot;click: $parent.destroyTask&quot; class=&quot;destroytask&quot;&gt;&lt;a&gt;X&lt;/a&gt;&lt;/td&gt;
                    &lt;/tr&gt;
                    &lt;!-- /ko --&gt;
                &lt;/tbody&gt;&lt;/table&gt;
            &lt;/section&gt;
        &lt;/div&gt;
        &lt;script src=&quot;http://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js&quot;&gt;&lt;/script&gt;
        &lt;script&gt;window.jQuery || document.write('&lt;script src=&quot;scripts/jquery.js&quot;&gt;&lt;\/script&gt;')&lt;/script&gt;
        &lt;script src=&quot;scripts/knockout.js&quot;&gt;&lt;/script&gt;
        &lt;script src=&quot;scripts/app.js&quot;&gt;&lt;/script&gt;
        &lt;!-- Google Analytics: change UA-XXXXX-X to be your site's ID. --&gt;
        &lt;script&gt;
            var _gaq=[['_setAccount','UA-XXXXX-X'],['_trackPageview']];
            (function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
            g.src=('https:'==location.protocol?'//ssl':'//www')+'.google-analytics.com/ga.js';
            s.parentNode.insertBefore(g,s)}(document,'script'));
        &lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;</pre><h4>app.js</h4><pre class="brush: jscript; title: ; notranslate">function Task(data) {
    this.description = ko.observable(data.description);
    this.complete = ko.observable(data.complete);
    this.created_at = ko.observable(data.created_at);
    this.updated_at = ko.observable(data.updated_at);
    this.id = ko.observable(data.id);
    this.isvisible = ko.observable(true);
}
function TaskViewModel() {
    var t = this;
    t.tasks = ko.observableArray([]);
    t.newTaskDesc = ko.observable();
    t.sortedBy = [];
    t.query = ko.observable('');
    t.MONTHS = [&quot;Jan&quot;, &quot;Feb&quot;, &quot;Mar&quot;, &quot;Apr&quot;, &quot;May&quot;, &quot;Jun&quot;, &quot;Jul&quot;, &quot;Aug&quot;, &quot;Sep&quot;, &quot;Oct&quot;, &quot;Nov&quot;, &quot;Dec&quot;];
    $.getJSON(&quot;http://localhost:9393/tasks&quot;, function(raw) {
        var tasks = $.map(raw, function(item) { return new Task(item) });
        t.tasks(tasks);
    });
    t.incompleteTasks = ko.computed(function() {
        return ko.utils.arrayFilter(t.tasks(), function(task) { return (!task.complete() &amp;&amp; task._method != &quot;delete&quot;) });
    });
    t.completeTasks = ko.computed(function() {
        return ko.utils.arrayFilter(t.tasks(), function(task) { return (task.complete() &amp;&amp; task._method != &quot;delete&quot;) });
    });
    // Operations
    t.dateFormat = function(date){
        if (!date) { return &quot;refresh to see server date&quot;; }
        var d = new Date(date);
        return d.getHours() + &quot;:&quot; + d.getMinutes() + &quot;, &quot; + d.getDate() + &quot; &quot; + t.MONTHS[d.getMonth()] + &quot;, &quot; + d.getFullYear();
    }
    t.addTask = function() {
        var newtask = new Task({ description: this.newTaskDesc() });
        $.getJSON(&quot;/getdate&quot;, function(data){
            newtask.created_at(data.date);
            newtask.updated_at(data.date);
            t.tasks.push(newtask);
            t.saveTask(newtask);
            t.newTaskDesc(&quot;&quot;);
        })
    };
    t.search = function(task){
        ko.utils.arrayForEach(t.tasks(), function(task){
            if (task.description() &amp;&amp; t.query() != &quot;&quot;){
                task.isvisible(task.description().toLowerCase().indexOf(t.query().toLowerCase()) &gt;= 0);
            } else if (t.query() == &quot;&quot;) {
                task.isvisible(true);
            } else {
                task.isvisible(false);
            }
        })
        return true;
    }
    t.sort = function(field){
        if (t.sortedBy.length &amp;&amp; t.sortedBy[0] == field &amp;&amp; t.sortedBy[1]==1){
                t.sortedBy[1]=0;
                t.tasks.sort(function(first,next){
                    if (!next[field].call()){ return 1; }
                    return (next[field].call() &lt; first[field].call()) ? 1 : (next[field].call() == first[field].call()) ? 0 : -1;
                });
        } else {
            t.sortedBy[0] = field;
            t.sortedBy[1] = 1;
            t.tasks.sort(function(first,next){
                if (!first[field].call()){ return 1; }
                return (first[field].call() &lt; next[field].call()) ? 1 : (first[field].call() == next[field].call()) ? 0 : -1;
            });
        }
    }
    t.markAsComplete = function(task) {
        if (task.complete() == true){
            task.complete(true);
        } else {
            task.complete(false);
        }
        task._method = &quot;put&quot;;
        t.saveTask(task);
        return true;
    }
    t.destroyTask = function(task) {
        task._method = &quot;delete&quot;;
        t.tasks.destroy(task);
        t.saveTask(task);
    };
    t.removeAllComplete = function() {
        ko.utils.arrayForEach(t.tasks(), function(task){
            if (task.complete()){
                t.destroyTask(task);
            }
        });
    }
    t.saveTask = function(task) {
        var t = ko.toJS(task);
        $.ajax({
             url: &quot;http://localhost:9393/tasks&quot;,
             type: &quot;POST&quot;,
             data: t
        }).done(function(data){
            task.id(data.task.id);
        });
    }
}
ko.applyBindings(new TaskViewModel());</pre><p><em>Note the rearrangement of property declarations on the <code>TaskViewModel</code>.</em></p><hr/><h2>Conclusion</h2><blockquote
class="pullquote"><p>You now have the techniques to create more complex applications!</p></blockquote><p>These two tutorials have taken you through the process of creating a single-page application with Knockout.js and Sinatra. The application can write and retrieve data, via a simple JSON interface, and it has features beyond simple CRUD actions, like mass deletion, sorting, and searching. With these tools and examples, you now have the techniques to create much more complex applications!</p>
<p><a href="http://feedads.g.doubleclick.net/~a/CGyCfixkrEto1OFR8ztho_VNXqQ/0/da"><img src="http://feedads.g.doubleclick.net/~a/CGyCfixkrEto1OFR8ztho_VNXqQ/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/CGyCfixkrEto1OFR8ztho_VNXqQ/1/da"><img src="http://feedads.g.doubleclick.net/~a/CGyCfixkrEto1OFR8ztho_VNXqQ/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=9gJ5KPZax8Q:kn3lELDwm2E:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=9gJ5KPZax8Q:kn3lELDwm2E:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=9gJ5KPZax8Q:kn3lELDwm2E:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=9gJ5KPZax8Q:kn3lELDwm2E:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=9gJ5KPZax8Q:kn3lELDwm2E:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=9gJ5KPZax8Q:kn3lELDwm2E:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=9gJ5KPZax8Q:kn3lELDwm2E:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=9gJ5KPZax8Q:kn3lELDwm2E:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/9gJ5KPZax8Q" height="1" width="1"/>";s:14:"date_timestamp";i:1353361212;}i:6;a:13:{s:5:"title";s:37:"A First Look at the HTML5 History API";s:4:"link";s:54:"http://feedproxy.google.com/~r/nettuts/~3/5tyzQkCiSrA/";s:8:"comments";s:95:"http://net.tutsplus.com/tutorials/html-css-techniques/a-first-look-at-the-history-api/#comments";s:7:"pubdate";s:31:"Fri, 16 Nov 2012 20:14:59 +0000";s:2:"dc";a:1:{s:7:"creator";s:10:"Umar Hansa";}s:8:"category";s:22:"HTML & CSShistoryhtml5";s:4:"guid";s:32:"http://net.tutsplus.com/?p=28053";s:11:"description";s:20104:"<a
href='http://rss.buysellads.com/click.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28053&c=419707638' target='_blank'><img
src='http://rss.buysellads.com/img.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28053&c=419707638' border='0' alt='' /></a><p>HTML5 introduces a variety of new goodies for front-end developers, such as the additions to the browser&#8217;s <code>history</code> object. Let&#8217;s take a look at its new features in this lesson.</p><p><span
id="more-28053"></span></p><hr
/><h2>Introduction</h2><blockquote
class="pullquote"><p>Always present the same information when the user refreshes the page.</p></blockquote><p>The <code>history</code> object isn&#8217;t new; in fact, you can trace its beginnings to the early browsers from the 1990s. While it has never been based on a public standard, until HTML5 that is, every browser has supported its meager, yet sometimes useful, functionality. Since its inception, the <code>history</code> object has provided a means to work with the history of a particular tab in the browser (or a window before tabbed browsing became the norm). This is sometimes referred to as <strong>session history</strong>.</p><p>The old <code>history</code> object gave us the ability to programmatically navigate backwards and forwards, the equivalent of the user clicking the <em>Back</em> and <em>Forward</em> buttons. But HTML5 finally updates the history API by adding the ability to manipulate the browser&#8217;s URL and maintain state; although URL manipulation, to some extent, has been possible since the introduction of the <code>location</code> object. For example:</p><pre class="brush: jscript; title: ; notranslate">
//On the URL: http://net.tutsplus.com/
//Get the full URL
location.href //&quot;http://net.tutsplus.com/&quot;
//Get the hash fragment
location.hash // &quot;&quot; (an empty string)
//Set the hash fragment
location.hash = &quot;hello&quot;
//Get the full URL
location.href //&quot;http://net.tutsplus.com/#hello&quot;
//Get the hash fragment
location.hash //&quot;#hello&quot;
</pre><blockquote
class="pullquote"><p>The native API is easy enough to use&#8230;</p></blockquote><p>It&#8217;s common for some web applications to use &#8220;hash-bangs&#8221; (<code>#!</code>). Not only can they prevent the browser from navigating to a different page (making dynamic web pages easier to manage), but they can also aid in search engine optimization (SEO) (<a
href="http://www.webmonkey.com/2012/05/twitter-declares-everything-old-new-again/">until recently</a>, Twitter made extensive use of hash-bangs).</p><p>The hash-bang technique is useful when you have a lot of content that you want to display in the same page while allowing users to bookmark certain parts of a page. You can also use hash-bangs in conjunction with infinite scrolling scripts keep track of the user&#8217;s position by storing that information in the URL.</p><p>The technique is simple: store information in the URL, parse it, and then use Ajax to load content. It sounds wonderful, but there are <a
href="http://www.tbray.org/ongoing/When/201x/2011/02/09/Hash-Blecch">many</a> <a
href="http://blog.benward.me/post/3231388630">reasons</a> not <a
href="http://isolani.co.uk/blog/javascript/BreakingTheWebWithHashBangs/">to use</a> this technique. To summarize:</p><ul><li>A URL like <code>http://domain.com/#!1234</code> may fail to load correctly if JavaScript is not enabled.</li><li>You may have two different URLs pointing to the exact same content (eg: <code>http://domain.com/#!1234</code> and <code>http://domain.com/1234</code>)&#8211;a no-no for SEO.</li><li>The server is unaware of <a
href="http://en.wikipedia.org/wiki/Fragment_identifier">fragment identifiers</a>.</li></ul><hr
/><h2>Using the History API</h2><p>The History API helps solve the aforementioned issues by giving us the ability to transform URLs, like <code>http://domain.com</code> to <code>http://domain.com/hello</code>, without triggering a page refresh. The following lists the <code>history</code> object&#8217;s members and their purposes:</p><ul><li><strong><code>history.back()</code></strong>: Navigates to the previous URL in the history stack.</li><li><strong><code>history.forward()</code></strong>: Navigates to the next URL in the history stack.</li><li><strong><code>history.go()</code></strong>: Navigates to the URL at the specified index in the history stack. e.g. <code>history.go(-2)</code></li><li><strong><code>history.pushState()</code></strong>: Adds a URL to the history stack with a specified state. e.g. <code>history.pushState({ foo : "bar"}, "New title", "new-url.html")</code>, where the first argument is a state object.</li><li><strong><code>history.replaceState()</code></strong>: Updates (rather than adds) the current URL on the history stack with the provided state information. e.g. <code>history.replaceState({ foo : "bar"}, "New title", location.href)</code></li><li><strong><code>history.length</code></strong>: Returns the amount of URLs in the history stack.</li><li><strong><code>history.state</code></strong>: Returns the state object at the top of the history stack.</li></ul><p>The following example uses no external libraries:</p><pre class="brush: xml; title: ; notranslate">
&lt;nav&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;/history/example/index.html&quot;&gt;Home&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;/history/example/hello.html&quot;&gt;hello&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;/history/example/about/index.html&quot;&gt;About&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/nav&gt;
</pre><pre class="brush: jscript; title: ; notranslate">
// NodeLists do not have a forEach method
[].forEach.call(document.querySelectorAll(&quot;nav a&quot;),function(e) {
	e.addEventListener(&quot;click&quot;, function(evt) {
	  var title = this.textContent;
	  var url = this.href;
	  //Change the URL
	  history.pushState(null, title, url);
	  //Do some ajax stuff
	  //Prevent the browsers default behaviour of navigating to the hyperlink
	  evt.preventDefault();
	})
});
</pre><p>The native API is easy enough to use, but you can find many libraries that greatly help with the common patterns of intercepting a link, loading data via Ajax, and inserting the data into the page. Two popular libraries are <a
href="https://github.com/defunkt/jquery-pjax/">pjax</a> and <a
href="https://github.com/balupton/History.js/">History.js</a>.</p><hr
/><h2>With Great Power&#8230;</h2><p>As with any technology or API, be mindful of best practices. Let&#8217;s look at a few best practices when using the history API.</p><h3>Be Kind to URLs</h3><blockquote><p>Don&#8217;t change the URL just because you can; only change it when it makes sense to do so!</p></blockquote><p>For example, let&#8217;s say your online shop resides at <code>https://shop.domain.com/</code>, and the homepage displays a list of popular items. Clicking on one of the items could open a <a
href="http://en.wikipedia.org/wiki/Modal_window">modal window</a> that contains the product&#8217;s information (retrieved via Ajax, of course). You wouldn&#8217;t need to change the URL when doing this; instead, you could provide a link to the product in the modal window that would take the user to the product&#8217;s page.</p><p>Another example would be to maintain the user&#8217;s scrolling position in an infinite scrolling situation. The user could refresh the page and continue where they left off.</p><p>The <a
href="https://chrome.google.com/webstore/">Chrome Web Store</a> changes its URL when showing different items. No page refresh occurs when going from <a
href="https://chrome.google.com/webstore/category/popular">/webstore/category/popular</a> to <a
href="https://chrome.google.com/webstore/detail/pjkljhegncpnkpknbcohdijeoejaedia">/webstore/detail/pjkljhegncpnkpknbcohdijeoejaedia</a>.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2155_html5history/chrome-web-store.jpg" border="0" /></div><h3>Ensure Compatibility</h3><blockquote
class="pullquote"><p>Only load what is necessary.</p></blockquote><p>Unfortunately, older browsers do not support <code>pushState()</code> and <code>replaceState()</code>. Therefore, it is important to ensure that both your page and the user experience (UX) are not broken in those browsers. Use the tried and true concept of <a
href="http://en.wikipedia.org/wiki/Progressive_enhancement">progressive enhancement</a>.</p><p>A common use case might be to intercept a link&#8217;s click event and use Ajax to load the content in a new window while also changing the URL. Make sure that the links <strong>work normally without JavaScript</strong>; the anchor element should have a valid URL in the <code>href</code> attribute. Then for browsers that do support the new goodies, the JavaScript code would retrieve the URL&#8217;s content via Ajax. Here&#8217;s what that code might look like:</p><pre class="brush: jscript; title: ; notranslate">
//Using jQuery (would work fine with raw javascript)
if (&quot;pushState&quot; in history) {
    $(&quot;nav a&quot;).on(&quot;click&quot;, function() {
        history.pushState(null, this.textContent, this.href);
        return false;
    });​
}
</pre><h3>Don&#8217;t Download Unnecessary Markup</h3><p>Ajax is wonderful, and it can be tempting to take the easy road and download an entire HTML document to display in a modal window. Don&#8217;t do that! Downloading unnecessary data can take its toll on the UX, especially on slow connections.</p><p>Take the extra time to ensure your application doesn&#8217;t waste bytes over the wire, even if it means spending extra time on your back-end code. You can send a <a
href="http://www.web-design-talk.co.uk/197/detect-ajax-requests-using-the-x-requested-with-header-and-xmlhttprequest/">custom HTTP header</a> that indicates that the server should only serve minimal content (e.g. JSON, HTML fragments, etc).</p><pre class="brush: php; title: ; notranslate">
/* Note server support for HTTP_X_REQUESTED_WITH may vary, also it may be worth sending your own custom header in the case that the JavaScript doesn't send the header you expected */
if(isset($_SERVER['HTTP_X_REQUESTED_WITH']) &amp;&amp; strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
    //Ajax request
    echo &quot;Content without lots of crazy markup&quot;;
}
else {
    //Non-ajax request
    include('header.php');
    ...
}
</pre><p>The <a
href="https://umaar.com/demos/history/">demo</a> demonstrates this. Click on <code>cat.php</code> on Example 4, and you&#8217;ll notice only the necessary content is sent through in the response.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2155_html5history/network-panel.jpg" border="0" /></div><h3>Maintain Continuity</h3><blockquote
class="pullquote"><p>Be mindful of best practices.</p></blockquote><p>Always present the same information when the user refreshes the page. It might sound obvious, but it&#8217;s easy to forget when dealing with so much client-side code.</p><p>When you change a URL via <code>pushState()</code> from <code>http://domain.com</code> to <code>http://domain.com/contact</code>, your web server may look for a directory called <code>contact</code> or a file named <code>contact.html</code>. It&#8217;s important that URLs you use with the history API should be actual URLs that your server responds to.</p><p>There are many frameworks that can handle routing for you; it&#8217;s worth using one if you are able to.</p><ul><li><a
href="http://rubyonrails.org/">Ruby on Rails</a> (Ruby) &#8211; <a
href="http://guides.rubyonrails.org/routing.html">Routing</a></li><li><a
href="http://www.playframework.org/">Play Framework</a> (Java) &#8211; <a
href="http://www.playframework.org/documentation/2.0/JavaRouting">HTTP Routing</a></li><li><a
href="http://codeigniter.com/">CodeIgniter</a> (PHP) &#8211; <a
href="http://codeigniter.com/user_guide/general/routing.html">URI Routing</a></li><li><a
href="http://expressjs.com/">Express</a> (JavaScript on Node.js) &#8211; <a
href="http://expressjs.com/guide.html#routing">Routing</a></li><li><a
href="https://www.djangoproject.com/">django</a> (Python) &#8211; <a
href="https://docs.djangoproject.com/en/dev/topics/http/urls/">URL Dispatcher</a></li><li><a
href="http://www.asp.net">ASP.NET</a> (C#) &#8211; <a
href="http://msdn.microsoft.com/en-us/library/system.web.routing.aspx">System.Web.Routing</a></ul><p>Github <a
href="https://github.com/blog/760-the-tree-slider">uses <code>pushState()</code></a> for semantically different portions of content; their content looks the same when you refresh the page.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2155_html5history/github-pushstate.png" border="0" /></div><h3>Sensibly Handle the Forward/Back Buttons</h3><blockquote
class="pullquote"><p>Ensure that both your page and the user experience (UX) are not broken in those browsers.</p></blockquote><p>A <code>popstate</code> event fires every time the current history entry changes. Use this event for a consistent UX.</p><p>For example, let&#8217;s assume you use Ajax to load content with your team&#8217;s members. The URL might look like <code>http://domain.com/team/person1</code>. The user then clicks on the &#8220;Next&#8221; link in the UI which loads Person 2&#8242;s information (<code>http://domain.com/team/person2</code>). If the user then clicks the browser&#8217;s <em>Back</em> button, Person 1&#8242;s information may not automatically load. It&#8217;s up to you to retrieve the state information and display Person 1&#8242;s information.</p><p>Once again, be sure to <strong>only load what is necessary</strong>. If Person 1&#8242;s information is already loaded, you don&#8217;t need to request it again. Show and hide DOM elements when necessary. You can also pass state objects to <code>pushState()</code> to maintain state.</p><pre class="brush: xml; title: ; notranslate">
&lt;article data-person-id=&quot;1234&quot;&gt;...&lt;/article&gt;
</pre><pre class="brush: jscript; title: ; notranslate">
var personId = '1234';
/*
* jQuery selector
* If the html fragment for personId is found, we should show it
*/
var person = $(&quot;.person[data-person-id=&quot;+personId+&quot;]&quot;);
if ( person &amp;&amp; person.length &gt; 0 ) {
	person.show();
}
</pre><p>The ever informative <a
href="http://www.caniuse.com/">caniuse.com</a> site has a great implementation (hash fragments aside!) for handling the <em>Back</em> button. Try it out. Edit some text in the search field and click <em>Back</em>. <strong>Hint:</strong> Notice the update delay with the address bar. This delay prevents constant updates to the URL with every key press, as opposed to less frequent updates when you finish entering a search term.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2155_html5history/can-i-use.png" border="0" /></div><h3>Use <code>pushState</code> and <code>replaceState</code> Appropriately</h3><p>The <code>pushState()</code> method adds an entry to the history stack; whereas, <code>replaceState()</code> replaces the current entry. For example, let&#8217;s assume you modify the URL with every keystroke the user makes in a text box. &#8220;Pushing&#8221; a new state adds an entry to the history each time the user submits that data; this isn&#8217;t be the best solution because the user will need to click the <em>Back</em> button for each letter entry. Use <code>replaceState()</code> instead, like this:</p><pre class="brush: xml; title: ; notranslate">
&lt;input type=&quot;text&quot; id=&quot;search&quot; /&gt;
</pre><pre class="brush: jscript; title: ; notranslate">
$(&quot;#search&quot;).keyup(function() {
  history.replaceState(null, null, &quot;search?=&quot; + $(&quot;#search&quot;).val());
});
</pre><hr
/><h2>Further Reading</h2><p>Naturally, this is just the tip of the iceberg. There are many techniques, patterns, and libraries on the web that work with the HTML5 history API. While I cannot possibly cover every aspect of the history API, I can provide you with a variety of resources to further your knowledge.</p><ul><li><a
href="http://html5doctor.com/">HTML5Doctor</a> &#8211; <a
href="http://html5doctor.com/history-api/">Pushing and Popping with the History API</a></li><li><a
href="http://dev.opera.com/">dev.opera</a> &#8211; <a
href="http://dev.opera.com/articles/view/introducing-the-html5-history-api/">Introducing the HTML5 History API</a></li><li><a
href="http://davisjs.com/">Davis.js</a> &#8211; RESTful degradable JavaScript routing using pushState &#8211; (<a
href="https://github.com/olivernn/davis.js">Github</a>)</li><li><a
href="https://developer.mozilla.org">Mozilla Developer Network</a> on <a
href="https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history">Manipulating the browser history</a></li><li><a
href="https://github.com/blog">Github Blog</a> on <a
href="https://github.com/blog/760-the-tree-slider">The Tree Slider</a></li><li><a
href="http://www.w3.org">W3C</a> &#8211; <a
href="http://www.w3.org/TR/html5/history.html#the-history-interface">The History interface</a></li><li>A <a
href="http://blog.gesteves.com/2011/09/22/better-infinite-scrolling-with-the-html5-history-api/">great article</a> on how <a
href="http://piictu.com/streams/4df4fcc02d26880001000353">piictu</a> uses history management with infinite scrolling. <a
href="http://blog.gesteves.com/2011/09/22/better-infinite-scrolling-with-the-html5-history-api/">Better infinite scrolling with the HTML5 History API</a></li><li><a
href="http://diveintohtml5.info/">Dive into HTML5</a> &#8211; <a
href="http://diveintohtml5.info/history.html">Manipulating History for Fun &amp; Profit</a></li><li><a
href="http://mtrpcic.github.com/pathjs/">path.js</a> &#8211; Simple, lightweight routing for web browsers &#8211; <a
href="https://github.com/mtrpcic/pathjs">Github</a></li><li>Interesting information on <a
href="https://github.com/balupton/history.js/wiki/Intelligent-State-Handling">Intelligent State Handling</a> which is on the Wiki of the <a
href="https://github.com/balupton/history.js">history.js project</a>. (Also check out the owners <a
href="https://gist.github.com/854622">gist</a>! )</li><li><a
href="http://railscasts.com/episodes/294-playing-with-pjax">Playing with PJAX</a> &#8211; A cool screencast on using pjax within <a
href="https://github.com/rails/pjax_rails">Rails</a></li><li><a
href="http://www.thegillowfamily.co.uk/">ABaroids</a> &#8211; a game in the address bar using html5 history.replaceState!</li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/a78rrG6Ps2MAtCXTzwt_mqOVMnk/0/da"><img src="http://feedads.g.doubleclick.net/~a/a78rrG6Ps2MAtCXTzwt_mqOVMnk/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/a78rrG6Ps2MAtCXTzwt_mqOVMnk/1/da"><img src="http://feedads.g.doubleclick.net/~a/a78rrG6Ps2MAtCXTzwt_mqOVMnk/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=5tyzQkCiSrA:vOaURNQSw1w:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=5tyzQkCiSrA:vOaURNQSw1w:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=5tyzQkCiSrA:vOaURNQSw1w:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=5tyzQkCiSrA:vOaURNQSw1w:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=5tyzQkCiSrA:vOaURNQSw1w:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=5tyzQkCiSrA:vOaURNQSw1w:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=5tyzQkCiSrA:vOaURNQSw1w:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=5tyzQkCiSrA:vOaURNQSw1w:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/5tyzQkCiSrA" height="1" width="1"/>";s:3:"wfw";a:1:{s:10:"commentrss";s:91:"http://net.tutsplus.com/tutorials/html-css-techniques/a-first-look-at-the-history-api/feed/";}s:5:"slash";a:1:{s:8:"comments";s:2:"10";}s:10:"feedburner";a:1:{s:8:"origlink";s:86:"http://net.tutsplus.com/tutorials/html-css-techniques/a-first-look-at-the-history-api/";}s:7:"summary";s:20104:"<a
href='http://rss.buysellads.com/click.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28053&c=419707638' target='_blank'><img
src='http://rss.buysellads.com/img.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28053&c=419707638' border='0' alt='' /></a><p>HTML5 introduces a variety of new goodies for front-end developers, such as the additions to the browser&#8217;s <code>history</code> object. Let&#8217;s take a look at its new features in this lesson.</p><p><span
id="more-28053"></span></p><hr
/><h2>Introduction</h2><blockquote
class="pullquote"><p>Always present the same information when the user refreshes the page.</p></blockquote><p>The <code>history</code> object isn&#8217;t new; in fact, you can trace its beginnings to the early browsers from the 1990s. While it has never been based on a public standard, until HTML5 that is, every browser has supported its meager, yet sometimes useful, functionality. Since its inception, the <code>history</code> object has provided a means to work with the history of a particular tab in the browser (or a window before tabbed browsing became the norm). This is sometimes referred to as <strong>session history</strong>.</p><p>The old <code>history</code> object gave us the ability to programmatically navigate backwards and forwards, the equivalent of the user clicking the <em>Back</em> and <em>Forward</em> buttons. But HTML5 finally updates the history API by adding the ability to manipulate the browser&#8217;s URL and maintain state; although URL manipulation, to some extent, has been possible since the introduction of the <code>location</code> object. For example:</p><pre class="brush: jscript; title: ; notranslate">
//On the URL: http://net.tutsplus.com/
//Get the full URL
location.href //&quot;http://net.tutsplus.com/&quot;
//Get the hash fragment
location.hash // &quot;&quot; (an empty string)
//Set the hash fragment
location.hash = &quot;hello&quot;
//Get the full URL
location.href //&quot;http://net.tutsplus.com/#hello&quot;
//Get the hash fragment
location.hash //&quot;#hello&quot;
</pre><blockquote
class="pullquote"><p>The native API is easy enough to use&#8230;</p></blockquote><p>It&#8217;s common for some web applications to use &#8220;hash-bangs&#8221; (<code>#!</code>). Not only can they prevent the browser from navigating to a different page (making dynamic web pages easier to manage), but they can also aid in search engine optimization (SEO) (<a
href="http://www.webmonkey.com/2012/05/twitter-declares-everything-old-new-again/">until recently</a>, Twitter made extensive use of hash-bangs).</p><p>The hash-bang technique is useful when you have a lot of content that you want to display in the same page while allowing users to bookmark certain parts of a page. You can also use hash-bangs in conjunction with infinite scrolling scripts keep track of the user&#8217;s position by storing that information in the URL.</p><p>The technique is simple: store information in the URL, parse it, and then use Ajax to load content. It sounds wonderful, but there are <a
href="http://www.tbray.org/ongoing/When/201x/2011/02/09/Hash-Blecch">many</a> <a
href="http://blog.benward.me/post/3231388630">reasons</a> not <a
href="http://isolani.co.uk/blog/javascript/BreakingTheWebWithHashBangs/">to use</a> this technique. To summarize:</p><ul><li>A URL like <code>http://domain.com/#!1234</code> may fail to load correctly if JavaScript is not enabled.</li><li>You may have two different URLs pointing to the exact same content (eg: <code>http://domain.com/#!1234</code> and <code>http://domain.com/1234</code>)&#8211;a no-no for SEO.</li><li>The server is unaware of <a
href="http://en.wikipedia.org/wiki/Fragment_identifier">fragment identifiers</a>.</li></ul><hr
/><h2>Using the History API</h2><p>The History API helps solve the aforementioned issues by giving us the ability to transform URLs, like <code>http://domain.com</code> to <code>http://domain.com/hello</code>, without triggering a page refresh. The following lists the <code>history</code> object&#8217;s members and their purposes:</p><ul><li><strong><code>history.back()</code></strong>: Navigates to the previous URL in the history stack.</li><li><strong><code>history.forward()</code></strong>: Navigates to the next URL in the history stack.</li><li><strong><code>history.go()</code></strong>: Navigates to the URL at the specified index in the history stack. e.g. <code>history.go(-2)</code></li><li><strong><code>history.pushState()</code></strong>: Adds a URL to the history stack with a specified state. e.g. <code>history.pushState({ foo : "bar"}, "New title", "new-url.html")</code>, where the first argument is a state object.</li><li><strong><code>history.replaceState()</code></strong>: Updates (rather than adds) the current URL on the history stack with the provided state information. e.g. <code>history.replaceState({ foo : "bar"}, "New title", location.href)</code></li><li><strong><code>history.length</code></strong>: Returns the amount of URLs in the history stack.</li><li><strong><code>history.state</code></strong>: Returns the state object at the top of the history stack.</li></ul><p>The following example uses no external libraries:</p><pre class="brush: xml; title: ; notranslate">
&lt;nav&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;/history/example/index.html&quot;&gt;Home&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;/history/example/hello.html&quot;&gt;hello&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;/history/example/about/index.html&quot;&gt;About&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/nav&gt;
</pre><pre class="brush: jscript; title: ; notranslate">
// NodeLists do not have a forEach method
[].forEach.call(document.querySelectorAll(&quot;nav a&quot;),function(e) {
	e.addEventListener(&quot;click&quot;, function(evt) {
	  var title = this.textContent;
	  var url = this.href;
	  //Change the URL
	  history.pushState(null, title, url);
	  //Do some ajax stuff
	  //Prevent the browsers default behaviour of navigating to the hyperlink
	  evt.preventDefault();
	})
});
</pre><p>The native API is easy enough to use, but you can find many libraries that greatly help with the common patterns of intercepting a link, loading data via Ajax, and inserting the data into the page. Two popular libraries are <a
href="https://github.com/defunkt/jquery-pjax/">pjax</a> and <a
href="https://github.com/balupton/History.js/">History.js</a>.</p><hr
/><h2>With Great Power&#8230;</h2><p>As with any technology or API, be mindful of best practices. Let&#8217;s look at a few best practices when using the history API.</p><h3>Be Kind to URLs</h3><blockquote><p>Don&#8217;t change the URL just because you can; only change it when it makes sense to do so!</p></blockquote><p>For example, let&#8217;s say your online shop resides at <code>https://shop.domain.com/</code>, and the homepage displays a list of popular items. Clicking on one of the items could open a <a
href="http://en.wikipedia.org/wiki/Modal_window">modal window</a> that contains the product&#8217;s information (retrieved via Ajax, of course). You wouldn&#8217;t need to change the URL when doing this; instead, you could provide a link to the product in the modal window that would take the user to the product&#8217;s page.</p><p>Another example would be to maintain the user&#8217;s scrolling position in an infinite scrolling situation. The user could refresh the page and continue where they left off.</p><p>The <a
href="https://chrome.google.com/webstore/">Chrome Web Store</a> changes its URL when showing different items. No page refresh occurs when going from <a
href="https://chrome.google.com/webstore/category/popular">/webstore/category/popular</a> to <a
href="https://chrome.google.com/webstore/detail/pjkljhegncpnkpknbcohdijeoejaedia">/webstore/detail/pjkljhegncpnkpknbcohdijeoejaedia</a>.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2155_html5history/chrome-web-store.jpg" border="0" /></div><h3>Ensure Compatibility</h3><blockquote
class="pullquote"><p>Only load what is necessary.</p></blockquote><p>Unfortunately, older browsers do not support <code>pushState()</code> and <code>replaceState()</code>. Therefore, it is important to ensure that both your page and the user experience (UX) are not broken in those browsers. Use the tried and true concept of <a
href="http://en.wikipedia.org/wiki/Progressive_enhancement">progressive enhancement</a>.</p><p>A common use case might be to intercept a link&#8217;s click event and use Ajax to load the content in a new window while also changing the URL. Make sure that the links <strong>work normally without JavaScript</strong>; the anchor element should have a valid URL in the <code>href</code> attribute. Then for browsers that do support the new goodies, the JavaScript code would retrieve the URL&#8217;s content via Ajax. Here&#8217;s what that code might look like:</p><pre class="brush: jscript; title: ; notranslate">
//Using jQuery (would work fine with raw javascript)
if (&quot;pushState&quot; in history) {
    $(&quot;nav a&quot;).on(&quot;click&quot;, function() {
        history.pushState(null, this.textContent, this.href);
        return false;
    });​
}
</pre><h3>Don&#8217;t Download Unnecessary Markup</h3><p>Ajax is wonderful, and it can be tempting to take the easy road and download an entire HTML document to display in a modal window. Don&#8217;t do that! Downloading unnecessary data can take its toll on the UX, especially on slow connections.</p><p>Take the extra time to ensure your application doesn&#8217;t waste bytes over the wire, even if it means spending extra time on your back-end code. You can send a <a
href="http://www.web-design-talk.co.uk/197/detect-ajax-requests-using-the-x-requested-with-header-and-xmlhttprequest/">custom HTTP header</a> that indicates that the server should only serve minimal content (e.g. JSON, HTML fragments, etc).</p><pre class="brush: php; title: ; notranslate">
/* Note server support for HTTP_X_REQUESTED_WITH may vary, also it may be worth sending your own custom header in the case that the JavaScript doesn't send the header you expected */
if(isset($_SERVER['HTTP_X_REQUESTED_WITH']) &amp;&amp; strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
    //Ajax request
    echo &quot;Content without lots of crazy markup&quot;;
}
else {
    //Non-ajax request
    include('header.php');
    ...
}
</pre><p>The <a
href="https://umaar.com/demos/history/">demo</a> demonstrates this. Click on <code>cat.php</code> on Example 4, and you&#8217;ll notice only the necessary content is sent through in the response.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2155_html5history/network-panel.jpg" border="0" /></div><h3>Maintain Continuity</h3><blockquote
class="pullquote"><p>Be mindful of best practices.</p></blockquote><p>Always present the same information when the user refreshes the page. It might sound obvious, but it&#8217;s easy to forget when dealing with so much client-side code.</p><p>When you change a URL via <code>pushState()</code> from <code>http://domain.com</code> to <code>http://domain.com/contact</code>, your web server may look for a directory called <code>contact</code> or a file named <code>contact.html</code>. It&#8217;s important that URLs you use with the history API should be actual URLs that your server responds to.</p><p>There are many frameworks that can handle routing for you; it&#8217;s worth using one if you are able to.</p><ul><li><a
href="http://rubyonrails.org/">Ruby on Rails</a> (Ruby) &#8211; <a
href="http://guides.rubyonrails.org/routing.html">Routing</a></li><li><a
href="http://www.playframework.org/">Play Framework</a> (Java) &#8211; <a
href="http://www.playframework.org/documentation/2.0/JavaRouting">HTTP Routing</a></li><li><a
href="http://codeigniter.com/">CodeIgniter</a> (PHP) &#8211; <a
href="http://codeigniter.com/user_guide/general/routing.html">URI Routing</a></li><li><a
href="http://expressjs.com/">Express</a> (JavaScript on Node.js) &#8211; <a
href="http://expressjs.com/guide.html#routing">Routing</a></li><li><a
href="https://www.djangoproject.com/">django</a> (Python) &#8211; <a
href="https://docs.djangoproject.com/en/dev/topics/http/urls/">URL Dispatcher</a></li><li><a
href="http://www.asp.net">ASP.NET</a> (C#) &#8211; <a
href="http://msdn.microsoft.com/en-us/library/system.web.routing.aspx">System.Web.Routing</a></ul><p>Github <a
href="https://github.com/blog/760-the-tree-slider">uses <code>pushState()</code></a> for semantically different portions of content; their content looks the same when you refresh the page.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2155_html5history/github-pushstate.png" border="0" /></div><h3>Sensibly Handle the Forward/Back Buttons</h3><blockquote
class="pullquote"><p>Ensure that both your page and the user experience (UX) are not broken in those browsers.</p></blockquote><p>A <code>popstate</code> event fires every time the current history entry changes. Use this event for a consistent UX.</p><p>For example, let&#8217;s assume you use Ajax to load content with your team&#8217;s members. The URL might look like <code>http://domain.com/team/person1</code>. The user then clicks on the &#8220;Next&#8221; link in the UI which loads Person 2&#8242;s information (<code>http://domain.com/team/person2</code>). If the user then clicks the browser&#8217;s <em>Back</em> button, Person 1&#8242;s information may not automatically load. It&#8217;s up to you to retrieve the state information and display Person 1&#8242;s information.</p><p>Once again, be sure to <strong>only load what is necessary</strong>. If Person 1&#8242;s information is already loaded, you don&#8217;t need to request it again. Show and hide DOM elements when necessary. You can also pass state objects to <code>pushState()</code> to maintain state.</p><pre class="brush: xml; title: ; notranslate">
&lt;article data-person-id=&quot;1234&quot;&gt;...&lt;/article&gt;
</pre><pre class="brush: jscript; title: ; notranslate">
var personId = '1234';
/*
* jQuery selector
* If the html fragment for personId is found, we should show it
*/
var person = $(&quot;.person[data-person-id=&quot;+personId+&quot;]&quot;);
if ( person &amp;&amp; person.length &gt; 0 ) {
	person.show();
}
</pre><p>The ever informative <a
href="http://www.caniuse.com/">caniuse.com</a> site has a great implementation (hash fragments aside!) for handling the <em>Back</em> button. Try it out. Edit some text in the search field and click <em>Back</em>. <strong>Hint:</strong> Notice the update delay with the address bar. This delay prevents constant updates to the URL with every key press, as opposed to less frequent updates when you finish entering a search term.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2155_html5history/can-i-use.png" border="0" /></div><h3>Use <code>pushState</code> and <code>replaceState</code> Appropriately</h3><p>The <code>pushState()</code> method adds an entry to the history stack; whereas, <code>replaceState()</code> replaces the current entry. For example, let&#8217;s assume you modify the URL with every keystroke the user makes in a text box. &#8220;Pushing&#8221; a new state adds an entry to the history each time the user submits that data; this isn&#8217;t be the best solution because the user will need to click the <em>Back</em> button for each letter entry. Use <code>replaceState()</code> instead, like this:</p><pre class="brush: xml; title: ; notranslate">
&lt;input type=&quot;text&quot; id=&quot;search&quot; /&gt;
</pre><pre class="brush: jscript; title: ; notranslate">
$(&quot;#search&quot;).keyup(function() {
  history.replaceState(null, null, &quot;search?=&quot; + $(&quot;#search&quot;).val());
});
</pre><hr
/><h2>Further Reading</h2><p>Naturally, this is just the tip of the iceberg. There are many techniques, patterns, and libraries on the web that work with the HTML5 history API. While I cannot possibly cover every aspect of the history API, I can provide you with a variety of resources to further your knowledge.</p><ul><li><a
href="http://html5doctor.com/">HTML5Doctor</a> &#8211; <a
href="http://html5doctor.com/history-api/">Pushing and Popping with the History API</a></li><li><a
href="http://dev.opera.com/">dev.opera</a> &#8211; <a
href="http://dev.opera.com/articles/view/introducing-the-html5-history-api/">Introducing the HTML5 History API</a></li><li><a
href="http://davisjs.com/">Davis.js</a> &#8211; RESTful degradable JavaScript routing using pushState &#8211; (<a
href="https://github.com/olivernn/davis.js">Github</a>)</li><li><a
href="https://developer.mozilla.org">Mozilla Developer Network</a> on <a
href="https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history">Manipulating the browser history</a></li><li><a
href="https://github.com/blog">Github Blog</a> on <a
href="https://github.com/blog/760-the-tree-slider">The Tree Slider</a></li><li><a
href="http://www.w3.org">W3C</a> &#8211; <a
href="http://www.w3.org/TR/html5/history.html#the-history-interface">The History interface</a></li><li>A <a
href="http://blog.gesteves.com/2011/09/22/better-infinite-scrolling-with-the-html5-history-api/">great article</a> on how <a
href="http://piictu.com/streams/4df4fcc02d26880001000353">piictu</a> uses history management with infinite scrolling. <a
href="http://blog.gesteves.com/2011/09/22/better-infinite-scrolling-with-the-html5-history-api/">Better infinite scrolling with the HTML5 History API</a></li><li><a
href="http://diveintohtml5.info/">Dive into HTML5</a> &#8211; <a
href="http://diveintohtml5.info/history.html">Manipulating History for Fun &amp; Profit</a></li><li><a
href="http://mtrpcic.github.com/pathjs/">path.js</a> &#8211; Simple, lightweight routing for web browsers &#8211; <a
href="https://github.com/mtrpcic/pathjs">Github</a></li><li>Interesting information on <a
href="https://github.com/balupton/history.js/wiki/Intelligent-State-Handling">Intelligent State Handling</a> which is on the Wiki of the <a
href="https://github.com/balupton/history.js">history.js project</a>. (Also check out the owners <a
href="https://gist.github.com/854622">gist</a>! )</li><li><a
href="http://railscasts.com/episodes/294-playing-with-pjax">Playing with PJAX</a> &#8211; A cool screencast on using pjax within <a
href="https://github.com/rails/pjax_rails">Rails</a></li><li><a
href="http://www.thegillowfamily.co.uk/">ABaroids</a> &#8211; a game in the address bar using html5 history.replaceState!</li></ul>
<p><a href="http://feedads.g.doubleclick.net/~a/a78rrG6Ps2MAtCXTzwt_mqOVMnk/0/da"><img src="http://feedads.g.doubleclick.net/~a/a78rrG6Ps2MAtCXTzwt_mqOVMnk/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/a78rrG6Ps2MAtCXTzwt_mqOVMnk/1/da"><img src="http://feedads.g.doubleclick.net/~a/a78rrG6Ps2MAtCXTzwt_mqOVMnk/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=5tyzQkCiSrA:vOaURNQSw1w:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=5tyzQkCiSrA:vOaURNQSw1w:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=5tyzQkCiSrA:vOaURNQSw1w:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=5tyzQkCiSrA:vOaURNQSw1w:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=5tyzQkCiSrA:vOaURNQSw1w:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=5tyzQkCiSrA:vOaURNQSw1w:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=5tyzQkCiSrA:vOaURNQSw1w:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=5tyzQkCiSrA:vOaURNQSw1w:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/5tyzQkCiSrA" height="1" width="1"/>";s:14:"date_timestamp";i:1353096899;}i:7;a:13:{s:5:"title";s:12:"Why Haskell?";s:4:"link";s:54:"http://feedproxy.google.com/~r/nettuts/~3/K1PcQOE9hDc/";s:8:"comments";s:61:"http://net.tutsplus.com/tutorials/other/why-haskell/#comments";s:7:"pubdate";s:31:"Thu, 15 Nov 2012 21:07:30 +0000";s:2:"dc";a:1:{s:7:"creator";s:16:"Gabriel Manricks";}s:8:"category";s:12:"Otherhaskell";s:4:"guid";s:32:"http://net.tutsplus.com/?p=28066";s:11:"description";s:22936:"<a
href='http://rss.buysellads.com/click.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28066&c=1279376057' target='_blank'><img
src='http://rss.buysellads.com/img.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28066&c=1279376057' border='0' alt='' /></a><p>Being a purely functional language, <a
href="http://www.haskell.org/haskellwiki/Haskell">Haskell</a> limits you from many of the conventional methods of programming in an object-oriented language. But does limiting programming options truly offer us any benefits over other languages?</p><p>In this tutorial, we&#8217;ll take a look at <a
href="http://www.haskell.org/haskellwiki/Haskell">Haskell</a>, and attempt to clarify what it is, and why it just might be worth using in your future projects.</p><p><span
id="more-28066"></span></p><hr
/><h2>Haskell at a Glance</h2><blockquote
class="pullquote"><p>Haskell is a very different kind of language.</p></blockquote><p>Haskell is a very different kind of language than you may be used to, in the way that you arrange your code into &#8220;Pure&#8221; functions. A pure function is one that performs no outside tasks other than returning a computed value. These outside tasks are generally referred to as &#8220;Side-Effects.</p><p>This includes fetching outside data from the user, printing to the console, reading from a file, etc. In Haskell, you don&#8217;t put any of these types of actions into your pure functions.</p><p>Now you may be wondering, &#8220;what good is a program, if it can&#8217;t interact with the outside world?&#8221; Well, Haskell solves this with a special kind of function, called an IO function. Essentially, you separate all the data processing parts of your code into pure functions, and then put the parts which load data in and out into IO functions. The &#8220;main&#8221; function that is called when your program first runs is an IO function.</p><p>Let&#8217;s review a quick comparison between a standard Java program, and it&#8217;s Haskell equivalent.</p><h4>Java Version:</h4><pre class="brush: java; title: ; notranslate">
import java.io.*;
class Test{
    public static void main(String[] args)
    {
        System.out.println(&quot;What's Your Name: &quot;);
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String name = null;
        try {
            name = br.readLine();
        }
        catch(IOException e) {
            System.out.println(&quot;There Was an Error&quot;);
        }
        System.out.println(&quot;Hello &quot; + name);
    }
}
</pre><h4>Haskell Version:</h4><pre class="brush: ruby; title: ; notranslate">
welcomeMessage name = &quot;Hello &quot; ++ name
main = do
       putStrLn &quot;What's Your Name: &quot;
       name &lt;- getLine
       putStrLn $ welcomeMessage name
</pre><p>The first thing that you may notice when looking at a Haskell program is that there are no brackets. In Haskell , you only apply brackets when attempting to group things together. The first line at the top of the program &#8211; that starts with <code>welcomeMessage</code> &#8211; is actually a function; it accepts a string and returns the welcome message. The only other thing that may appear somewhat odd here is the dollar sign on the last line.</p><pre class="brush: ruby; title: ; notranslate">putStrLn $ welcomeMessage name</pre><p>This dollar sign simply tells Haskell to first perform what&#8217;s on the right side of the dollar sign, and then move on to the left. This is needed because, in Haskell, you could pass a function as a parameter to another function; so Haskell doesn&#8217;t know if you are trying to pass the <code>welcomeMessage</code> function to <code>putStrLn</code>, or process it first.</p><p>Besides the fact that the Haskell program is considerably shorter than the Java implementation, the main difference is that we&#8217;ve separated the data processing into a <code>pure</code> function, whereas, in the Java version, we only printed it out. This is your job in Haskell in a nutshell: separating your code into its components. Why, you ask? Well. there are a couple of reasons; let&#8217;s review some of them.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2156_whyHaskell/function.png" border="0" /></div><h3>1. Safer Code</h3><blockquote
class="pullquote"><p>There is no way for this code to break.</p></blockquote><p>If you&#8217;ve ever had programs crash on you in the past, then you know that the problem is always related to one of these unsafe operations, such as an error when reading a file, a user entered the wrong kind of data, etc. By limiting your functions to only processing data, your are guaranteed that they won&#8217;t crash. The most natural comparison that most people are familiar with is a Math function.</p><p>In Math, a function computes a result; that&#8217;s all. For example, if I were to write a Math function, like <code>f(x) = 2x + 4</code>, then, if I pass in <code>x = 2</code>, I will get <code>8</code>. If I instead pass in <code>x = 3</code>, I will get <code>10</code> as a result. There is no way for this code to break. Additionally, since everything is split up into small functions, unit-testing becomes trivial; you can test each individual part of your program and move on knowing that it&#8217;s 100% safe.</p><h3>2. Increased Code Modularity</h3><p>Another benefit to separating your code into multiple functions is code reusability. Imagine if all the standard functions, like <code>min</code> and <code>max</code>, also printed the value to the screen. Then, these functions would only be relevant in very unique circumstances, and, in most cases, you would have to write your own functions that only return a value without printing it. The same applies to your custom code. If you have a program that converts a measurement from cm to inches, you could put the actual conversion process into a pure function and then reuse it everywhere. However, if you hardcode it into your program, you will have to retype it every time. Now this seems fairly obvious in theory, but, if you remember the Java comparison from above, there are some things that we are used to just hardcoding in.</p><p>Additionally, Haskell offers two ways of combining functions: the dot operator, and higher order functions.</p><blockquote><p>The dot operator allows you to chain functions together so that the output of one function goes into the input of the next.</p></blockquote><p> Here is a quick example to demonstrate this idea:</p><pre class="brush: ruby; title: ; notranslate">
cmToInches cm  = cm * 0.3937
formatInchesStr i = show i ++ &quot; inches&quot;
main = do
    putStrLn &quot;Enter length in cm:&quot;
    inp &lt;- getLine
    let c = (read inp :: Float)
    (putStrLn . formatInchesStr . cmToInches) c
</pre><p>This is similar to the last Haskell example, but, here, I&#8217;ve combined the output of <code>cmToInches</code> to the input of <code>formatInchesStr</code>, and have tied that output to <code>putStrLn</code>. Higher order functions are functions that accept other functions as an input, or functions that output a function as its output. A helpful example of this is Haskell&#8217;s built-in <code>map</code> function. <code>map</code> takes in a function that was meant for a single value, and performs this function on an array of objects. Higher order functions allow you to abstract sections of code that multiple functions have in common, and then simply supply a function as a parameter to change the overall effect.</p><h3>3. Better Optimisation</h3><blockquote
class="pullquote"><p>In Haskell, there is no support for changing state or mutable data.</p></blockquote><p>In Haskell, there is no support for changing state or mutable data, so if you try to change a variable after it has been set, you will receive an error at compile time. This may not sound appealing at first, but it makes your program &#8220;referentially transparent&#8221;. What this means is that your functions will always return the same values, provided the same inputs. This allows Haskell to simplify your function or replace it entirely with a cached value, and your program will continue to run normally, as expected. Again, a good analogy to this is Math functions &#8211; as all Math functions are referentially transparent. If you had a function, like <code>sin(90)</code>, you could replace that with the number <code>1</code>, because they have the same value, saving you time calculating this each time. Another benefit you get with this sort of code is that, if you have functions that don&#8217;t rely on each other, you can run them in parallel &#8211; again boosting the overall performance of your application.</p><h3>4. Higher Productivity in Workflow</h3><blockquote
class="pullquote"><p>Personally, I&#8217;ve found that this leads to a considerably more efficient workflow.</p></blockquote><p>By making your functions individual components that don&#8217;t rely on anything else, you are able to plan and execute your project in a much more focused manner. Conventionally, you would make a very generic to-do list that encompasses many things, such as &#8220;Build Object Parser&#8221; or something like that, which doesn&#8217;t really allow you to know what&#8217;s involved or how long it will take. You have a basic idea, but, many times, things tend to &#8220;come up.&#8221;</p><p>In Haskell, most functions are fairly short &#8211; a couple of lines, max &#8211; and are quite focused. Most of them only execute a single specific task. But then, you have other functions, which are a combination of these lower-level functions. So your to-do list ends up being comprised of very specific functions, where you know exactly what each one does ahead of time. Personally, I&#8217;ve found that this leads to a considerably more efficient workflow.</p><p>Now this workflow is not exclusive to Haskell; you can easily do this in any language. The only difference is that this is the preferred way in Haskell, as apposed to other languages, where you are more likely to combine multiple tasks together.</p><blockquote><p>This is why I recommended that you learn Haskell, even if you don&#8217;t plan on using it every day. It forces you to get into this habit.</p></blockquote><p>Now that I&#8217;ve given you a quick overview of some of the benefits to using Haskell, let&#8217;s take a look at a real world example. Because this is a net-related site, I thought that a relevant demo would be to make a Haskell program that can backup your MySQL databases.</p><p>Let&#8217;s start with some planning.</p><hr
/><h2>Building a Haskell Program</h2><h3>Planning</h3><p>I mentioned earlier that, in Haskell, you don&#8217;t really plan out your program in an overview type style. Instead, you organize the individual functions, while, at the same time, remembering to separate the code into <code>pure</code> and IO functions. The first thing this program has to do is connect to a database and get the list of tables. These are both IO functions, because they fetch data from an outside database.</p><p>Next, we have to write a function that will cycle through the list of tables and return all the entries &#8211; this is also an IO function. Once that&#8217;s finished, we have a few <code>pure</code> functions to get the data ready for writing, and, last but not least, we have to write all the entries to backup files along with the date and a query to remove old entries. Here is a model of our program:</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2156_whyHaskell/Outline.png" border="0" /></div><p>This is the main flow of the program, but, like I said, there will also be a few helper functions to do things like getting the date and such. Now that we have everything mapped out, we can begin building the program.</p><h3>Building</h3><p>I will be using the HDBC MySQL library in this program, which you can install by running <code>cabal install HDBC</code> and <code>cabal install HDBC-mysql</code> if you have the Haskell platform installed. Let&#8217;s start with the first two functions on the list, as these are both built into the HDBC library:</p><pre class="brush: ruby; title: ; notranslate">
import Control.Monad
import Database.HDBC
import Database.HDBC.MySQL
import System.IO
import System.Directory
import Data.Time
import Data.Time.Calendar
main = do
    conn &lt;- connectMySQL defaultMySQLConnectInfo {
        mysqlHost = &quot;127.0.0.1&quot;,
        mysqlUser = &quot;root&quot;,
        mysqlPassword = &quot;pass&quot;,
        mysqlDatabase = &quot;test&quot;
    }
    tables &lt;- getTables conn
</pre><p>This part is fairly straight forward; we create the connection and then put the list of tables into a variable, called <code>tables</code>. The next function will loop through the list of tables and get all the rows in each one, a quick way to do this is to make a function that handles just one value, and then use the <code>map</code> function to apply it to the array. Since we are mapping an IO function, we have to use <code>mapM</code>. With this implemented, your code should now look like the following:</p><pre class="brush: ruby; title: ; notranslate">
getQueryString name = &quot;select * from &quot; ++ name
processTable :: IConnection conn =&gt; conn -&gt; String -&gt; IO [[SqlValue]]
processTable conn name = do
        let qu = getQueryString name
        rows &lt;- quickQuery' conn qu []
        return rows
main = do
        conn &lt;- connectMySQL defaultMySQLConnectInfo {
                mysqlHost = &quot;127.0.0.1&quot;,
                mysqlUser = &quot;root&quot;,
                mysqlPassword = &quot;pass&quot;,
                mysqlDatabase = &quot;test&quot;
        }
        tables &lt;- getTables conn
        rows &lt;- mapM (processTable conn) tables
</pre><p><code>getQueryString</code> is a pure function that returns a <code>select</code> query, and then we have the actual <code>processTable</code> function, which uses this query string to fetch all the rows from the specified table. Haskell is a strongly typed language, which basically means you can&#8217;t, for instance, put an <code>int</code> where a <code>string</code> is supposed to go. But Haskell is also &#8220;type inferencing,&#8221; which means you usually don&#8217;t need to write the types and Haskell will figure it out. Here, we have a custom <code>conn</code> type, which I needed to declare explicitly; so that is what the line above the <code>processTable</code> function is doing.</p><p>The next thing on the list is to convert the SQL values that were returned by the previous function into strings. Another way to handle lists, besides <code>map</code> is to create a recursive function. In our program, we have three layers of lists: a list of SQL values, which are in a list of rows, which are in a list of tables. I will use <code>map</code> for the first two lists, and then a recursive function to handle the final one. This will allow the function itself to be pretty short. Here is the resulting function:</p><pre class="brush: ruby; title: ; notranslate">
unSql x = (fromSql x) :: String
sqlToArray [n] = (unSql n) : []
sqlToArray (n:n2) = (unSql n) : sqlToArray n2
</pre><p>Then, add the following line to the main function:</p><pre class="brush: ruby; title: ; notranslate">
let stringRows = map (map sqlToArrays) rows
</pre><p>You may have noticed that, somtimes, variables are declared as <code>var <-
function</code>, and at other times, as <code>let var = function</code>. The rule is essentially, when you are attempting to run a IO function and place the results in a variable, you use the <code><-</code> method; to store a pure function's results within a variable, you would instead use <code>let</code>.</p><p>The next part is going to be a little tricky. We have all the rows in string format, and, now, we have to replace each row of values with an insert string that MySQL will understand. The problem is that the table names are in a separate array; so a double <code>map</code> function won't really work in this case. We could have used <code>map</code> once, but then we would have to combine the lists into one - possibly using tuples because <code>map</code> only accepts one input parameter - so I decided that it would be simpler to just write new recursive functions. Since we have a three layer array, we are going to need three seperate recursive functions, so that each level can pass down its contents to the next layer. Here are the three functions along with a helper function to generate the actual SQL query:</p><pre class="brush: ruby; title: ; notranslate">
flattenArgs [arg] = &quot;\&quot;&quot; ++ arg ++ &quot;\&quot;&quot;
flattenArgs (arg1:args) = &quot;\&quot;&quot; ++ arg1 ++ &quot;\&quot;, &quot; ++ (flattenArgs args)
iQuery name args = &quot;insert into &quot; ++ name ++ &quot; values (&quot; ++ (flattenArgs args) ++ &quot;);\n&quot;
insertStrRows name [arg] = iQuery name arg
insertStrRows name (arg1:args) = (iQuery name arg1) ++ (insertStrRows name args)
insertStrTables [table] [rows] = insertStrRows table rows : []
insertStrTables (table1:other) (rows1:etc) = (insertStrRows table1 rows1) : (insertStrTables other etc)
</pre><p>Again, add the following to the main function:</p><pre class="brush: ruby; title: ; notranslate">
let insertStrs = insertStrTables tables stringRows
</pre><p>The <code>flattenArgs</code> and <code>iQuery</code> functions work together to create the actual SQL insert query. After that, we only have the two recursive functions. Notice that, in two of the three recursive functions, we input an array, but the function returns a string. By doing this, we are removing two of the nested arrays. Now, we only have one array with one output string per table. The last step is to actually write the data to their corresponding files; this is significantly easier, now that we're merely dealing with a simple array. Here is the last part along with the function to get the date:</p><pre class="brush: ruby; title: ; notranslate">
dateStr = do
    t &lt;- getCurrentTime
    return (showGregorian . utctDay $ t)
filename name time = &quot;Backups/&quot; ++ name ++ &quot;_&quot; ++ time ++ &quot;.bac&quot;
writeToFile name queries = do
    let output = (deleteStr name) ++ queries
    time &lt;- dateStr
    createDirectoryIfMissing False &quot;Backups&quot;
    f &lt;- openFile (filename name time) WriteMode
    hPutStr f output
    hClose f
writeFiles [n] [q] = writeToFile n q
writeFiles (n:n2) (q:q2) = do
    writeFiles [n] [q]
    writeFiles n2 q2
</pre><p>The <code>dateStr</code> function converts the current date into a string with the format, <code>YYYY-MM-DD</code>. Then, there is the filename function, which puts all the pieces of the filename together. The <code>writeToFile</code> function takes care of the outputting to the files. Lastly, the <code>writeFiles</code> function iterates through the list of tables, so you can have one file per table. All that's left to do is finish up the main function with the call to <code>writeFiles</code>, and add a message informing the user when it's finished. Once completed, your <code>main</code> function should look like so:</p><pre class="brush: ruby; title: ; notranslate">
main = do
    conn &lt;- connectMySQL defaultMySQLConnectInfo {
        mysqlHost = &quot;127.0.0.1&quot;,
        mysqlUser = &quot;root&quot;,
        mysqlPassword = &quot;pass&quot;,
        mysqlDatabase = &quot;test&quot;
    }
    tables &lt;- getTables conn
    rows &lt;- mapM (processTable conn) tables
    let stringRows = map (map sqlToArray) rows
    let insertStrs = insertStrTables tables stringRows
    writeFiles tables insertStrs
    putStrLn &quot;Databases Sucessfully Backed Up&quot;
</pre><p>Now, if any of your databases ever lose their information, you can paste the SQL queries straight from their backup file into any MySQL terminal or program that can execute queries; it will restore the data to that point in time. You can also add a cron job to run this hourly or daily, in order to keep your backups up to date.</p><hr
/><h2>Finishing Up</h2><blockquote
class="pullquote"><p>There's an excellent book by Miran Lipovača, called <a
href="http://learnyouahaskell.com/">"Learn you a Haskell"</a>.</p></blockquote><p>That's all I have for this tutorial! Moving forward, if you are interested in fully learning Haskell, there are a few good resources to check out. There's an excellent book, by Miran Lipovača, called <a
href="http://learnyouahaskell.com/">"Learn you a Haskell"</a>, which even has a free online version. That would be an excellent start.</p><p>If you are looking for specific functions, you should refer to <a
href="http://www.haskell.org/hoogle/">Hoogle</a>, which is a Google-like search engine that allows you to search by name, or even by type. So, if you need a function that converts a string to a list of strings, you would type <code>String -> [String]</code>, and it will provide you with all of the applicable functions. There is also a site, called <a
href="hackage.haskell.org">hackage.haskell.org</a>, which contains the list of modules for Haskell; you can install them all through cabal.</p><p>I hope you've enjoyed this tutorial. If you have any questions at all, feel free to post a comment below; I'll do my best to get back to you as soon as possible!</p>
<p><a href="http://feedads.g.doubleclick.net/~a/M-UW0HWuisHq5BJo5M-DagTiHuM/0/da"><img src="http://feedads.g.doubleclick.net/~a/M-UW0HWuisHq5BJo5M-DagTiHuM/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/M-UW0HWuisHq5BJo5M-DagTiHuM/1/da"><img src="http://feedads.g.doubleclick.net/~a/M-UW0HWuisHq5BJo5M-DagTiHuM/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=K1PcQOE9hDc:srRcCwQVMoA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=K1PcQOE9hDc:srRcCwQVMoA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=K1PcQOE9hDc:srRcCwQVMoA:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=K1PcQOE9hDc:srRcCwQVMoA:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=K1PcQOE9hDc:srRcCwQVMoA:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=K1PcQOE9hDc:srRcCwQVMoA:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=K1PcQOE9hDc:srRcCwQVMoA:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=K1PcQOE9hDc:srRcCwQVMoA:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/K1PcQOE9hDc" height="1" width="1"/>";s:3:"wfw";a:1:{s:10:"commentrss";s:57:"http://net.tutsplus.com/tutorials/other/why-haskell/feed/";}s:5:"slash";a:1:{s:8:"comments";s:2:"16";}s:10:"feedburner";a:1:{s:8:"origlink";s:52:"http://net.tutsplus.com/tutorials/other/why-haskell/";}s:7:"summary";s:22936:"<a
href='http://rss.buysellads.com/click.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28066&c=1279376057' target='_blank'><img
src='http://rss.buysellads.com/img.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28066&c=1279376057' border='0' alt='' /></a><p>Being a purely functional language, <a
href="http://www.haskell.org/haskellwiki/Haskell">Haskell</a> limits you from many of the conventional methods of programming in an object-oriented language. But does limiting programming options truly offer us any benefits over other languages?</p><p>In this tutorial, we&#8217;ll take a look at <a
href="http://www.haskell.org/haskellwiki/Haskell">Haskell</a>, and attempt to clarify what it is, and why it just might be worth using in your future projects.</p><p><span
id="more-28066"></span></p><hr
/><h2>Haskell at a Glance</h2><blockquote
class="pullquote"><p>Haskell is a very different kind of language.</p></blockquote><p>Haskell is a very different kind of language than you may be used to, in the way that you arrange your code into &#8220;Pure&#8221; functions. A pure function is one that performs no outside tasks other than returning a computed value. These outside tasks are generally referred to as &#8220;Side-Effects.</p><p>This includes fetching outside data from the user, printing to the console, reading from a file, etc. In Haskell, you don&#8217;t put any of these types of actions into your pure functions.</p><p>Now you may be wondering, &#8220;what good is a program, if it can&#8217;t interact with the outside world?&#8221; Well, Haskell solves this with a special kind of function, called an IO function. Essentially, you separate all the data processing parts of your code into pure functions, and then put the parts which load data in and out into IO functions. The &#8220;main&#8221; function that is called when your program first runs is an IO function.</p><p>Let&#8217;s review a quick comparison between a standard Java program, and it&#8217;s Haskell equivalent.</p><h4>Java Version:</h4><pre class="brush: java; title: ; notranslate">
import java.io.*;
class Test{
    public static void main(String[] args)
    {
        System.out.println(&quot;What's Your Name: &quot;);
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String name = null;
        try {
            name = br.readLine();
        }
        catch(IOException e) {
            System.out.println(&quot;There Was an Error&quot;);
        }
        System.out.println(&quot;Hello &quot; + name);
    }
}
</pre><h4>Haskell Version:</h4><pre class="brush: ruby; title: ; notranslate">
welcomeMessage name = &quot;Hello &quot; ++ name
main = do
       putStrLn &quot;What's Your Name: &quot;
       name &lt;- getLine
       putStrLn $ welcomeMessage name
</pre><p>The first thing that you may notice when looking at a Haskell program is that there are no brackets. In Haskell , you only apply brackets when attempting to group things together. The first line at the top of the program &#8211; that starts with <code>welcomeMessage</code> &#8211; is actually a function; it accepts a string and returns the welcome message. The only other thing that may appear somewhat odd here is the dollar sign on the last line.</p><pre class="brush: ruby; title: ; notranslate">putStrLn $ welcomeMessage name</pre><p>This dollar sign simply tells Haskell to first perform what&#8217;s on the right side of the dollar sign, and then move on to the left. This is needed because, in Haskell, you could pass a function as a parameter to another function; so Haskell doesn&#8217;t know if you are trying to pass the <code>welcomeMessage</code> function to <code>putStrLn</code>, or process it first.</p><p>Besides the fact that the Haskell program is considerably shorter than the Java implementation, the main difference is that we&#8217;ve separated the data processing into a <code>pure</code> function, whereas, in the Java version, we only printed it out. This is your job in Haskell in a nutshell: separating your code into its components. Why, you ask? Well. there are a couple of reasons; let&#8217;s review some of them.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2156_whyHaskell/function.png" border="0" /></div><h3>1. Safer Code</h3><blockquote
class="pullquote"><p>There is no way for this code to break.</p></blockquote><p>If you&#8217;ve ever had programs crash on you in the past, then you know that the problem is always related to one of these unsafe operations, such as an error when reading a file, a user entered the wrong kind of data, etc. By limiting your functions to only processing data, your are guaranteed that they won&#8217;t crash. The most natural comparison that most people are familiar with is a Math function.</p><p>In Math, a function computes a result; that&#8217;s all. For example, if I were to write a Math function, like <code>f(x) = 2x + 4</code>, then, if I pass in <code>x = 2</code>, I will get <code>8</code>. If I instead pass in <code>x = 3</code>, I will get <code>10</code> as a result. There is no way for this code to break. Additionally, since everything is split up into small functions, unit-testing becomes trivial; you can test each individual part of your program and move on knowing that it&#8217;s 100% safe.</p><h3>2. Increased Code Modularity</h3><p>Another benefit to separating your code into multiple functions is code reusability. Imagine if all the standard functions, like <code>min</code> and <code>max</code>, also printed the value to the screen. Then, these functions would only be relevant in very unique circumstances, and, in most cases, you would have to write your own functions that only return a value without printing it. The same applies to your custom code. If you have a program that converts a measurement from cm to inches, you could put the actual conversion process into a pure function and then reuse it everywhere. However, if you hardcode it into your program, you will have to retype it every time. Now this seems fairly obvious in theory, but, if you remember the Java comparison from above, there are some things that we are used to just hardcoding in.</p><p>Additionally, Haskell offers two ways of combining functions: the dot operator, and higher order functions.</p><blockquote><p>The dot operator allows you to chain functions together so that the output of one function goes into the input of the next.</p></blockquote><p> Here is a quick example to demonstrate this idea:</p><pre class="brush: ruby; title: ; notranslate">
cmToInches cm  = cm * 0.3937
formatInchesStr i = show i ++ &quot; inches&quot;
main = do
    putStrLn &quot;Enter length in cm:&quot;
    inp &lt;- getLine
    let c = (read inp :: Float)
    (putStrLn . formatInchesStr . cmToInches) c
</pre><p>This is similar to the last Haskell example, but, here, I&#8217;ve combined the output of <code>cmToInches</code> to the input of <code>formatInchesStr</code>, and have tied that output to <code>putStrLn</code>. Higher order functions are functions that accept other functions as an input, or functions that output a function as its output. A helpful example of this is Haskell&#8217;s built-in <code>map</code> function. <code>map</code> takes in a function that was meant for a single value, and performs this function on an array of objects. Higher order functions allow you to abstract sections of code that multiple functions have in common, and then simply supply a function as a parameter to change the overall effect.</p><h3>3. Better Optimisation</h3><blockquote
class="pullquote"><p>In Haskell, there is no support for changing state or mutable data.</p></blockquote><p>In Haskell, there is no support for changing state or mutable data, so if you try to change a variable after it has been set, you will receive an error at compile time. This may not sound appealing at first, but it makes your program &#8220;referentially transparent&#8221;. What this means is that your functions will always return the same values, provided the same inputs. This allows Haskell to simplify your function or replace it entirely with a cached value, and your program will continue to run normally, as expected. Again, a good analogy to this is Math functions &#8211; as all Math functions are referentially transparent. If you had a function, like <code>sin(90)</code>, you could replace that with the number <code>1</code>, because they have the same value, saving you time calculating this each time. Another benefit you get with this sort of code is that, if you have functions that don&#8217;t rely on each other, you can run them in parallel &#8211; again boosting the overall performance of your application.</p><h3>4. Higher Productivity in Workflow</h3><blockquote
class="pullquote"><p>Personally, I&#8217;ve found that this leads to a considerably more efficient workflow.</p></blockquote><p>By making your functions individual components that don&#8217;t rely on anything else, you are able to plan and execute your project in a much more focused manner. Conventionally, you would make a very generic to-do list that encompasses many things, such as &#8220;Build Object Parser&#8221; or something like that, which doesn&#8217;t really allow you to know what&#8217;s involved or how long it will take. You have a basic idea, but, many times, things tend to &#8220;come up.&#8221;</p><p>In Haskell, most functions are fairly short &#8211; a couple of lines, max &#8211; and are quite focused. Most of them only execute a single specific task. But then, you have other functions, which are a combination of these lower-level functions. So your to-do list ends up being comprised of very specific functions, where you know exactly what each one does ahead of time. Personally, I&#8217;ve found that this leads to a considerably more efficient workflow.</p><p>Now this workflow is not exclusive to Haskell; you can easily do this in any language. The only difference is that this is the preferred way in Haskell, as apposed to other languages, where you are more likely to combine multiple tasks together.</p><blockquote><p>This is why I recommended that you learn Haskell, even if you don&#8217;t plan on using it every day. It forces you to get into this habit.</p></blockquote><p>Now that I&#8217;ve given you a quick overview of some of the benefits to using Haskell, let&#8217;s take a look at a real world example. Because this is a net-related site, I thought that a relevant demo would be to make a Haskell program that can backup your MySQL databases.</p><p>Let&#8217;s start with some planning.</p><hr
/><h2>Building a Haskell Program</h2><h3>Planning</h3><p>I mentioned earlier that, in Haskell, you don&#8217;t really plan out your program in an overview type style. Instead, you organize the individual functions, while, at the same time, remembering to separate the code into <code>pure</code> and IO functions. The first thing this program has to do is connect to a database and get the list of tables. These are both IO functions, because they fetch data from an outside database.</p><p>Next, we have to write a function that will cycle through the list of tables and return all the entries &#8211; this is also an IO function. Once that&#8217;s finished, we have a few <code>pure</code> functions to get the data ready for writing, and, last but not least, we have to write all the entries to backup files along with the date and a query to remove old entries. Here is a model of our program:</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2156_whyHaskell/Outline.png" border="0" /></div><p>This is the main flow of the program, but, like I said, there will also be a few helper functions to do things like getting the date and such. Now that we have everything mapped out, we can begin building the program.</p><h3>Building</h3><p>I will be using the HDBC MySQL library in this program, which you can install by running <code>cabal install HDBC</code> and <code>cabal install HDBC-mysql</code> if you have the Haskell platform installed. Let&#8217;s start with the first two functions on the list, as these are both built into the HDBC library:</p><pre class="brush: ruby; title: ; notranslate">
import Control.Monad
import Database.HDBC
import Database.HDBC.MySQL
import System.IO
import System.Directory
import Data.Time
import Data.Time.Calendar
main = do
    conn &lt;- connectMySQL defaultMySQLConnectInfo {
        mysqlHost = &quot;127.0.0.1&quot;,
        mysqlUser = &quot;root&quot;,
        mysqlPassword = &quot;pass&quot;,
        mysqlDatabase = &quot;test&quot;
    }
    tables &lt;- getTables conn
</pre><p>This part is fairly straight forward; we create the connection and then put the list of tables into a variable, called <code>tables</code>. The next function will loop through the list of tables and get all the rows in each one, a quick way to do this is to make a function that handles just one value, and then use the <code>map</code> function to apply it to the array. Since we are mapping an IO function, we have to use <code>mapM</code>. With this implemented, your code should now look like the following:</p><pre class="brush: ruby; title: ; notranslate">
getQueryString name = &quot;select * from &quot; ++ name
processTable :: IConnection conn =&gt; conn -&gt; String -&gt; IO [[SqlValue]]
processTable conn name = do
        let qu = getQueryString name
        rows &lt;- quickQuery' conn qu []
        return rows
main = do
        conn &lt;- connectMySQL defaultMySQLConnectInfo {
                mysqlHost = &quot;127.0.0.1&quot;,
                mysqlUser = &quot;root&quot;,
                mysqlPassword = &quot;pass&quot;,
                mysqlDatabase = &quot;test&quot;
        }
        tables &lt;- getTables conn
        rows &lt;- mapM (processTable conn) tables
</pre><p><code>getQueryString</code> is a pure function that returns a <code>select</code> query, and then we have the actual <code>processTable</code> function, which uses this query string to fetch all the rows from the specified table. Haskell is a strongly typed language, which basically means you can&#8217;t, for instance, put an <code>int</code> where a <code>string</code> is supposed to go. But Haskell is also &#8220;type inferencing,&#8221; which means you usually don&#8217;t need to write the types and Haskell will figure it out. Here, we have a custom <code>conn</code> type, which I needed to declare explicitly; so that is what the line above the <code>processTable</code> function is doing.</p><p>The next thing on the list is to convert the SQL values that were returned by the previous function into strings. Another way to handle lists, besides <code>map</code> is to create a recursive function. In our program, we have three layers of lists: a list of SQL values, which are in a list of rows, which are in a list of tables. I will use <code>map</code> for the first two lists, and then a recursive function to handle the final one. This will allow the function itself to be pretty short. Here is the resulting function:</p><pre class="brush: ruby; title: ; notranslate">
unSql x = (fromSql x) :: String
sqlToArray [n] = (unSql n) : []
sqlToArray (n:n2) = (unSql n) : sqlToArray n2
</pre><p>Then, add the following line to the main function:</p><pre class="brush: ruby; title: ; notranslate">
let stringRows = map (map sqlToArrays) rows
</pre><p>You may have noticed that, somtimes, variables are declared as <code>var <-
function</code>, and at other times, as <code>let var = function</code>. The rule is essentially, when you are attempting to run a IO function and place the results in a variable, you use the <code><-</code> method; to store a pure function's results within a variable, you would instead use <code>let</code>.</p><p>The next part is going to be a little tricky. We have all the rows in string format, and, now, we have to replace each row of values with an insert string that MySQL will understand. The problem is that the table names are in a separate array; so a double <code>map</code> function won't really work in this case. We could have used <code>map</code> once, but then we would have to combine the lists into one - possibly using tuples because <code>map</code> only accepts one input parameter - so I decided that it would be simpler to just write new recursive functions. Since we have a three layer array, we are going to need three seperate recursive functions, so that each level can pass down its contents to the next layer. Here are the three functions along with a helper function to generate the actual SQL query:</p><pre class="brush: ruby; title: ; notranslate">
flattenArgs [arg] = &quot;\&quot;&quot; ++ arg ++ &quot;\&quot;&quot;
flattenArgs (arg1:args) = &quot;\&quot;&quot; ++ arg1 ++ &quot;\&quot;, &quot; ++ (flattenArgs args)
iQuery name args = &quot;insert into &quot; ++ name ++ &quot; values (&quot; ++ (flattenArgs args) ++ &quot;);\n&quot;
insertStrRows name [arg] = iQuery name arg
insertStrRows name (arg1:args) = (iQuery name arg1) ++ (insertStrRows name args)
insertStrTables [table] [rows] = insertStrRows table rows : []
insertStrTables (table1:other) (rows1:etc) = (insertStrRows table1 rows1) : (insertStrTables other etc)
</pre><p>Again, add the following to the main function:</p><pre class="brush: ruby; title: ; notranslate">
let insertStrs = insertStrTables tables stringRows
</pre><p>The <code>flattenArgs</code> and <code>iQuery</code> functions work together to create the actual SQL insert query. After that, we only have the two recursive functions. Notice that, in two of the three recursive functions, we input an array, but the function returns a string. By doing this, we are removing two of the nested arrays. Now, we only have one array with one output string per table. The last step is to actually write the data to their corresponding files; this is significantly easier, now that we're merely dealing with a simple array. Here is the last part along with the function to get the date:</p><pre class="brush: ruby; title: ; notranslate">
dateStr = do
    t &lt;- getCurrentTime
    return (showGregorian . utctDay $ t)
filename name time = &quot;Backups/&quot; ++ name ++ &quot;_&quot; ++ time ++ &quot;.bac&quot;
writeToFile name queries = do
    let output = (deleteStr name) ++ queries
    time &lt;- dateStr
    createDirectoryIfMissing False &quot;Backups&quot;
    f &lt;- openFile (filename name time) WriteMode
    hPutStr f output
    hClose f
writeFiles [n] [q] = writeToFile n q
writeFiles (n:n2) (q:q2) = do
    writeFiles [n] [q]
    writeFiles n2 q2
</pre><p>The <code>dateStr</code> function converts the current date into a string with the format, <code>YYYY-MM-DD</code>. Then, there is the filename function, which puts all the pieces of the filename together. The <code>writeToFile</code> function takes care of the outputting to the files. Lastly, the <code>writeFiles</code> function iterates through the list of tables, so you can have one file per table. All that's left to do is finish up the main function with the call to <code>writeFiles</code>, and add a message informing the user when it's finished. Once completed, your <code>main</code> function should look like so:</p><pre class="brush: ruby; title: ; notranslate">
main = do
    conn &lt;- connectMySQL defaultMySQLConnectInfo {
        mysqlHost = &quot;127.0.0.1&quot;,
        mysqlUser = &quot;root&quot;,
        mysqlPassword = &quot;pass&quot;,
        mysqlDatabase = &quot;test&quot;
    }
    tables &lt;- getTables conn
    rows &lt;- mapM (processTable conn) tables
    let stringRows = map (map sqlToArray) rows
    let insertStrs = insertStrTables tables stringRows
    writeFiles tables insertStrs
    putStrLn &quot;Databases Sucessfully Backed Up&quot;
</pre><p>Now, if any of your databases ever lose their information, you can paste the SQL queries straight from their backup file into any MySQL terminal or program that can execute queries; it will restore the data to that point in time. You can also add a cron job to run this hourly or daily, in order to keep your backups up to date.</p><hr
/><h2>Finishing Up</h2><blockquote
class="pullquote"><p>There's an excellent book by Miran Lipovača, called <a
href="http://learnyouahaskell.com/">"Learn you a Haskell"</a>.</p></blockquote><p>That's all I have for this tutorial! Moving forward, if you are interested in fully learning Haskell, there are a few good resources to check out. There's an excellent book, by Miran Lipovača, called <a
href="http://learnyouahaskell.com/">"Learn you a Haskell"</a>, which even has a free online version. That would be an excellent start.</p><p>If you are looking for specific functions, you should refer to <a
href="http://www.haskell.org/hoogle/">Hoogle</a>, which is a Google-like search engine that allows you to search by name, or even by type. So, if you need a function that converts a string to a list of strings, you would type <code>String -> [String]</code>, and it will provide you with all of the applicable functions. There is also a site, called <a
href="hackage.haskell.org">hackage.haskell.org</a>, which contains the list of modules for Haskell; you can install them all through cabal.</p><p>I hope you've enjoyed this tutorial. If you have any questions at all, feel free to post a comment below; I'll do my best to get back to you as soon as possible!</p>
<p><a href="http://feedads.g.doubleclick.net/~a/M-UW0HWuisHq5BJo5M-DagTiHuM/0/da"><img src="http://feedads.g.doubleclick.net/~a/M-UW0HWuisHq5BJo5M-DagTiHuM/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/M-UW0HWuisHq5BJo5M-DagTiHuM/1/da"><img src="http://feedads.g.doubleclick.net/~a/M-UW0HWuisHq5BJo5M-DagTiHuM/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=K1PcQOE9hDc:srRcCwQVMoA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=K1PcQOE9hDc:srRcCwQVMoA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=K1PcQOE9hDc:srRcCwQVMoA:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=K1PcQOE9hDc:srRcCwQVMoA:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=K1PcQOE9hDc:srRcCwQVMoA:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=K1PcQOE9hDc:srRcCwQVMoA:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=K1PcQOE9hDc:srRcCwQVMoA:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=K1PcQOE9hDc:srRcCwQVMoA:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/K1PcQOE9hDc" height="1" width="1"/>";s:14:"date_timestamp";i:1353013650;}i:8;a:13:{s:5:"title";s:26:"Responsive Grids With Susy";s:4:"link";s:54:"http://feedproxy.google.com/~r/nettuts/~3/2UHmup7lAzA/";s:8:"comments";s:90:"http://net.tutsplus.com/tutorials/html-css-techniques/responsive-grids-with-susy/#comments";s:7:"pubdate";s:31:"Wed, 14 Nov 2012 23:03:45 +0000";s:2:"dc";a:1:{s:7:"creator";s:16:"Gabriel Manricks";}s:8:"category";s:39:"HTML & CSSTutorialscompassgridssasssusy";s:4:"guid";s:32:"http://net.tutsplus.com/?p=27893";s:11:"description";s:18672:"<a
href='http://rss.buysellads.com/click.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=27893&c=1832288559' target='_blank'><img
src='http://rss.buysellads.com/img.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=27893&c=1832288559' border='0' alt='' /></a><p>Are you happy with with any of the CSS grid libraries available? No? I don&#8217;t blame you. Enter <a
href="http://susy.oddbird.net/">Susy</a>, a plugin for the Compass CSS framework that lets you create your own custom grid framework, minimizing overhead, while making it more understandable to use. Sounds good, right? Let&#8217;s jump right in.</p><p><span
id="more-27893"></span></p><p>I&#8217;m not going to delve much into Compass or SCSS (the language you write the CSS in), but feel free to refer to our <a
href="https://tutsplus.com/course/maintainable-css-with-sass/">Maintainable CSS With Sass and Compass</a> Premium course, if you want to learn about them.</p><hr
/><h2>Setting the Stage</h2><blockquote
class="pullquote"><p>You can create three different types of grids: static, fluid and magic.</p></blockquote><p>Today&#8217;s popular grid libraries seem to fall short in one way or another. Grids like 960 and Blueprint are both static grids with very specific pixel values. Viewing these grids on screens that are under 950 pixels wide results in horizontal scroll bars&#8211;the bane of the Web.</p><p>Fluid grids are tricky to get right, but a few do exist. Most fluid grids work with percentages instead of pixels, but they tend to have a maximum size and make it impossible to scale past a respectable maximum width. By itself, a fluid layout is almost as bad as a fixed layout, because while you get better coverage of desktop computers, mobile devices tend to suffer with a worse layout. In this particular situation, a static grid gives you a better experience. Yes, you do have to scroll horizontally on devices with a lower resolution, but percentage based systems usually end up with a column that is, for example, 10% of 480px. This causes a vertical split in your text.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2148_grids/images/FluidStatic.png" border="0" /></div><p>One solution to this problem is CSS <em>media queries</em>. Some of the more popular libraries, like the <a
href="http://cssgrid.net/" alt="1140 grid">&#8220;1140 grid&#8221;</a> and the <a
href="http://twitter.github.com/bootstrap/scaffolding.html" alt="Bootstrap scaffolding grid">&#8220;Bootstrap scaffolding grid&#8221;</a>, come with preset media queries. The 1140 grid has a fluid layout, but small screen sizes cause the columns to stack on top of each other.</p><blockquote
class="pullquote"><p>Fluid grids are tricky to get right&#8230;</p></blockquote><p>Bootstrap&#8217;s scaffolding grid, on the other hand, incorporates multiple static layouts. As the screen size changes, Bootstrap changes the layout to the one best suited for the current screen size. Once you get to a mobile screen size, Bootstrap loads the same setup as the 1140 grid, a fluid layout with all the columns stacked on top of each other.</p><p>What&#8217;s wrong with choosing one of these? Well, technically nothing, but they are not tailor-made for your specific app. This forces you to build your app into their grid and work around the framework&#8217;s limitations. You can always modify their framework, but you might as well make your own and shave off the unneeded, overhead features.</p><hr
/><h2>Introducing Susy</h2><p>As I mentioned before, Susy is a plugin for the Compass framework that brings a wide array of mix-ins for creating your own CSS grids. You simply specify the default number of columns and a few size options (column width, grid padding, etc), and Susy calculates the correct percentages for your elements. This gives you the power to change the number of columns and their sizes.</p><blockquote><p>You can create three different types of grids: static, fluid and magic.</p></blockquote><p>You already know what static and fluid grids are; let&#8217;s take a look at what &#8220;magic&#8221; grids give you. Magic grids have an elastic outside and a fluid inside. In other words, the outside of the grid (max width) adjusts according to the browser&#8217;s default font size (desktop browsers usually have a default of about 16px). The grid&#8217;s inside resizes based on the browser&#8217;s actual width. This combination gives your site a more consistent look across browsers while still supporting smaller screens.</p><p>Susy provides a mix-in called &#8220;at-breakpoint&#8221;, which allows you to set custom CSS according to the size of the screen. This mix-in accomplishes this feat with CSS media queries. So for example, you can rearrange the columns to stack on top of each other like in the previously discussed frameworks, and you can even remove content that doesn&#8217;t fit a mobile device.</p><hr
/><h2>Setting Up a Susy Project</h2><p>I assume you already have Compass installed, but if not, you can refer to Jeffrey&#8217;s video series. To install Susy, just open a Ruby command line and type the following:</p><pre class="brush: bash; title: ; notranslate">
sudo gem install susy
</pre><p>Next create a Compass project. Type the following:</p><pre class="brush: bash; title: ; notranslate">
compass create project_name -r susy -u susy
</pre><p>You should see an info page, detailing how to get started.</p><p>Inside the newly created directory, you should see two folders along with a config file. You will edit the files residing in the <code>sass</code> directory; Compass compiles these files to output the final CSS to the stylesheets folder.</p><p>To save time compiling the CSS files after each update, you can use Compass&#8217; <code>watch</code> command to make Compass automatically recompile your files every time you save an update. So, in the terminal window type the following command:</p><pre class="brush: bash; title: ; notranslate">
compass watch
</pre><p>Compass will now start monitoring and re-compiling the files in the <code>sass</code> folder. Keep in mind that you must keep the terminal window open in order to monitor the folder; if you use the terminal for file editing (i.e. vim), then you need to open another window.</p><hr
/><h2>Susy in Action</h2><p>Now that you have everything setup, let&#8217;s take a look at my quick demo. I am going to keep the HTML short because it&#8217;s the CSS that we are really here for. The demo is an event guest manager that lists the invited guests and keeps track of who RSVP&#8217;d. It&#8217;s a simple idea that showcases many of the concepts we discussed.</p><h3>The Plan</h3><p>HTML-wise, there will be a header area followed by a row with the name of the event, some controls, and finally the actual list of guests. You can take a look at the image below to better understand the layout.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2148_grids/images/Imac.png" border="0" /></div><p>Here is the entire HTML page for the demo:</p><pre class="brush: xml; title: ; notranslate">
&lt;!DOCTYPE HTML&gt;
&lt;html&gt;
	&lt;head&gt;
		&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot; /&gt;
		&lt;link href=&quot;stylesheets/screen.css&quot; media=&quot;screen, projection&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;
	&lt;/head&gt;
	&lt;body&gt;
		&lt;div class=&quot;container&quot;&gt;
			&lt;h1 id=&quot;header&quot;&gt;Plan It! &lt;span class=&quot;tagline&quot;&gt;Event Guest Manager&lt;/span&gt;&lt;/h1&gt;
			&lt;div id=&quot;controls&quot;&gt;
				&lt;h3 id=&quot;menutitle&quot;&gt;Guest List For - John's Wedding&lt;/h3&gt;
				&lt;div id=&quot;buttons&quot;&gt;
					&lt;a id=&quot;phonebook&quot; href=&quot;#&quot;&gt;Add From Contacts&lt;/a&gt;
					&lt;a id=&quot;newguest&quot; href=&quot;#&quot;&gt;Add New Guest&lt;/a&gt;
				&lt;/div&gt;
			&lt;/div&gt;
			&lt;table cellspacing=&quot;0&quot;&gt;
				&lt;thead&gt;
					&lt;tr&gt;
						&lt;th&gt;Name&lt;/th&gt;
						&lt;th class=&quot;email&quot;&gt;Email&lt;/th&gt;
						&lt;th class=&quot;phone&quot;&gt;Phone&lt;/th&gt;
						&lt;th class=&quot;cell&quot;&gt;Cell&lt;/th&gt;
						&lt;th&gt;RSVP Status&lt;/th&gt;
					&lt;/tr&gt;
				&lt;/thead&gt;
				&lt;tbody&gt;
					&lt;tr&gt;
						&lt;td&gt;Dave K. Samten&lt;/th&gt;
						&lt;td class=&quot;email&quot;&gt;dsamten@gman.com&lt;/td&gt;
						&lt;td class=&quot;phone&quot;&gt;708-6777&lt;/td&gt;
						&lt;td class=&quot;cell&quot;&gt;360-234-1192&lt;/td&gt;
						&lt;td class=&quot;buttoncell&quot;&gt;
							&lt;a class=&quot;unconfirm&quot; href=&quot;#&quot; alt=&quot;Confirmed&quot;&gt;Confirmed&lt;/a&gt;
						&lt;/td&gt;
					&lt;/tr&gt;
					&lt;tr class=&quot;alt&quot;&gt;
						&lt;td&gt;Bob Renper&lt;/th&gt;
						&lt;td class=&quot;email&quot;&gt;bobren@gman.com&lt;/td&gt;
						&lt;td class=&quot;phone&quot;&gt;537-4267&lt;/td&gt;
						&lt;td class=&quot;cell&quot;&gt;621-124-4294&lt;/td&gt;
						&lt;td class=&quot;buttoncell&quot;&gt;
							&lt;a class=&quot;unconfirm&quot; href=&quot;#&quot; alt=&quot;Confirmed&quot;&gt;Confirmed&lt;/a&gt;
						&lt;/td&gt;
					&lt;/tr&gt;
					&lt;tr&gt;
						&lt;td&gt;Kevin D. Turner&lt;/th&gt;
						&lt;td class=&quot;email&quot;&gt;kturn@gman.com&lt;/td&gt;
						&lt;td class=&quot;phone&quot;&gt;942-2674&lt;/td&gt;
						&lt;td class=&quot;cell&quot;&gt;930-654-4144&lt;/td&gt;
						&lt;td class=&quot;buttoncell&quot;&gt;
							&lt;a class=&quot;confirm&quot; href=&quot;#&quot; alt=&quot;RSVP&quot;&gt;RSVP&lt;/a&gt;
						&lt;/td&gt;
					&lt;/tr&gt;
				&lt;/tbody&gt;
			&lt;/table&gt;
		&lt;/div&gt;
	&lt;/body&gt;
&lt;/html&gt;
</pre><p>Susy uses <code>min-width</code> for the media queries by default; so, you start by defining the CSS for the smallest layout and then gradually expand the layout with the increasing screen size. The &#8216;mobile&#8217; version separates the tagline and buttons onto their own lines, and we make everything fill the width of the page.</p><p>I use another Compass plugin, called Sassy Buttons, to generate the buttons&#8217; CSS. It isn&#8217;t integral to this demo, but you can install it by typing the following in a terminal:</p><pre class="brush: bash; title: ; notranslate">
gem install sassy-buttons
</pre><p>Then add the following line to your <code>config.rb</code> file:</p><pre class="brush: ruby; title: ; notranslate">
require 'sassy-buttons'
</pre><hr
/><h2>The SCSS</h2><p>Let&#8217;s define the layout. Open <code>_base.scss</code> in the <code>sass</code> folder. This file contains all the <code>import</code> statements and variables that we need later. Replace everything inside that file with the following:</p><pre class="brush: css; title: ; notranslate">
@import &quot;susy&quot;;
//if you want to use the buttons plugin
@import &quot;sassy-buttons&quot;;
//this is the default number of columns
$total-columns: 5;
//width of each column
$column-width   : 4em;
//space between columns
$gutter-width   : 1em;
//space on the right and left of the grid
$grid-padding   : $gutter-width;
//alternative layout breakpoints
$tablet: 8;
$computer: 55em 12;
</pre><blockquote
class="pullquote"><p>By itself, a fluid layout is almost as bad as a fixed layout&#8230;</p></blockquote><p>The <code>total-columns</code> holds the default number of columns for the smallest display in your layout.</p><p>I went with three layouts total: mobile, tablet, and computer. Susy&#8217;s breakpoints allow you to do things like setting the min and max sizes for the media queries, and you can even add special support for Internet Explorer. I&#8217;m going to keep this example simple and cover just two types.</p><p>The tablet breakpoint activates when the screen can fit eight columns. The computer breakpoint activates when the screen is at least 55em wide, and the <code>12</code> in <code>$computer: 55em 12;</code> tells Susy to switch to twelve columns.</p><p>Now save this file and open <code>screen.scss</code>. Erase everything in the file and import the base file. Let&#8217;s also define the main container:</p><pre class="brush: css; title: ; notranslate">
@import &quot;base&quot;;
body{
	background:#F7F3E8;
	a{ text-decoration: none; }
	.container{
		@include container($total-columns, $tablet, $computer);
</pre><p>Notice you don&#8217;t need the underscore or the file extension when importing the <code>base</code> file. Inside the container class, we use the first Susy mix-in that defines the different layouts for the grid. Then, it&#8217;s just regular SCSS for the mobile layout:</p><pre class="brush: css; title: ; notranslate">
		#header{
			font-weight: 700;
			font-size: 72px;
			span{
				font-weight: 300;
				font-size: 18px;
				display: block;
			}
		}
		#controls{
			#buttons{
				margin-bottom: 5px;
				#phonebook{ @include sassy-button(&quot;simple&quot;, 6px, 14px, #337EC4); }
				#newguest{
					margin-top: 5px;
					@include sassy-button(&quot;simple&quot;, 6px, 14px, #D93131);
				}
			}
		}
		table{
			width:100%;
			thead{
				color: #FEFEFE;
				background: #000;
				th{
					text-align: left;
					font-weight:500;
					padding:10px;
				}
			}
			tbody{
				border: 3px solid #000;
				tr{ background: #E5E5E5; }
				tr.alt{ background: #EEEEEE; }
				.buttoncell{
					.confirm{ @include sassy-button(&quot;simple&quot;, 6px, 14px, #F39B06); }
					.unconfirm{ @include sassy-button(&quot;flat&quot;, 6px, 14px, #3BA06F); }
				}
			}
			.email{ display: none; }
			.phone{ display: none; }
		}
	}
}
</pre><p>As you can see in the last two lines, I hide the email and phone columns in the table so that the page fits normally on a mobile device. As a best practice, give the user a different way to view the full information (i.e. modal, other page), but I leave that out for the sake of this example&#8217;s simplicity.</p><p>We now have the basic CSS completed for the mobile website, and we can start modifying the layout with breakpoints. Here is a quick screenshot I took on my iPhone of the mobile version:</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2148_grids/images/Iphone.png" border="0" /></div><h3>Adding Breakpoints</h3><p>The first breakpoint we need to implement is the tablet version; remember, we must start with the smallest layout first. The tablet size is large enough to put the tagline on it&#8217;s own line, and we can also display the email column. Unfortunately, it still isn&#8217;t big enough to put the event name and buttons on the same line. Here is the SCSS for this breakpoint:</p><pre class="brush: css; title: ; notranslate">
@include at-breakpoint($tablet){
	body .container{
		#header span{ display: inline; }
		table .email{ display: table-cell; }
	}
}
</pre><p>No &#8216;magic&#8217; commands here, just standard SCSS inside a Susy mix-in. Here is a screenshot from an iPad of the tablet layout:</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2148_grids/images/Ipad.png" border="0" /></div><p>Finally, let&#8217;s implement the desktop version. We definitely have more than enough room for all the columns; therefore, we indent the table on both sides so that it doesn&#8217;t have too much blank space. We also move the buttons onto the same line as the event&#8217;s name, aligning it to the right side, in order to center the table (visually, at least). Here is that code:</p><pre class="brush: css; title: ; notranslate">
@include at-breakpoint($computer){
	body .container{
		#controls{
			#menutitle{
				@include span-columns(5);
				margin-top:5px;
			}
			#buttons{
				text-align: right;
				@include span-columns(5 omega);
			}
		}
		table{
			@include prefix(1);
			@include suffix(1);
			.cell{ display: table-cell; }
		}
	}
}
</pre><p>This is the first time we use the <code>span-columns</code> mix-in. Susy takes whatever value you pass to calculate the width percentage of the container. The <code>omega</code> keyword tells Susy that this is the final column in the row. This makes Compass float the column to the right and removes the right margin.</p><blockquote><p>The <code>prefix</code> and <code>suffix</code> mix-ins push the container x amount of columns in from the left and right respectively.</p></blockquote><p>You can now save this file and let compass compile it into CSS. If you added the sassy-buttons plugin after launching the <code>compass watch</code> command, you have to stop the watch command ( shortcut: CTLR-C ) and restart it in order to compile the SCSS.</p><hr
/><h2>Closing Thoughts</h2><p>This is a very brief introduction into Susy. For a more complete list of features, you can visit <a
href="http://susy.oddbird.net/guides/reference/" alt="Susy Documentation">Susy&#8217;s documentation</a>.</p><p>I hope you enjoyed this article, and thank you for reading. Like always, feel free to leave any comments or questions in the comments section. You can also contact me on Twitter &#8211; <a
href="https://twitter.com/GabrielManricks" alt="Gabriel Manricks on Twitter">@GabrielManricks</a> and I will try to get back to you as soon as possible.</p><p></p>
<p><a href="http://feedads.g.doubleclick.net/~a/0rBrxspzSNUaH_ONKsZLX6nIUc8/0/da"><img src="http://feedads.g.doubleclick.net/~a/0rBrxspzSNUaH_ONKsZLX6nIUc8/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/0rBrxspzSNUaH_ONKsZLX6nIUc8/1/da"><img src="http://feedads.g.doubleclick.net/~a/0rBrxspzSNUaH_ONKsZLX6nIUc8/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=2UHmup7lAzA:VhO5zkYU76k:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=2UHmup7lAzA:VhO5zkYU76k:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=2UHmup7lAzA:VhO5zkYU76k:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=2UHmup7lAzA:VhO5zkYU76k:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=2UHmup7lAzA:VhO5zkYU76k:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=2UHmup7lAzA:VhO5zkYU76k:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=2UHmup7lAzA:VhO5zkYU76k:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=2UHmup7lAzA:VhO5zkYU76k:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/2UHmup7lAzA" height="1" width="1"/>";s:3:"wfw";a:1:{s:10:"commentrss";s:86:"http://net.tutsplus.com/tutorials/html-css-techniques/responsive-grids-with-susy/feed/";}s:5:"slash";a:1:{s:8:"comments";s:2:"16";}s:10:"feedburner";a:1:{s:8:"origlink";s:81:"http://net.tutsplus.com/tutorials/html-css-techniques/responsive-grids-with-susy/";}s:7:"summary";s:18672:"<a
href='http://rss.buysellads.com/click.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=27893&c=1832288559' target='_blank'><img
src='http://rss.buysellads.com/img.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=27893&c=1832288559' border='0' alt='' /></a><p>Are you happy with with any of the CSS grid libraries available? No? I don&#8217;t blame you. Enter <a
href="http://susy.oddbird.net/">Susy</a>, a plugin for the Compass CSS framework that lets you create your own custom grid framework, minimizing overhead, while making it more understandable to use. Sounds good, right? Let&#8217;s jump right in.</p><p><span
id="more-27893"></span></p><p>I&#8217;m not going to delve much into Compass or SCSS (the language you write the CSS in), but feel free to refer to our <a
href="https://tutsplus.com/course/maintainable-css-with-sass/">Maintainable CSS With Sass and Compass</a> Premium course, if you want to learn about them.</p><hr
/><h2>Setting the Stage</h2><blockquote
class="pullquote"><p>You can create three different types of grids: static, fluid and magic.</p></blockquote><p>Today&#8217;s popular grid libraries seem to fall short in one way or another. Grids like 960 and Blueprint are both static grids with very specific pixel values. Viewing these grids on screens that are under 950 pixels wide results in horizontal scroll bars&#8211;the bane of the Web.</p><p>Fluid grids are tricky to get right, but a few do exist. Most fluid grids work with percentages instead of pixels, but they tend to have a maximum size and make it impossible to scale past a respectable maximum width. By itself, a fluid layout is almost as bad as a fixed layout, because while you get better coverage of desktop computers, mobile devices tend to suffer with a worse layout. In this particular situation, a static grid gives you a better experience. Yes, you do have to scroll horizontally on devices with a lower resolution, but percentage based systems usually end up with a column that is, for example, 10% of 480px. This causes a vertical split in your text.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2148_grids/images/FluidStatic.png" border="0" /></div><p>One solution to this problem is CSS <em>media queries</em>. Some of the more popular libraries, like the <a
href="http://cssgrid.net/" alt="1140 grid">&#8220;1140 grid&#8221;</a> and the <a
href="http://twitter.github.com/bootstrap/scaffolding.html" alt="Bootstrap scaffolding grid">&#8220;Bootstrap scaffolding grid&#8221;</a>, come with preset media queries. The 1140 grid has a fluid layout, but small screen sizes cause the columns to stack on top of each other.</p><blockquote
class="pullquote"><p>Fluid grids are tricky to get right&#8230;</p></blockquote><p>Bootstrap&#8217;s scaffolding grid, on the other hand, incorporates multiple static layouts. As the screen size changes, Bootstrap changes the layout to the one best suited for the current screen size. Once you get to a mobile screen size, Bootstrap loads the same setup as the 1140 grid, a fluid layout with all the columns stacked on top of each other.</p><p>What&#8217;s wrong with choosing one of these? Well, technically nothing, but they are not tailor-made for your specific app. This forces you to build your app into their grid and work around the framework&#8217;s limitations. You can always modify their framework, but you might as well make your own and shave off the unneeded, overhead features.</p><hr
/><h2>Introducing Susy</h2><p>As I mentioned before, Susy is a plugin for the Compass framework that brings a wide array of mix-ins for creating your own CSS grids. You simply specify the default number of columns and a few size options (column width, grid padding, etc), and Susy calculates the correct percentages for your elements. This gives you the power to change the number of columns and their sizes.</p><blockquote><p>You can create three different types of grids: static, fluid and magic.</p></blockquote><p>You already know what static and fluid grids are; let&#8217;s take a look at what &#8220;magic&#8221; grids give you. Magic grids have an elastic outside and a fluid inside. In other words, the outside of the grid (max width) adjusts according to the browser&#8217;s default font size (desktop browsers usually have a default of about 16px). The grid&#8217;s inside resizes based on the browser&#8217;s actual width. This combination gives your site a more consistent look across browsers while still supporting smaller screens.</p><p>Susy provides a mix-in called &#8220;at-breakpoint&#8221;, which allows you to set custom CSS according to the size of the screen. This mix-in accomplishes this feat with CSS media queries. So for example, you can rearrange the columns to stack on top of each other like in the previously discussed frameworks, and you can even remove content that doesn&#8217;t fit a mobile device.</p><hr
/><h2>Setting Up a Susy Project</h2><p>I assume you already have Compass installed, but if not, you can refer to Jeffrey&#8217;s video series. To install Susy, just open a Ruby command line and type the following:</p><pre class="brush: bash; title: ; notranslate">
sudo gem install susy
</pre><p>Next create a Compass project. Type the following:</p><pre class="brush: bash; title: ; notranslate">
compass create project_name -r susy -u susy
</pre><p>You should see an info page, detailing how to get started.</p><p>Inside the newly created directory, you should see two folders along with a config file. You will edit the files residing in the <code>sass</code> directory; Compass compiles these files to output the final CSS to the stylesheets folder.</p><p>To save time compiling the CSS files after each update, you can use Compass&#8217; <code>watch</code> command to make Compass automatically recompile your files every time you save an update. So, in the terminal window type the following command:</p><pre class="brush: bash; title: ; notranslate">
compass watch
</pre><p>Compass will now start monitoring and re-compiling the files in the <code>sass</code> folder. Keep in mind that you must keep the terminal window open in order to monitor the folder; if you use the terminal for file editing (i.e. vim), then you need to open another window.</p><hr
/><h2>Susy in Action</h2><p>Now that you have everything setup, let&#8217;s take a look at my quick demo. I am going to keep the HTML short because it&#8217;s the CSS that we are really here for. The demo is an event guest manager that lists the invited guests and keeps track of who RSVP&#8217;d. It&#8217;s a simple idea that showcases many of the concepts we discussed.</p><h3>The Plan</h3><p>HTML-wise, there will be a header area followed by a row with the name of the event, some controls, and finally the actual list of guests. You can take a look at the image below to better understand the layout.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2148_grids/images/Imac.png" border="0" /></div><p>Here is the entire HTML page for the demo:</p><pre class="brush: xml; title: ; notranslate">
&lt;!DOCTYPE HTML&gt;
&lt;html&gt;
	&lt;head&gt;
		&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot; /&gt;
		&lt;link href=&quot;stylesheets/screen.css&quot; media=&quot;screen, projection&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot; /&gt;
	&lt;/head&gt;
	&lt;body&gt;
		&lt;div class=&quot;container&quot;&gt;
			&lt;h1 id=&quot;header&quot;&gt;Plan It! &lt;span class=&quot;tagline&quot;&gt;Event Guest Manager&lt;/span&gt;&lt;/h1&gt;
			&lt;div id=&quot;controls&quot;&gt;
				&lt;h3 id=&quot;menutitle&quot;&gt;Guest List For - John's Wedding&lt;/h3&gt;
				&lt;div id=&quot;buttons&quot;&gt;
					&lt;a id=&quot;phonebook&quot; href=&quot;#&quot;&gt;Add From Contacts&lt;/a&gt;
					&lt;a id=&quot;newguest&quot; href=&quot;#&quot;&gt;Add New Guest&lt;/a&gt;
				&lt;/div&gt;
			&lt;/div&gt;
			&lt;table cellspacing=&quot;0&quot;&gt;
				&lt;thead&gt;
					&lt;tr&gt;
						&lt;th&gt;Name&lt;/th&gt;
						&lt;th class=&quot;email&quot;&gt;Email&lt;/th&gt;
						&lt;th class=&quot;phone&quot;&gt;Phone&lt;/th&gt;
						&lt;th class=&quot;cell&quot;&gt;Cell&lt;/th&gt;
						&lt;th&gt;RSVP Status&lt;/th&gt;
					&lt;/tr&gt;
				&lt;/thead&gt;
				&lt;tbody&gt;
					&lt;tr&gt;
						&lt;td&gt;Dave K. Samten&lt;/th&gt;
						&lt;td class=&quot;email&quot;&gt;dsamten@gman.com&lt;/td&gt;
						&lt;td class=&quot;phone&quot;&gt;708-6777&lt;/td&gt;
						&lt;td class=&quot;cell&quot;&gt;360-234-1192&lt;/td&gt;
						&lt;td class=&quot;buttoncell&quot;&gt;
							&lt;a class=&quot;unconfirm&quot; href=&quot;#&quot; alt=&quot;Confirmed&quot;&gt;Confirmed&lt;/a&gt;
						&lt;/td&gt;
					&lt;/tr&gt;
					&lt;tr class=&quot;alt&quot;&gt;
						&lt;td&gt;Bob Renper&lt;/th&gt;
						&lt;td class=&quot;email&quot;&gt;bobren@gman.com&lt;/td&gt;
						&lt;td class=&quot;phone&quot;&gt;537-4267&lt;/td&gt;
						&lt;td class=&quot;cell&quot;&gt;621-124-4294&lt;/td&gt;
						&lt;td class=&quot;buttoncell&quot;&gt;
							&lt;a class=&quot;unconfirm&quot; href=&quot;#&quot; alt=&quot;Confirmed&quot;&gt;Confirmed&lt;/a&gt;
						&lt;/td&gt;
					&lt;/tr&gt;
					&lt;tr&gt;
						&lt;td&gt;Kevin D. Turner&lt;/th&gt;
						&lt;td class=&quot;email&quot;&gt;kturn@gman.com&lt;/td&gt;
						&lt;td class=&quot;phone&quot;&gt;942-2674&lt;/td&gt;
						&lt;td class=&quot;cell&quot;&gt;930-654-4144&lt;/td&gt;
						&lt;td class=&quot;buttoncell&quot;&gt;
							&lt;a class=&quot;confirm&quot; href=&quot;#&quot; alt=&quot;RSVP&quot;&gt;RSVP&lt;/a&gt;
						&lt;/td&gt;
					&lt;/tr&gt;
				&lt;/tbody&gt;
			&lt;/table&gt;
		&lt;/div&gt;
	&lt;/body&gt;
&lt;/html&gt;
</pre><p>Susy uses <code>min-width</code> for the media queries by default; so, you start by defining the CSS for the smallest layout and then gradually expand the layout with the increasing screen size. The &#8216;mobile&#8217; version separates the tagline and buttons onto their own lines, and we make everything fill the width of the page.</p><p>I use another Compass plugin, called Sassy Buttons, to generate the buttons&#8217; CSS. It isn&#8217;t integral to this demo, but you can install it by typing the following in a terminal:</p><pre class="brush: bash; title: ; notranslate">
gem install sassy-buttons
</pre><p>Then add the following line to your <code>config.rb</code> file:</p><pre class="brush: ruby; title: ; notranslate">
require 'sassy-buttons'
</pre><hr
/><h2>The SCSS</h2><p>Let&#8217;s define the layout. Open <code>_base.scss</code> in the <code>sass</code> folder. This file contains all the <code>import</code> statements and variables that we need later. Replace everything inside that file with the following:</p><pre class="brush: css; title: ; notranslate">
@import &quot;susy&quot;;
//if you want to use the buttons plugin
@import &quot;sassy-buttons&quot;;
//this is the default number of columns
$total-columns: 5;
//width of each column
$column-width   : 4em;
//space between columns
$gutter-width   : 1em;
//space on the right and left of the grid
$grid-padding   : $gutter-width;
//alternative layout breakpoints
$tablet: 8;
$computer: 55em 12;
</pre><blockquote
class="pullquote"><p>By itself, a fluid layout is almost as bad as a fixed layout&#8230;</p></blockquote><p>The <code>total-columns</code> holds the default number of columns for the smallest display in your layout.</p><p>I went with three layouts total: mobile, tablet, and computer. Susy&#8217;s breakpoints allow you to do things like setting the min and max sizes for the media queries, and you can even add special support for Internet Explorer. I&#8217;m going to keep this example simple and cover just two types.</p><p>The tablet breakpoint activates when the screen can fit eight columns. The computer breakpoint activates when the screen is at least 55em wide, and the <code>12</code> in <code>$computer: 55em 12;</code> tells Susy to switch to twelve columns.</p><p>Now save this file and open <code>screen.scss</code>. Erase everything in the file and import the base file. Let&#8217;s also define the main container:</p><pre class="brush: css; title: ; notranslate">
@import &quot;base&quot;;
body{
	background:#F7F3E8;
	a{ text-decoration: none; }
	.container{
		@include container($total-columns, $tablet, $computer);
</pre><p>Notice you don&#8217;t need the underscore or the file extension when importing the <code>base</code> file. Inside the container class, we use the first Susy mix-in that defines the different layouts for the grid. Then, it&#8217;s just regular SCSS for the mobile layout:</p><pre class="brush: css; title: ; notranslate">
		#header{
			font-weight: 700;
			font-size: 72px;
			span{
				font-weight: 300;
				font-size: 18px;
				display: block;
			}
		}
		#controls{
			#buttons{
				margin-bottom: 5px;
				#phonebook{ @include sassy-button(&quot;simple&quot;, 6px, 14px, #337EC4); }
				#newguest{
					margin-top: 5px;
					@include sassy-button(&quot;simple&quot;, 6px, 14px, #D93131);
				}
			}
		}
		table{
			width:100%;
			thead{
				color: #FEFEFE;
				background: #000;
				th{
					text-align: left;
					font-weight:500;
					padding:10px;
				}
			}
			tbody{
				border: 3px solid #000;
				tr{ background: #E5E5E5; }
				tr.alt{ background: #EEEEEE; }
				.buttoncell{
					.confirm{ @include sassy-button(&quot;simple&quot;, 6px, 14px, #F39B06); }
					.unconfirm{ @include sassy-button(&quot;flat&quot;, 6px, 14px, #3BA06F); }
				}
			}
			.email{ display: none; }
			.phone{ display: none; }
		}
	}
}
</pre><p>As you can see in the last two lines, I hide the email and phone columns in the table so that the page fits normally on a mobile device. As a best practice, give the user a different way to view the full information (i.e. modal, other page), but I leave that out for the sake of this example&#8217;s simplicity.</p><p>We now have the basic CSS completed for the mobile website, and we can start modifying the layout with breakpoints. Here is a quick screenshot I took on my iPhone of the mobile version:</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2148_grids/images/Iphone.png" border="0" /></div><h3>Adding Breakpoints</h3><p>The first breakpoint we need to implement is the tablet version; remember, we must start with the smallest layout first. The tablet size is large enough to put the tagline on it&#8217;s own line, and we can also display the email column. Unfortunately, it still isn&#8217;t big enough to put the event name and buttons on the same line. Here is the SCSS for this breakpoint:</p><pre class="brush: css; title: ; notranslate">
@include at-breakpoint($tablet){
	body .container{
		#header span{ display: inline; }
		table .email{ display: table-cell; }
	}
}
</pre><p>No &#8216;magic&#8217; commands here, just standard SCSS inside a Susy mix-in. Here is a screenshot from an iPad of the tablet layout:</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2148_grids/images/Ipad.png" border="0" /></div><p>Finally, let&#8217;s implement the desktop version. We definitely have more than enough room for all the columns; therefore, we indent the table on both sides so that it doesn&#8217;t have too much blank space. We also move the buttons onto the same line as the event&#8217;s name, aligning it to the right side, in order to center the table (visually, at least). Here is that code:</p><pre class="brush: css; title: ; notranslate">
@include at-breakpoint($computer){
	body .container{
		#controls{
			#menutitle{
				@include span-columns(5);
				margin-top:5px;
			}
			#buttons{
				text-align: right;
				@include span-columns(5 omega);
			}
		}
		table{
			@include prefix(1);
			@include suffix(1);
			.cell{ display: table-cell; }
		}
	}
}
</pre><p>This is the first time we use the <code>span-columns</code> mix-in. Susy takes whatever value you pass to calculate the width percentage of the container. The <code>omega</code> keyword tells Susy that this is the final column in the row. This makes Compass float the column to the right and removes the right margin.</p><blockquote><p>The <code>prefix</code> and <code>suffix</code> mix-ins push the container x amount of columns in from the left and right respectively.</p></blockquote><p>You can now save this file and let compass compile it into CSS. If you added the sassy-buttons plugin after launching the <code>compass watch</code> command, you have to stop the watch command ( shortcut: CTLR-C ) and restart it in order to compile the SCSS.</p><hr
/><h2>Closing Thoughts</h2><p>This is a very brief introduction into Susy. For a more complete list of features, you can visit <a
href="http://susy.oddbird.net/guides/reference/" alt="Susy Documentation">Susy&#8217;s documentation</a>.</p><p>I hope you enjoyed this article, and thank you for reading. Like always, feel free to leave any comments or questions in the comments section. You can also contact me on Twitter &#8211; <a
href="https://twitter.com/GabrielManricks" alt="Gabriel Manricks on Twitter">@GabrielManricks</a> and I will try to get back to you as soon as possible.</p><p></p>
<p><a href="http://feedads.g.doubleclick.net/~a/0rBrxspzSNUaH_ONKsZLX6nIUc8/0/da"><img src="http://feedads.g.doubleclick.net/~a/0rBrxspzSNUaH_ONKsZLX6nIUc8/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/0rBrxspzSNUaH_ONKsZLX6nIUc8/1/da"><img src="http://feedads.g.doubleclick.net/~a/0rBrxspzSNUaH_ONKsZLX6nIUc8/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=2UHmup7lAzA:VhO5zkYU76k:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=2UHmup7lAzA:VhO5zkYU76k:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=2UHmup7lAzA:VhO5zkYU76k:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=2UHmup7lAzA:VhO5zkYU76k:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=2UHmup7lAzA:VhO5zkYU76k:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=2UHmup7lAzA:VhO5zkYU76k:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=2UHmup7lAzA:VhO5zkYU76k:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=2UHmup7lAzA:VhO5zkYU76k:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/2UHmup7lAzA" height="1" width="1"/>";s:14:"date_timestamp";i:1352934225;}i:9;a:13:{s:5:"title";s:26:"Getting Started with Parse";s:4:"link";s:54:"http://feedproxy.google.com/~r/nettuts/~3/E_IivGJ37A4/";s:8:"comments";s:86:"http://net.tutsplus.com/tutorials/javascript-ajax/getting-started-with-parse/#comments";s:7:"pubdate";s:31:"Tue, 13 Nov 2012 17:00:25 +0000";s:2:"dc";a:1:{s:7:"creator";s:10:"Tilo Mitra";}s:8:"category";s:52:"DatabasesJavaScript & AJAXTutorialscloudparsestorage";s:4:"guid";s:32:"http://net.tutsplus.com/?p=28000";s:11:"description";s:22215:"<a
href='http://rss.buysellads.com/click.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28000&c=1023288711' target='_blank'><img
src='http://rss.buysellads.com/img.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28000&c=1023288711' border='0' alt='' /></a><p>I am a big fan of <a
href="https://www.parse.com/">Parse</a>, a technology that makes developing web and mobile apps faster. It lets you store, sync and push data in the cloud without writing a line of server-side code. Read on to see how you can integrate Parse in your next project.</p><p><span
id="more-28000"></span></p><hr
/><h2>A Bit of Background</h2><blockquote
class="pullquote"><p>Interacting with the database is extremely painless!</p></blockquote><p>Let&#8217;s take a step back and evaluate where web development was five years ago. We were using languages such as PHP/Ruby on the back-end that interacted with relational databases (such as MySQL), and our front-end was littered with various JavaScript files. I don&#8217;t know about you, but most of my projects were on some server with a small amount of disk space, RAM and bandwidth.</p><p>A lot of new technologies leverage the cloud, and it&#8217;s not uncommon to see developers taking advantage of these cost-effective services, such as AWS, Amazon S3, Heroku, and more. The introduction of these services essentially altered the web development landscape; more of what we do resides in the cloud.</p><p>Today, we&#8217;re going to look at Parse, a startup that offers a cloud-based data management system. By leveraging their service, I was able to rapidly create new mobile and web apps. We&#8217;re going to use Parse to create the obligatory To-do web application, and I hope it gives you a taste of what the service can offer.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2152_parse/app-screenshot.png" alt="Envato Todo List App"></div><hr
/><h2>What&#8217;s Parse?</h2><p>Simply put, Parse is a cloud-based data management system that allows you to quickly develop web and mobile apps.</p><blockquote><p>It makes developing apps <em>really</em> easy by taking the back-end out of your hands.</p></blockquote><p>So, how&#8217;s this work? Well, let&#8217;s assume you&#8217;re a web developer. You can add the Parse JavaScript file on your page, get an API key, and start saving &#8220;objects&#8221; in the cloud with only a few lines of code. Parse frees you from setting up a server-side stack.</p><p>Think about this for a minute. Traditionally, you set up a server-side stack (LAMP, or RoR, ASP.NET, or something else), set up a database, and then interact with it via Ajax on the client. Parse just reduced all that work to a few lines of code.</p><p>In this tutorial, we&#8217;ll use Parse&#8217;s JavaScript SDK. You&#8217;re not limited to using only JavaScript, however; there are Parse libraries in many different languages, including PHP, NodeJS, Java, C# and more. You can find all the available libraries <a
href="https://parse.com/docs/api_libraries">here</a>.</p><hr
/><h2>Using Parse for Your Web-based Projects</h2><p>Before we start, let&#8217;s take a minute and think how a traditional To-do list app could be created using a LAMP stack.</p><ul><li>You would create a MySQL database.</li><li>You may have a PHP class that is responsible for performing CRUD operations. Optionally, you could just have a bunch of PHP functions.</li><li>You may use JavaScript and Ajax on the client-side to call the respective PHP scripts and pass in query strings.</li><li>You would need to sanitize the input to protect against XSS attacks, as well as worry about database security in general.</li><li>If a collaborative app, you would need to track different users and manage their lists. More code, more tables, and more schemas.</li><li>You would need to make sure your database stays performant.</li></ul><p>You get the idea. There&#8217;s a lot to think about and many areas to make mistakes. Parse handles these issues for us.</p><h3>Create a Parse Account</h3><p>Before you do anything, create a <a
href="https://parse.com/">free Parse account</a>. Then create a new app called EnvatoTodo.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2152_parse/create-new-app.png" alt="Create a new Parse App"></div><h3>Download the Empty Project</h3><p>Parse provides a great QuickStart guide to help you get started. Select JavaScript and choose EnvatoTodo from the drop down menu in step 2 (shown in the image below). Parse will generate a zip file that contains the Parse SDK and <code>index.html</code>.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2152_parse/quickstart.png" alt="Parse Quickstart Guide"></div><h3>The Client-Side</h3><p>Before we start interacting with Parse, let&#8217;s set up a basic client-side structure for our application. Since the UI is not the focus of this application, I&#8217;ll just show you the code that I used. It&#8217;s nothing fancy, but I&#8217;m using YUI3. You could optionally use jQuery. Everything is in <code>index.html</code>.</p><pre class="brush: xml; title: ; notranslate">&lt;!DOCTYPE html&gt;
&lt;head&gt;
  &lt;meta charset=&quot;utf-8&quot;&gt;
  &lt;title&gt;Todo App Built on Parse&lt;/title&gt;
  &lt;meta name=&quot;description&quot; content=&quot;My Parse App&quot;&gt;
  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width&quot;&gt;
  &lt;link rel=&quot;stylesheet&quot; href=&quot;css/reset.css&quot;&gt;
  &lt;link rel=&quot;stylesheet&quot; href=&quot;css/styles.css&quot;&gt;
  &lt;script src=&quot;http://yui.yahooapis.com/3.6.0/build/yui/yui-min.js&quot;&gt;&lt;/script&gt;
  &lt;script type=&quot;text/javascript&quot; src=&quot;http://www.parsecdn.com/js/parse-1.0.19.min.js&quot;&gt;&lt;/script&gt;
    &lt;style&gt;
        body {
            font-family: &quot;HelveticaNeue-Light&quot;, sans-serif;
            font-weight:300;
        }
        h2 {
            font-size:16px;
            text-transform:uppercase;
        }
        a {
            text-decoration:none;
        }
        .hidden {
            display:none;
        }
        #main {
            text-align:center;
        }
        input {
            padding: 10px;
            border-radius: 3px;
            border:1px solid #ccc;
            box-shadow: inset 0 0 10px #eee;
            font-size:24px;
        }
        #input-wrapper {
            padding-bottom:15px;
        }
        #list-item-submit {
            background: #73D175;
            color: white;
            box-shadow:none;
            border-color: #599E5A;
        }
        li {
            text-align:left;
            font-family:sans-serif;
            list-style: none;
            padding: 10px 0;
            border-bottom:1px solid #ccc;
            margin-left:-10px;
        }
        li input {
            margin-right:15px;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;h1&gt;Todo List built on &lt;a href=&quot;http://www.parse.com&quot; alt=&quot;Parse&quot;&gt;Parse&lt;/a&gt;&lt;/h1&gt;
  &lt;div id=&quot;main&quot;&gt;
        &lt;div id=&quot;input-wrapper&quot;&gt;
            &lt;input type=&quot;text&quot; id=&quot;list-input&quot; placeholder=&quot;Enter a todo here...&quot;&gt;
            &lt;input type=&quot;button&quot; id=&quot;list-item-submit&quot; value=&quot;Add&quot;&gt;
        &lt;/div&gt;
        &lt;div&gt;
            &lt;h2&gt;Incomplete Tasks&lt;/h2&gt;
            &lt;ul id=&quot;incomplete-items&quot;&gt;
                &lt;li id=&quot;no-incomplete-message&quot;&gt;There are no incomplete tasks! Consider adding one above.&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/div&gt;
  &lt;/div&gt;
    &lt;!-- This is a template that we'll be using to populate our list items --&gt;
    &lt;script id=&quot;todo-items-template&quot; type=&quot;x/handlebars&quot;&gt;
        &lt;li class=&quot;list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;{id}&quot;&gt;{content}&lt;/li&gt;
    &lt;/script&gt;
    &lt;script&gt;
        //Use the YUI 'node' module.
        YUI().use('node', function(Y) {
            //Lets declare some variables that we'll be using.
            var ListItem,
            query,
            noTasksMessage = Y.one('#no-incomplete-message'),
            submitBtn = Y.one(&quot;#list-item-submit&quot;),
            incompleteItemList = Y.one('#incomplete-items'),
            completeItemList = Y.one('#complete-items'),
            input = Y.one(&quot;#list-input&quot;);
            //The rest of our application code will go below.
            submitBtn.on('click', function(e) {
                /*
                When the submit button is clicked, we want to get the contents of the input and save a new todo list item.
                */
            });
            /*
            When a &lt;li&gt; is clicked, we want to save that item as being complete. We use 'delegate' here instead of 'on' so that we only create one event listener instead of one for each checkbox.
            */
            incompleteItemList.delegate('click', function(e) {
            }, 'li');
            /* We also want to get the 10 most recent incomplete tasks and add them to &lt;div id=&quot;incomplete-items&quot;&gt;&lt;/div&gt; */
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre><p>The important thing to note in the above code is the inclusion of the Parse JavaScript file, <code>&lt;script src="http://www.parsecdn.com/js/parse-1.0.19.min.js"&gt;&lt;/script&gt;</code>. This file contains the Parse object that we will interact with.</p><h3>Add Classes in the Data Browser</h3><blockquote
class="pullquote"><p>Parse frees you from setting up a server-side stack.</p></blockquote><p>Let&#8217;s get back to Parse. View the Data Browser for EnvatoTodo (it&#8217;s currently empty). The Data Browser is similar to a MySQL database server, but the Parse DB is schema-less. While you can specify columns in the Data Browser, you can actually save any object with simple JSON (not unlike many NoSQL/Document databases). This is an extremely important and useful feature of Parse.</p><p>We&#8217;re going to go ahead and add a &#8220;class&#8221; to the database. Think of a class as a table. The reason it&#8217;s called a class is because you&#8217;ll generally create objects from a certain class and then save that object to the database.</p><p><strong>Disclaimer:</strong> JavaScript does not officially have classes (yet), but it does have the logical equivalent. For the sake of simplicity, I will use the terminology &#8220;class&#8221; in this tutorial.</p><p>Parse has five types of classes.</p><ul><li><strong>User classes</strong> store user-specific information, and Parse provides sugar methods such as <code>signUp()</code>, <code>login()</code>, and more to help with user administration.</li><li><strong>Installation classes</strong> are typically used to send push notifications for mobile apps. Yes, Parse supports push notifications to all clients.</li><li><strong>Role classes</strong> help segregate users into specific roles, controlling access to read/write to other classes. This is called ACL (access control list) within Parse.</li><li><strong>Product classes</strong> store in-app product data.</li><li><strong>Custom classes</strong> are for anything else.</li></ul><p>Let&#8217;s create a custom class called <code>ListItem</code>. Once it&#8217;s created, you&#8217;ll notice it already has four properties. Parse automatically updates the properties of every class that you create. Some classes, such as user classes, may have their own specific properties.</p><p>Our <code>ListItem</code> objects will contain a <code>content</code> property to show what the Todo contains, and an <code>isComplete</code> property to indicate whether the Todo was completed. We could add columns for these properties, but Parse will figure it out from our JSON.</p><h3>Initializing Parse</h3><p>Let&#8217;s go back to <code>index.html</code> to add some code. The first thing we want to do is initialize Parse with our App ID and JavaScript key. These can be found under the Overview tab of your application inside the Data Browser. Add the following line to your JavaScript, replacing <code>APP_ID</code> and <code>JS_KEY</code> with the appropriate values:</p><pre class="brush: jscript; title: ; notranslate">
Parse.initialize(APP_ID, JS_KEY);
</pre><h3>Saving Todos</h3><p>Let&#8217;s start adding functionality to our application. We&#8217;ll first save a To-do list item when the user clicks the add button. The following code is all we need for this functionality:</p><pre class="brush: jscript; title: ; notranslate">
submitBtn.on('click', function(e) {
    //Extend the native Parse.Object class.
    var ListItem = Parse.Object.extend(&quot;ListItem&quot;);
    //Instantiate an object of the ListItem class
    var listItem = new ListItem();
    //listItem is now the object that we want to save, so we assign the properties that we want on it.
    listItem.set(&quot;content&quot;, text);
    listItem.set(&quot;isComplete&quot;, false);
    //We call the save method, and pass in success and failure callback functions.
    listItem.save(null, {
        success: function(item) {
        //Success Callback
    },
    error: function(gameScore, error) {
        //Failure Callback
    }
    });
});
</pre><p>Interacting with the database is extremely painless! Every custom class in Parse inherits from <code>Parse.Object</code>; therefore, <code>ListItem</code> is a subclass. The string argument <code>"ListItem"</code> tells Parse that this class correlates to the ListItem table that we created. Then we create a new <code>ListItem</code> object, set its properties, and call <code>save()</code>.</p><h3>Showing Items</h3><p>In order to display a list of To-do items, we&#8217;ll use the <a
href="https://parse.com/docs/js_guide">Parse JavaScript API</a> to query the ten most recently saved items, and list those below the app. This will give you an idea as to how queries work in Parse.</p><pre class="brush: jscript; title: ; notranslate">
//Once again, we extend the Parse.Object class to make the ListItem class
ListItem = Parse.Object.extend(&quot;ListItem&quot;);
//This time, we use Parse.Query to generate a new query, specifically querying the ListItem table.
query = new Parse.Query(ListItem);
//We set constraints on the query.
query.equalTo('isComplete', false)
query.limit = 10;
query.descending('createdAt');
//We submit the query and pass in callback functions.
query.find({
  success: function(results) {
    //Success callback
  },
  error: function(error) {
    //Error Callback
  }
});
</pre><p>Once again, it&#8217;s fairly simple and easy to read. The <code>Parse.Query()</code> method is quite powerful. Here, we perform a fairly basic query, but Parse queries can be complex as well. You can query for specific regular expressions, perform relational queries, and many more. Be sure to visit the <a
href="https://parse.com/docs/js_guide#queries">Query Documentation</a> for more examples and code snippets.</p><h3>Putting it all together</h3><p>The next thing we need to add is the ability to mark a to-do item as complete when checking the item&#8217;s checkbox. Each checkbox has a unique <code>id</code> associated with the Parse object that it represents. Therefore, when a checkbox is clicked, we need to:</p><ul><li>Get the id.</li><li>Query for a Parse object with that id.</li><li>Get the returned Parse object, and update it&#8217;s <code>isComplete</code> property as <code>true</code>.</li><li>Save the updated object.</li><li>Remove it from the displayed list.</li></ul><p>Here&#8217;s what that code looks like:</p><pre class="brush: jscript; title: ; notranslate">
incompleteItemList.delegate('click', function (e) {
    //keep a reference to this
    var self = this;
    //create a Parse query object
    var query = new Parse.Query(ListItem);
    //The query.get() method requires the objectId as its first argument. It returns the object with that id.
    query.get(self.one('input').get('id'), {
      success: function(item) {
        //Once the object is returned, we update its property and save it.
        item.set('isComplete', true);
            item.save();
            //Since the item is no longer incomplete, we remove it from the list.
            self.remove();
            //If there's nothing in the list, show a message saying the list is empty.
            if (incompleteItemList.all('li').size() &gt;= 1) {
                noTasksMessage.removeClass('hidden');
            }
      },
      error: function(object, error) {
            alert(&quot;Error when updating todo item: &quot; + error.code + &quot; &quot; + error.message);
      }
    });
}, 'li');
</pre><p>In this snippet, we query for an individual element with a specific <code>id</code>, update it, and save it. Then we remove it from the list with <code>self.remove()</code>.</p><p>In Parse, updating objects is very similar to saving objects&#8211;we call <code>save()</code> in both cases. Parse figures out whether it&#8217;s an existing (dirty) object, or an entirely new object and performs the appropriate action.</p><h3>Complete Source Code</h3><p>With that, we&#8217;re good to go! Pretty easy, eh? Download the attached ZIP file and open <code>index.html</code> to view the entire source code.</p><hr
/><h2>Other Features</h2><p>In this tutorial, we primarily looked at Parse from a web development point-of-view. However, the service was originally started with mobile developers in mind. Parse has a very thorough SDK for Android and iOS, and it supports features such as push notifications to all users of your mobile app.</p><blockquote><p>Some other big features that we didn&#8217;t cover in this tutorial involve users, roles, and storing relational information.</p></blockquote><p>Parse makes it relatively simple to create users, and assign different roles to them. For example, in a learning management system, you may have &#8220;Teachers&#8221;, &#8220;Students&#8221;, and &#8220;Administrators&#8221;. By assigning roles, you can specify which type of user has access to certain Parse objects.</p><hr
/><h2>What about Security?</h2><blockquote
class="pullquote"><p>A lot of new technologies leverage the cloud&#8230;</p></blockquote><p>As a developer, I like that Parse takes care of a lot of the security concerns that I have. As it states on the website, the Parse SDKs are designed &#8220;so that you typically don&#8217;t need to worry about how data is saved.&#8221; There&#8217;s still the issue of users having access to information that they shouldn&#8217;t be able to. To address this concern, Parse offers Object-level and Class-level permissions.</p><p>Object-level permissions allow a developer to specify an array of object IDs that have access to read and/or write the object. Class-level permissions allow a developer to specify what aspects of a Parse class can be manipulated from the API. The following operations can be allowed or denied on a per-class basis: Get, Find, Update, Create, Delete, and Add Fields.</p><hr
/><h2>Pros and Cons</h2><p>I want to stress is that Parse is not suitable for every type of project. Although the free plan is very generous, Parse is a paid service. It can get <a
href="https://parse.com/plans">expensive</a> if you go above certain limits. Luckily, the pricing model is very transparent, and you should be able to figure out how much your app can cost. Generally speaking, I use it for smaller projects where I can anticipate a certain cap when it comes to the number of API requests that I make. I have yet to try Parse for a large project.</p><blockquote><p>One common issue with a service such as Parse is the lock-in effect.</p></blockquote><p>If you use Parse for a small project that suddenly takes off, it can be difficult to move to a difference service or platform. As you can imagine, replacing Parse with your own back-end would entail a significant amount of refactoring. This doesn&#8217;t mean you shouldn&#8217;t use Parse, but it&#8217;s something to keep in mind.</p><hr
/><h2>Concluding Remarks</h2><p>In this tutorial, we looked at how we can use Parse to create a relatively simple web application. I&#8217;ve used this service for a number of projects for various clients, and I find the Parse team to be very helpful when issues arise. I encourage you give the service a try, and make your own decision!</p><p>Disclosure: I have no relationship with Parse or any of its employees. I&#8217;m just a developer who uses their service, and I find it to be a helpful addition to my development workflow.</p>
<p><a href="http://feedads.g.doubleclick.net/~a/C0JgV_PYrjpQ-z4YjmX3Tdi08-U/0/da"><img src="http://feedads.g.doubleclick.net/~a/C0JgV_PYrjpQ-z4YjmX3Tdi08-U/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/C0JgV_PYrjpQ-z4YjmX3Tdi08-U/1/da"><img src="http://feedads.g.doubleclick.net/~a/C0JgV_PYrjpQ-z4YjmX3Tdi08-U/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=E_IivGJ37A4:cK2X1Hva7bQ:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=E_IivGJ37A4:cK2X1Hva7bQ:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=E_IivGJ37A4:cK2X1Hva7bQ:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=E_IivGJ37A4:cK2X1Hva7bQ:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=E_IivGJ37A4:cK2X1Hva7bQ:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=E_IivGJ37A4:cK2X1Hva7bQ:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=E_IivGJ37A4:cK2X1Hva7bQ:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=E_IivGJ37A4:cK2X1Hva7bQ:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/E_IivGJ37A4" height="1" width="1"/>";s:3:"wfw";a:1:{s:10:"commentrss";s:82:"http://net.tutsplus.com/tutorials/javascript-ajax/getting-started-with-parse/feed/";}s:5:"slash";a:1:{s:8:"comments";s:2:"18";}s:10:"feedburner";a:1:{s:8:"origlink";s:77:"http://net.tutsplus.com/tutorials/javascript-ajax/getting-started-with-parse/";}s:7:"summary";s:22215:"<a
href='http://rss.buysellads.com/click.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28000&c=1023288711' target='_blank'><img
src='http://rss.buysellads.com/img.php?z=1260013&k=d754f1e9ba63a736ba8ff5ece958f7dd&a=28000&c=1023288711' border='0' alt='' /></a><p>I am a big fan of <a
href="https://www.parse.com/">Parse</a>, a technology that makes developing web and mobile apps faster. It lets you store, sync and push data in the cloud without writing a line of server-side code. Read on to see how you can integrate Parse in your next project.</p><p><span
id="more-28000"></span></p><hr
/><h2>A Bit of Background</h2><blockquote
class="pullquote"><p>Interacting with the database is extremely painless!</p></blockquote><p>Let&#8217;s take a step back and evaluate where web development was five years ago. We were using languages such as PHP/Ruby on the back-end that interacted with relational databases (such as MySQL), and our front-end was littered with various JavaScript files. I don&#8217;t know about you, but most of my projects were on some server with a small amount of disk space, RAM and bandwidth.</p><p>A lot of new technologies leverage the cloud, and it&#8217;s not uncommon to see developers taking advantage of these cost-effective services, such as AWS, Amazon S3, Heroku, and more. The introduction of these services essentially altered the web development landscape; more of what we do resides in the cloud.</p><p>Today, we&#8217;re going to look at Parse, a startup that offers a cloud-based data management system. By leveraging their service, I was able to rapidly create new mobile and web apps. We&#8217;re going to use Parse to create the obligatory To-do web application, and I hope it gives you a taste of what the service can offer.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2152_parse/app-screenshot.png" alt="Envato Todo List App"></div><hr
/><h2>What&#8217;s Parse?</h2><p>Simply put, Parse is a cloud-based data management system that allows you to quickly develop web and mobile apps.</p><blockquote><p>It makes developing apps <em>really</em> easy by taking the back-end out of your hands.</p></blockquote><p>So, how&#8217;s this work? Well, let&#8217;s assume you&#8217;re a web developer. You can add the Parse JavaScript file on your page, get an API key, and start saving &#8220;objects&#8221; in the cloud with only a few lines of code. Parse frees you from setting up a server-side stack.</p><p>Think about this for a minute. Traditionally, you set up a server-side stack (LAMP, or RoR, ASP.NET, or something else), set up a database, and then interact with it via Ajax on the client. Parse just reduced all that work to a few lines of code.</p><p>In this tutorial, we&#8217;ll use Parse&#8217;s JavaScript SDK. You&#8217;re not limited to using only JavaScript, however; there are Parse libraries in many different languages, including PHP, NodeJS, Java, C# and more. You can find all the available libraries <a
href="https://parse.com/docs/api_libraries">here</a>.</p><hr
/><h2>Using Parse for Your Web-based Projects</h2><p>Before we start, let&#8217;s take a minute and think how a traditional To-do list app could be created using a LAMP stack.</p><ul><li>You would create a MySQL database.</li><li>You may have a PHP class that is responsible for performing CRUD operations. Optionally, you could just have a bunch of PHP functions.</li><li>You may use JavaScript and Ajax on the client-side to call the respective PHP scripts and pass in query strings.</li><li>You would need to sanitize the input to protect against XSS attacks, as well as worry about database security in general.</li><li>If a collaborative app, you would need to track different users and manage their lists. More code, more tables, and more schemas.</li><li>You would need to make sure your database stays performant.</li></ul><p>You get the idea. There&#8217;s a lot to think about and many areas to make mistakes. Parse handles these issues for us.</p><h3>Create a Parse Account</h3><p>Before you do anything, create a <a
href="https://parse.com/">free Parse account</a>. Then create a new app called EnvatoTodo.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2152_parse/create-new-app.png" alt="Create a new Parse App"></div><h3>Download the Empty Project</h3><p>Parse provides a great QuickStart guide to help you get started. Select JavaScript and choose EnvatoTodo from the drop down menu in step 2 (shown in the image below). Parse will generate a zip file that contains the Parse SDK and <code>index.html</code>.</p><div
class="tutorial_image"><img
src="http://d2o0t5hpnwv4c1.cloudfront.net/2152_parse/quickstart.png" alt="Parse Quickstart Guide"></div><h3>The Client-Side</h3><p>Before we start interacting with Parse, let&#8217;s set up a basic client-side structure for our application. Since the UI is not the focus of this application, I&#8217;ll just show you the code that I used. It&#8217;s nothing fancy, but I&#8217;m using YUI3. You could optionally use jQuery. Everything is in <code>index.html</code>.</p><pre class="brush: xml; title: ; notranslate">&lt;!DOCTYPE html&gt;
&lt;head&gt;
  &lt;meta charset=&quot;utf-8&quot;&gt;
  &lt;title&gt;Todo App Built on Parse&lt;/title&gt;
  &lt;meta name=&quot;description&quot; content=&quot;My Parse App&quot;&gt;
  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width&quot;&gt;
  &lt;link rel=&quot;stylesheet&quot; href=&quot;css/reset.css&quot;&gt;
  &lt;link rel=&quot;stylesheet&quot; href=&quot;css/styles.css&quot;&gt;
  &lt;script src=&quot;http://yui.yahooapis.com/3.6.0/build/yui/yui-min.js&quot;&gt;&lt;/script&gt;
  &lt;script type=&quot;text/javascript&quot; src=&quot;http://www.parsecdn.com/js/parse-1.0.19.min.js&quot;&gt;&lt;/script&gt;
    &lt;style&gt;
        body {
            font-family: &quot;HelveticaNeue-Light&quot;, sans-serif;
            font-weight:300;
        }
        h2 {
            font-size:16px;
            text-transform:uppercase;
        }
        a {
            text-decoration:none;
        }
        .hidden {
            display:none;
        }
        #main {
            text-align:center;
        }
        input {
            padding: 10px;
            border-radius: 3px;
            border:1px solid #ccc;
            box-shadow: inset 0 0 10px #eee;
            font-size:24px;
        }
        #input-wrapper {
            padding-bottom:15px;
        }
        #list-item-submit {
            background: #73D175;
            color: white;
            box-shadow:none;
            border-color: #599E5A;
        }
        li {
            text-align:left;
            font-family:sans-serif;
            list-style: none;
            padding: 10px 0;
            border-bottom:1px solid #ccc;
            margin-left:-10px;
        }
        li input {
            margin-right:15px;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;h1&gt;Todo List built on &lt;a href=&quot;http://www.parse.com&quot; alt=&quot;Parse&quot;&gt;Parse&lt;/a&gt;&lt;/h1&gt;
  &lt;div id=&quot;main&quot;&gt;
        &lt;div id=&quot;input-wrapper&quot;&gt;
            &lt;input type=&quot;text&quot; id=&quot;list-input&quot; placeholder=&quot;Enter a todo here...&quot;&gt;
            &lt;input type=&quot;button&quot; id=&quot;list-item-submit&quot; value=&quot;Add&quot;&gt;
        &lt;/div&gt;
        &lt;div&gt;
            &lt;h2&gt;Incomplete Tasks&lt;/h2&gt;
            &lt;ul id=&quot;incomplete-items&quot;&gt;
                &lt;li id=&quot;no-incomplete-message&quot;&gt;There are no incomplete tasks! Consider adding one above.&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/div&gt;
  &lt;/div&gt;
    &lt;!-- This is a template that we'll be using to populate our list items --&gt;
    &lt;script id=&quot;todo-items-template&quot; type=&quot;x/handlebars&quot;&gt;
        &lt;li class=&quot;list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; id=&quot;{id}&quot;&gt;{content}&lt;/li&gt;
    &lt;/script&gt;
    &lt;script&gt;
        //Use the YUI 'node' module.
        YUI().use('node', function(Y) {
            //Lets declare some variables that we'll be using.
            var ListItem,
            query,
            noTasksMessage = Y.one('#no-incomplete-message'),
            submitBtn = Y.one(&quot;#list-item-submit&quot;),
            incompleteItemList = Y.one('#incomplete-items'),
            completeItemList = Y.one('#complete-items'),
            input = Y.one(&quot;#list-input&quot;);
            //The rest of our application code will go below.
            submitBtn.on('click', function(e) {
                /*
                When the submit button is clicked, we want to get the contents of the input and save a new todo list item.
                */
            });
            /*
            When a &lt;li&gt; is clicked, we want to save that item as being complete. We use 'delegate' here instead of 'on' so that we only create one event listener instead of one for each checkbox.
            */
            incompleteItemList.delegate('click', function(e) {
            }, 'li');
            /* We also want to get the 10 most recent incomplete tasks and add them to &lt;div id=&quot;incomplete-items&quot;&gt;&lt;/div&gt; */
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre><p>The important thing to note in the above code is the inclusion of the Parse JavaScript file, <code>&lt;script src="http://www.parsecdn.com/js/parse-1.0.19.min.js"&gt;&lt;/script&gt;</code>. This file contains the Parse object that we will interact with.</p><h3>Add Classes in the Data Browser</h3><blockquote
class="pullquote"><p>Parse frees you from setting up a server-side stack.</p></blockquote><p>Let&#8217;s get back to Parse. View the Data Browser for EnvatoTodo (it&#8217;s currently empty). The Data Browser is similar to a MySQL database server, but the Parse DB is schema-less. While you can specify columns in the Data Browser, you can actually save any object with simple JSON (not unlike many NoSQL/Document databases). This is an extremely important and useful feature of Parse.</p><p>We&#8217;re going to go ahead and add a &#8220;class&#8221; to the database. Think of a class as a table. The reason it&#8217;s called a class is because you&#8217;ll generally create objects from a certain class and then save that object to the database.</p><p><strong>Disclaimer:</strong> JavaScript does not officially have classes (yet), but it does have the logical equivalent. For the sake of simplicity, I will use the terminology &#8220;class&#8221; in this tutorial.</p><p>Parse has five types of classes.</p><ul><li><strong>User classes</strong> store user-specific information, and Parse provides sugar methods such as <code>signUp()</code>, <code>login()</code>, and more to help with user administration.</li><li><strong>Installation classes</strong> are typically used to send push notifications for mobile apps. Yes, Parse supports push notifications to all clients.</li><li><strong>Role classes</strong> help segregate users into specific roles, controlling access to read/write to other classes. This is called ACL (access control list) within Parse.</li><li><strong>Product classes</strong> store in-app product data.</li><li><strong>Custom classes</strong> are for anything else.</li></ul><p>Let&#8217;s create a custom class called <code>ListItem</code>. Once it&#8217;s created, you&#8217;ll notice it already has four properties. Parse automatically updates the properties of every class that you create. Some classes, such as user classes, may have their own specific properties.</p><p>Our <code>ListItem</code> objects will contain a <code>content</code> property to show what the Todo contains, and an <code>isComplete</code> property to indicate whether the Todo was completed. We could add columns for these properties, but Parse will figure it out from our JSON.</p><h3>Initializing Parse</h3><p>Let&#8217;s go back to <code>index.html</code> to add some code. The first thing we want to do is initialize Parse with our App ID and JavaScript key. These can be found under the Overview tab of your application inside the Data Browser. Add the following line to your JavaScript, replacing <code>APP_ID</code> and <code>JS_KEY</code> with the appropriate values:</p><pre class="brush: jscript; title: ; notranslate">
Parse.initialize(APP_ID, JS_KEY);
</pre><h3>Saving Todos</h3><p>Let&#8217;s start adding functionality to our application. We&#8217;ll first save a To-do list item when the user clicks the add button. The following code is all we need for this functionality:</p><pre class="brush: jscript; title: ; notranslate">
submitBtn.on('click', function(e) {
    //Extend the native Parse.Object class.
    var ListItem = Parse.Object.extend(&quot;ListItem&quot;);
    //Instantiate an object of the ListItem class
    var listItem = new ListItem();
    //listItem is now the object that we want to save, so we assign the properties that we want on it.
    listItem.set(&quot;content&quot;, text);
    listItem.set(&quot;isComplete&quot;, false);
    //We call the save method, and pass in success and failure callback functions.
    listItem.save(null, {
        success: function(item) {
        //Success Callback
    },
    error: function(gameScore, error) {
        //Failure Callback
    }
    });
});
</pre><p>Interacting with the database is extremely painless! Every custom class in Parse inherits from <code>Parse.Object</code>; therefore, <code>ListItem</code> is a subclass. The string argument <code>"ListItem"</code> tells Parse that this class correlates to the ListItem table that we created. Then we create a new <code>ListItem</code> object, set its properties, and call <code>save()</code>.</p><h3>Showing Items</h3><p>In order to display a list of To-do items, we&#8217;ll use the <a
href="https://parse.com/docs/js_guide">Parse JavaScript API</a> to query the ten most recently saved items, and list those below the app. This will give you an idea as to how queries work in Parse.</p><pre class="brush: jscript; title: ; notranslate">
//Once again, we extend the Parse.Object class to make the ListItem class
ListItem = Parse.Object.extend(&quot;ListItem&quot;);
//This time, we use Parse.Query to generate a new query, specifically querying the ListItem table.
query = new Parse.Query(ListItem);
//We set constraints on the query.
query.equalTo('isComplete', false)
query.limit = 10;
query.descending('createdAt');
//We submit the query and pass in callback functions.
query.find({
  success: function(results) {
    //Success callback
  },
  error: function(error) {
    //Error Callback
  }
});
</pre><p>Once again, it&#8217;s fairly simple and easy to read. The <code>Parse.Query()</code> method is quite powerful. Here, we perform a fairly basic query, but Parse queries can be complex as well. You can query for specific regular expressions, perform relational queries, and many more. Be sure to visit the <a
href="https://parse.com/docs/js_guide#queries">Query Documentation</a> for more examples and code snippets.</p><h3>Putting it all together</h3><p>The next thing we need to add is the ability to mark a to-do item as complete when checking the item&#8217;s checkbox. Each checkbox has a unique <code>id</code> associated with the Parse object that it represents. Therefore, when a checkbox is clicked, we need to:</p><ul><li>Get the id.</li><li>Query for a Parse object with that id.</li><li>Get the returned Parse object, and update it&#8217;s <code>isComplete</code> property as <code>true</code>.</li><li>Save the updated object.</li><li>Remove it from the displayed list.</li></ul><p>Here&#8217;s what that code looks like:</p><pre class="brush: jscript; title: ; notranslate">
incompleteItemList.delegate('click', function (e) {
    //keep a reference to this
    var self = this;
    //create a Parse query object
    var query = new Parse.Query(ListItem);
    //The query.get() method requires the objectId as its first argument. It returns the object with that id.
    query.get(self.one('input').get('id'), {
      success: function(item) {
        //Once the object is returned, we update its property and save it.
        item.set('isComplete', true);
            item.save();
            //Since the item is no longer incomplete, we remove it from the list.
            self.remove();
            //If there's nothing in the list, show a message saying the list is empty.
            if (incompleteItemList.all('li').size() &gt;= 1) {
                noTasksMessage.removeClass('hidden');
            }
      },
      error: function(object, error) {
            alert(&quot;Error when updating todo item: &quot; + error.code + &quot; &quot; + error.message);
      }
    });
}, 'li');
</pre><p>In this snippet, we query for an individual element with a specific <code>id</code>, update it, and save it. Then we remove it from the list with <code>self.remove()</code>.</p><p>In Parse, updating objects is very similar to saving objects&#8211;we call <code>save()</code> in both cases. Parse figures out whether it&#8217;s an existing (dirty) object, or an entirely new object and performs the appropriate action.</p><h3>Complete Source Code</h3><p>With that, we&#8217;re good to go! Pretty easy, eh? Download the attached ZIP file and open <code>index.html</code> to view the entire source code.</p><hr
/><h2>Other Features</h2><p>In this tutorial, we primarily looked at Parse from a web development point-of-view. However, the service was originally started with mobile developers in mind. Parse has a very thorough SDK for Android and iOS, and it supports features such as push notifications to all users of your mobile app.</p><blockquote><p>Some other big features that we didn&#8217;t cover in this tutorial involve users, roles, and storing relational information.</p></blockquote><p>Parse makes it relatively simple to create users, and assign different roles to them. For example, in a learning management system, you may have &#8220;Teachers&#8221;, &#8220;Students&#8221;, and &#8220;Administrators&#8221;. By assigning roles, you can specify which type of user has access to certain Parse objects.</p><hr
/><h2>What about Security?</h2><blockquote
class="pullquote"><p>A lot of new technologies leverage the cloud&#8230;</p></blockquote><p>As a developer, I like that Parse takes care of a lot of the security concerns that I have. As it states on the website, the Parse SDKs are designed &#8220;so that you typically don&#8217;t need to worry about how data is saved.&#8221; There&#8217;s still the issue of users having access to information that they shouldn&#8217;t be able to. To address this concern, Parse offers Object-level and Class-level permissions.</p><p>Object-level permissions allow a developer to specify an array of object IDs that have access to read and/or write the object. Class-level permissions allow a developer to specify what aspects of a Parse class can be manipulated from the API. The following operations can be allowed or denied on a per-class basis: Get, Find, Update, Create, Delete, and Add Fields.</p><hr
/><h2>Pros and Cons</h2><p>I want to stress is that Parse is not suitable for every type of project. Although the free plan is very generous, Parse is a paid service. It can get <a
href="https://parse.com/plans">expensive</a> if you go above certain limits. Luckily, the pricing model is very transparent, and you should be able to figure out how much your app can cost. Generally speaking, I use it for smaller projects where I can anticipate a certain cap when it comes to the number of API requests that I make. I have yet to try Parse for a large project.</p><blockquote><p>One common issue with a service such as Parse is the lock-in effect.</p></blockquote><p>If you use Parse for a small project that suddenly takes off, it can be difficult to move to a difference service or platform. As you can imagine, replacing Parse with your own back-end would entail a significant amount of refactoring. This doesn&#8217;t mean you shouldn&#8217;t use Parse, but it&#8217;s something to keep in mind.</p><hr
/><h2>Concluding Remarks</h2><p>In this tutorial, we looked at how we can use Parse to create a relatively simple web application. I&#8217;ve used this service for a number of projects for various clients, and I find the Parse team to be very helpful when issues arise. I encourage you give the service a try, and make your own decision!</p><p>Disclosure: I have no relationship with Parse or any of its employees. I&#8217;m just a developer who uses their service, and I find it to be a helpful addition to my development workflow.</p>
<p><a href="http://feedads.g.doubleclick.net/~a/C0JgV_PYrjpQ-z4YjmX3Tdi08-U/0/da"><img src="http://feedads.g.doubleclick.net/~a/C0JgV_PYrjpQ-z4YjmX3Tdi08-U/0/di" border="0" ismap="true"></img></a><br/>
<a href="http://feedads.g.doubleclick.net/~a/C0JgV_PYrjpQ-z4YjmX3Tdi08-U/1/da"><img src="http://feedads.g.doubleclick.net/~a/C0JgV_PYrjpQ-z4YjmX3Tdi08-U/1/di" border="0" ismap="true"></img></a></p><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/nettuts?a=E_IivGJ37A4:cK2X1Hva7bQ:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/nettuts?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=E_IivGJ37A4:cK2X1Hva7bQ:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/nettuts?i=E_IivGJ37A4:cK2X1Hva7bQ:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=E_IivGJ37A4:cK2X1Hva7bQ:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/nettuts?i=E_IivGJ37A4:cK2X1Hva7bQ:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=E_IivGJ37A4:cK2X1Hva7bQ:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/nettuts?i=E_IivGJ37A4:cK2X1Hva7bQ:gIN9vFwOqvQ" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/nettuts?a=E_IivGJ37A4:cK2X1Hva7bQ:TzevzKxY174"><img src="http://feeds.feedburner.com/~ff/nettuts?d=TzevzKxY174" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/nettuts/~4/E_IivGJ37A4" height="1" width="1"/>";s:14:"date_timestamp";i:1352826025;}}s:7:"channel";a:8:{s:5:"title";s:8:"Nettuts+";s:4:"link";s:23:"http://net.tutsplus.com";s:11:"description";s:34:"Web Development & Design Tutorials";s:13:"lastbuilddate";s:31:"Tue, 27 Nov 2012 19:39:44 +0000";s:2:"sy";a:2:{s:12:"updateperiod";s:6:"hourly";s:15:"updatefrequency";s:1:"1";}s:9:"generator";s:29:"http://wordpress.org/?v=3.4.1";s:10:"feedburner";a:2:{s:14:"emailserviceid";s:7:"nettuts";s:18:"feedburnerhostname";s:28:"http://feedburner.google.com";}s:7:"tagline";s:34:"Web Development & Design Tutorials";}s:9:"textinput";a:0:{}s:5:"image";a:3:{s:4:"link";s:18:"http://nettuts.com";s:3:"url";s:53:"http://envato.s3.amazonaws.com/rss_images/nettuts.jpg";s:5:"title";s:7:"NETTUTS";}s:9:"feed_type";s:3:"RSS";s:12:"feed_version";s:3:"2.0";s:8:"encoding";s:5:"UTF-8";s:16:"_source_encoding";s:0:"";s:5:"ERROR";s:0:"";s:7:"WARNING";s:0:"";s:19:"_CONTENT_CONSTRUCTS";a:6:{i:0;s:7:"content";i:1;s:7:"summary";i:2;s:4:"info";i:3;s:5:"title";i:4;s:7:"tagline";i:5;s:9:"copyright";}s:16:"_KNOWN_ENCODINGS";a:3:{i:0;s:5:"UTF-8";i:1;s:8:"US-ASCII";i:2;s:10:"ISO-8859-1";}s:5:"stack";a:0:{}s:9:"inchannel";b:0;s:6:"initem";b:0;s:9:"incontent";b:0;s:11:"intextinput";b:0;s:7:"inimage";b:0;s:17:"current_namespace";b:0;s:4:"etag";s:29:"+ef+ZVPaTFMZ2kZVY1avTFxftI4
";s:13:"last_modified";s:31:"Tue, 27 Nov 2012 20:50:23 GMT
";}