<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>User InExperience</title>
	
	<link>http://userinexperience.com</link>
	<description>Brandon Satrom on Development, Design and Architecture</description>
	<lastBuildDate>Tue, 15 May 2012 00:55:34 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
	<div id="fb-root" />
					<script type="text/javascript">
						window.fbAsyncInit = function()
						{
							FB.init({appId: null, status: true, cookie: true, xfbml: true});
						};
						(function()
						{
							var e = document.createElement('script'); e.async = true;
							e.src = document.location.protocol + '//connect.facebook.net/en_US/all.js';
							document.getElementById('fb-root').appendChild(e);
						}());
					</script>	
						<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/userinexperience/tYGT" /><feedburner:info uri="userinexperience/tygt" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><geo:lat>38.808934</geo:lat><geo:long>-104.738238</geo:long><creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/2.0/</creativeCommons:license><image><link>http://www.feedburner.com</link><url>http://www.feedburner.com/fb/images/pub/fb_pwrd.gif</url><title>This Feed Powered by FeedBurner.com</title></image><feedburner:emailServiceId>userinexperience/tYGT</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><feedburner:browserFriendly>This is an XML content feed. It is intended to be viewed in a newsreader or syndicated to another site, subject to copyright and fair use.</feedburner:browserFriendly><item>
		<title>What is Metro, really?</title>
		<link>http://feedproxy.google.com/~r/userinexperience/tYGT/~3/0TA0FtZ93pw/</link>
		<comments>http://userinexperience.com/?p=827#comments</comments>
		<pubDate>Thu, 05 Apr 2012 18:20:37 +0000</pubDate>
		<dc:creator>bsatrom</dc:creator>
				<category><![CDATA[design]]></category>
		<category><![CDATA[apps]]></category>
		<category><![CDATA[metro]]></category>
		<category><![CDATA[ux]]></category>
		<category><![CDATA[win8]]></category>

		<guid isPermaLink="false">http://userinexperience.com/?p=827</guid>
		<description>&lt;p&gt;There is a certain beauty in man-made things. In some ways, that beauty cannot match the extant world. In others, that beauty is unparalleled because it exhibits the best qualities man and woman are able to achieve with their own hands.&lt;/p&gt; &lt;p&gt;Art and Architecture are oft-cited examples, and we recognize this, conveying social and financial [...]</description>
			<content:encoded><![CDATA[<p>There is a certain beauty in man-made things. In some ways, that beauty cannot match the extant world. In others, that beauty is unparalleled because it exhibits the best qualities man and woman are able to achieve with their own hands.</p>
<p>Art and Architecture are oft-cited examples, and we recognize this, conveying social and financial reward upon those creations that best exhibit the creative spirit&#8211;or even boundless will&#8211;of humanity.</p>
<p>There is a simpler, yet more pervasive proof in the beauty of man-made things: the beauty of comfort and familiarity. The beauty in feeling like you belong, no matter where you may find yourself. This beauty is all the more meaningful to us because it speaks to the deep-seated social needs that <strong>all</strong> of us possess. It often feels less essential because it is so subtle, and also because we&#8217;re only acutely aware of this need when it is not being met.</p>
<p>When unfamiliarity encroaches, we cling to any shred of familiarity like an anchor&#8211;our only hope from being swept away by the waves of confusion and insecurity.</p>
<p>Imagine yourself in a foreign airport or the transit station of an unfamiliar city for the first time. Now suppose that you just stepped off your train or plane and you have a limited amount of time to get from your gate to the next one. Where do you go? How do you find information? What thoughts and emotions do you experience at even the mention of such a task?</p>
<p>If you have a first-hand memory of such a place and experience, recalling that memory might even evoke a physical response: Dilated pupils; an increased heart-rate; clammy hands; shortness of breath. Stress. Anxiety.</p>
<p>The unfamiliarity of it all evokes a need for familiarity, so what do you do? If you are traveling with co-workers, friends or loved-ones, your stress is lessened, but the task remains. What did you do?</p>
<p>You look for familiarity; for anchoring clues. Signs, numbers, letters, text. Anything to help you find your way. A sign with the text &#8220;A Gates&#8221; and an arrow leading in a specific direction may provide instant relief. A bank of monitors might do the same. Perhaps all you require is the appearance of a male or female block figure, pointing to the closest restroom. Whatever it may be, you would look for, and gravitate to, anything familiar that helps you accomplish the most important task at hand. And once found, those familiar things would anchor you, and provide comfort.</p>
<p>There is beauty in this! When numbers and letters and symbols can anchor us to a deeper reality and point us home, there is sublime beauty that almost nothing else can match.</p>
<p>This, then, is Metro: creating experiences that anchor us to reality, even in the face of the unfamiliar. Further, these experiences do more than simply try to transpose and replicate our comfort from one medium to another. I don&#8217;t need the subway signs in Chicago to look exactly like those in Manhattan or Munich. As long as there is <strong>just enough</strong> present to evoke familiarity, I am comfortable. Better still, I don&#8217;t need the sign for the men&#8217;s restroom in Beijing to be a life-like photograph of a six-foot tall white male. To loosely paraphrase Scott McCloud in &#8220;<a href="http://scottmccloud.com/2-print/1-uc/index.html">Understanding Comics</a>,&#8221; iconography is powerful not just because it is abstract, but because its abstract nature makes it identifiable, and we connect best with that which we identify. A stick figure is sufficient because I see myself in it, and that provides familiarity and comfort.</p>
<p>Metro is not Windows. Or Windows Phone. It is not Live Tiles, black backgrounds, Segoe UI or boxes with straight corners. It&#8217;s not HTML5, CSS or JavaScript. Metro is not even Microsoft. It can live in the browser or in the desktop. It can even live on an iPad, because it was never <em>really</em> about the platform, at all.</p>
<p>In a time when Metro is increasingly being used to instruct developers to find and delete every &#8216;border-radius&#8217; rule in their CSS, or to follow a design checklist, it&#8217;s important that we remember that Metro&#8211;like every single great design idea conceived since the dawn of humanity&#8211;is about building something that is beautiful for others. It is about delivering something that anchors them in reality and helps them find their way, and it&#8217;s about creating something that is beautiful <em>because</em> it&#8217;s useful and comfortable.</p>
<p>You can&#8217;t <em>code</em> your way to Metro, except perhaps by accident. Even then, what you create will likely seem more artificial than &#8220;digitally authentic.&#8221;</p>
<p>You can&#8217;t even <em>design</em> your way to Metro, and no tutorial, checklist, or book will deliver a &#8220;Metro experience&#8221; simply because you added colorful tiles, fancy page flip effects or a digital representation of a tabletop calendar.</p>
<p>All software is and has always been about the beneficiary of our work, and Metro is no different. Never has there been a checklist or process to unlock what is most beneficial for every case, because the real value lies in the process of discovery.</p>
<p>Once you discover what the human being using your application needs, it is up to you to discover how to best meet that need. Metro is about placing comfort and familiarity on an even footing with utility&#8211;and I am grateful for its popularity for that reason, alone&#8211;but it is only when armed with discovery that one can truly build &#8220;Metro&#8221; experiences.</p>
<p>So, learn Metro. Read the design guides and use the checklists. Watch the videos and think more like a designer, no matter what you are building. Before any of that, though, think about comfort and familiarity, and how your application or site can deliver those basic, human needs better than any other.</p>
<p>Because that&#8217;s what Metro really means.</p>
<div class='wpfblike' ><fb:like href='http://userinexperience.com/?p=827' layout='default' show_faces='true' width='400' action='like' colorscheme='light' send='false' /></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=0TA0FtZ93pw:lLMAKNLNoBo:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?i=0TA0FtZ93pw:lLMAKNLNoBo:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=0TA0FtZ93pw:lLMAKNLNoBo:dnMXMwOfBR0"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?d=dnMXMwOfBR0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=0TA0FtZ93pw:lLMAKNLNoBo:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?i=0TA0FtZ93pw:lLMAKNLNoBo:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/userinexperience/tYGT/~4/0TA0FtZ93pw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://userinexperience.com/?feed=rss2&amp;p=827</wfw:commentRss>
		<slash:comments>18</slash:comments>
		<feedburner:origLink>http://userinexperience.com/?p=827</feedburner:origLink></item>
		<item>
		<title>Farewell Microsoft, Hello…</title>
		<link>http://feedproxy.google.com/~r/userinexperience/tYGT/~3/KcQxRbSjB3Y/</link>
		<comments>http://userinexperience.com/?p=797#comments</comments>
		<pubDate>Thu, 16 Feb 2012 16:00:01 +0000</pubDate>
		<dc:creator>bsatrom</dc:creator>
				<category><![CDATA[career]]></category>
		<category><![CDATA[personal]]></category>
		<category><![CDATA[HTML5]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[kendoui]]></category>
		<category><![CDATA[mobile]]></category>

		<guid isPermaLink="false">http://userinexperience.com/?p=797</guid>
		<description>&lt;p&gt;I&amp;#8217;ve been doing this &amp;#8220;technology&amp;#8221; thing for a number of years now, and each career change I&amp;#8217;ve made has fallen into one of two categories. Either: a) a fortuitous opportunity I could not have envisioned; or, b) a desperate escape from a crumbling situation. The best example of the latter came with my very first [...]</description>
			<content:encoded><![CDATA[<p>I&#8217;ve been doing this &#8220;technology&#8221; thing for a number of years now, and each career change I&#8217;ve made has fallen into one of two categories. Either: a) a fortuitous opportunity I could not have envisioned; or, b) a desperate escape from a crumbling situation. The best example of the latter came with my very first job out of college&#8211;at the trough of the &#8220;dot com bust&#8221;&#8211;when I literally turned in my two-weeks notice at the start of a meeting that had been called by my manager for the purpose of telling me that I&#8211;after two years of surviving all the others&#8211;was a casualty to a round of layoffs. (Sidebar: that company is no longer in existence.)</p>
<p>On the other end of the spectrum are those times where I have made a move from one opportunity to another because of overriding personal, family or career goals. Often, those changes have been spurred on by opportunities that dovetailed nicely with said goals. Once such example was when I chose to leave a job I loved with <a href="http://www.compassion.com">a great non-profit</a> in order to move my family back to Texas. I still miss that place and those people, but we don&#8217;t regret for one minute making the decision to be back in Texas, and close to family (Except when it&#8217;s over 100-degrees, which is every day from May to October).</p>
<p>This is another one of those &#8220;fortuitous opportunity&#8221; times. And with mixed emotions, I&#8217;m announcing that today is my last day at Microsoft.</p>
<p>When I joined Microsoft nearly two years ago as a Developer Evangelist based in Austin, I truly expected that I would be a part of this organization for some time. I&#8217;ve had the great pleasure to spend nearly all of my time focused on the web (ASP.NET MVC, HTML5, CSS and JavaScript, to be specific) and have even had opportunities to participate in Microsoft&#8217;s ever-widening journey into the world of Open Source (A <a href="http://bsatrom.github.com/pinify">few</a> <a href="http://bsatrom.github.com/Knockout.Unobtrusive/">examples</a>). I had the pleasure of working with <a href="http://csell.net">some</a> <a href="http://www.uxarray.com/">amazing</a> <a href="http://jeffblankenburg.com/">individuals</a>, got to meet some industry luminaries, <a href="http://channel9.msdn.com/Events/TechEd/NorthAmerica/2011/DEV343">spoke at Tech Ed to an audience of over 600 people</a>, <a href="http://html5tx.com">organized a few events</a>, <a href="http://msdn.microsoft.com/en-us/magazine/ee532098.aspx?sdmr=BrandonSatrom&amp;sdmi=authors">wrote a crap ton for MSDN Magazine</a>, blogged, created some screencasts and had the privilege working side-by-side with <a href="http://csell.net">an individual</a> I consider a lifelong friend.</p>
<p>But personal concerns conflicted with the goals I had laid out for my career, and personal (namely, family), always wins. From day one, I had made it clear to my manager, his manger and anyone else who would listen that my desire was to move into a Product or Program Management role as a next step in my career at Microsoft. It became clear very quickly, though, that in nearly all cases, such a job required a migration to Redmond. My wife and I had some serious conversations about the matter, and decided that after moving away from Colorado (surely, God&#8217;s Picture Window ™) to return to Texas, we should stay put for a while. As early as last summer, we knew that a move to Redmond (or anywhere) for the next step in my career was out.</p>
<p>At that point, I set myself to focusing on my current role as a Web Evangelist with Microsoft, without worrying about what would come next. After another 3-4 years, I told myself, we&#8217;d think about the future. But &#8220;what was next&#8221; came much sooner than expected when I was presented with an opportunity to step into a role I&#8217;d wanted to tackle, and to do so without the condition I move myself or my family. In &#8220;Godfather&#8221; terms, it was the career offer I couldn&#8217;t refuse. After much consideration, conversation and consternation&#8211;the three &#8220;Cs&#8221; of any important decision&#8211;my wife and I decided that the change was a good one.</p>
<p><img title="Kendoui.png" src="http://userinexperience.com/wp-content/uploads/Kendoui.png" alt="Kendo UI" width="200" height="200" border="0" /></p>
<p>And so, on Monday, I begin a new chapter, this time as Product Manager for <a href="http://kendoui.com">Kendo UI</a> (http://kendoui.com) at <a href="http://telerik.com">Telerik</a>. I&#8217;ve used Telerik products for years, and I&#8217;ve always appreciated the quality and breadth of their tools. Late last year, they jumped into the HTML5 and Mobile space with Kendo UI, a suite of tools for building HTML5 and Mobile applications with JavaScript and CSS. I&#8217;ve been impressed from day one, and I&#8217;m really excited to join the team and help with driving this great product forward. I&#8217;m looking forward to working with brilliant folks like <a href="http://twitter.com/toddanglin">Todd Anglin</a> and <a href="http://twitter.com/burkeholland">Burke Holland</a> (<a href="http://a.shinynew.me">Blog</a>), as well as a few other former-Microsofties like <a href="http://sellsbrothers.com/">Chris Sells</a>, <a href="http://sellsbrothers.com/">Doug Seven</a> and <a href="http://bristowe.com/">John Bristowe</a>. It&#8217;s an exiting time to be a part of the open web, and an exciting time to join Telerik. I feel privileged to be able to do both.</p>
<p>I&#8217;m not going to lie to you and pretend that life at Microsoft was without its share of frustrations, but I think we all know that no organization populated by people is without its share of annoyances and daily struggles. In spite of any of those those, I want to be clear&#8211;especially in the face of so much negativity swirling around Microsoft&#8211;that I am leaving on the best of terms, especially with those individuals I had the pleasure of working with and for over the last two years. Those of you who know me personally know that I&#8217;m nobody&#8217;s fanboy. And even though I will continue to be open with my opinions in the future, I have the utmost respect for the brilliant people of Microsoft and believe that they collectively deserve more credit for attempting to respond to a shifting technology landscape then they often receive.</p>
<p>Here&#8217;s what this all means from a community perspective: though I am changing employers and the eventual makeup of my day-to-day job, I expect to remain involved with community: in Austin, online and beyond. In the short term, I&#8217;ll be at <a href="http://sxsw.com">SxSW</a> and <a href="http://codepalousa.com">CodePaLOUsa</a> next month, and I hope to see you at one (or both) of those events as well. Longer-term, you can expect that I will continue organizing the <a href="http://html5tx.com">HTML5.tx conference</a>. I had too much fun doing it last year not to. I&#8217;ll also probably find my way out for events every once and again. As always, I continue blogging here&#8211;never often enough&#8211;as I have since December of 2004, and I&#8217;ll be on Twitter&#8211;more often than I should&#8211;at <a href="http://twitter.com/brandonsatrom">http://twitter.com/brandonsatrom</a>. I&#8217;m also working on a book, but more on that one later.</p>
<p>In the meantime, thanks for following-along here for the Microsoft phase of my journey. Hope you&#8217;ll stick around for the next one!</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<div class='wpfblike' ><fb:like href='http://userinexperience.com/?p=797' layout='default' show_faces='true' width='400' action='like' colorscheme='light' send='false' /></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=KcQxRbSjB3Y:a9Xu3TcGXuo:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?i=KcQxRbSjB3Y:a9Xu3TcGXuo:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=KcQxRbSjB3Y:a9Xu3TcGXuo:dnMXMwOfBR0"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?d=dnMXMwOfBR0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=KcQxRbSjB3Y:a9Xu3TcGXuo:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?i=KcQxRbSjB3Y:a9Xu3TcGXuo:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/userinexperience/tYGT/~4/KcQxRbSjB3Y" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://userinexperience.com/?feed=rss2&amp;p=797</wfw:commentRss>
		<slash:comments>19</slash:comments>
		<feedburner:origLink>http://userinexperience.com/?p=797</feedburner:origLink></item>
		<item>
		<title>CoffeeScript Object Comprehensions (Excerpt from CoffeeScript in Action)</title>
		<link>http://feedproxy.google.com/~r/userinexperience/tYGT/~3/Zh7LnA1SU8M/</link>
		<comments>http://userinexperience.com/?p=753#comments</comments>
		<pubDate>Tue, 24 Jan 2012 02:53:42 +0000</pubDate>
		<dc:creator>bsatrom</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[book]]></category>
		<category><![CDATA[CoffeeScript]]></category>
		<category><![CDATA[excerpt]]></category>

		<guid isPermaLink="false">http://userinexperience.com/?p=753</guid>
		<description>&lt;p&gt;&lt;a href="http://userinexperience.com/?attachment_id=754" rel="attachment wp-att-754"&gt;&lt;/a&gt;   &lt;a href="http://www.manning.com/lee/"&gt;CoffeeScript in Action&lt;/a&gt;&lt;/p&gt; &lt;p&gt;   By Patrick Lee&lt;/p&gt; &lt;p&gt;CoffeeScript Object Comprehensions&lt;/p&gt; &lt;p&gt;This article is based on CoffeeScript in Action, to be published Summer 2012. It is being reproduced here by permission from &lt;a href="http://www.manning.com"&gt;Manning Publications&lt;/a&gt;. Manning early access books and ebooks are sold exclusively through Manning. Visit the book&amp;#8217;s page for [...]</description>
			<content:encoded><![CDATA[<div>
<div>
<div>
<div>
<p><a href="http://userinexperience.com/?attachment_id=754" rel="attachment wp-att-754"><img class="alignleft size-full wp-image-754" title="lee_cover150" src="http://userinexperience.com/wp-content/uploads/lee_cover150.jpg" alt="" width="150" height="188" /></a>   <a href="http://www.manning.com/lee/">CoffeeScript in Action</a></p>
</div>
</div>
</div>
<div>
<div>
<div>
<p>   By Patrick Lee</p>
<p><strong>CoffeeScript Object Comprehensions</strong></p>
<p><em>This article is based on CoffeeScript in Action, to be published Summer 2012. It is being reproduced here by permission from <a href="http://www.manning.com">Manning Publications</a>. Manning early access books and ebooks are sold exclusively through Manning. Visit the book&#8217;s page for more information.</em></p>
<p>To add up all the view counts for every property on the views object, you need to use a comprehension. In this article, based on chapter 4 of <a href="http://www.manning.com/lee">CoffeeScript in Action</a>, you will learn how to use comprehensions to transform the properties and values of an object into other values.</p>
<hr />
<p>Imagine you have a website with two pages. You want to track how many views each page on your website gets and the total number of views for all pages. Your website pages live on specific URLs but are referred to simply as the pages ren and stimpy for the sake of clarity. If the ren page has so far received 30 views and the stimpy page 10 views then that can be represented as:</p>
<pre>   views =
     'ren': 30
     'stimpy': 10</pre>
<p>&nbsp;<br />
Storing a property on the object is by assignment, so a count can be incremented using:</p>
<pre>   views.ren = views.ren + 1</pre>
<p>&nbsp;<br />
How about adding up all the view counts for every property on the views object though? How is that done? By using a comprehension. In this article, you will learn how to use comprehensions to transform the properties and values of an object into other values.</p>
<p><strong>Object comprehensions</strong></p>
<p>Comprehensions allow you to deal the elements of an array without having to write a bunch of boilerplate and iterate manually through every single thing in the array one by one, again and again and again. Check it out:</p>
<pre>   number + 1 for number in [1,2,3,4,5]
   # [2,3,4,5,6]</pre>
<p>&nbsp;<br />
Object comprehensions in CoffeeScript work similarly to how array comprehensions work. They also have a similar basic format to array comprehensions except they use the word <em>of</em> instead of <em>in</em>:</p>
<pre>    expression for property of object</pre>
<p>&nbsp;<br />
What does it do? Listing 1 is a side-by-side comparison with the JavaScript’s <em>for&#8230;in</em> loop that CoffeeScript replaces with object comprehensions:</p>
<p>&nbsp;</p>
<p><em><strong>Listing 1 Comprehension compared to for&#8230;in loop</strong></em></p>
<table>
<tr>
<th>CoffeeScript</th>
<th>JavaScript</th>
</tr>
<tr>
<td style="text-align: left;">
<pre>movie =
  title: 'From Dusk till Dawn'
  released: '1996'
  director: 'Robert Rodriguez'
  writer 'Quentin Tarantino'</pre>
<pre>for property of movie
  console.log property</pre>
</td>
<td style="text-align: left;">
<pre>var movie = {
  title: 'From Dusk till Dawn',
  released: '1996',
  director: 'Robert Rodriguez',
  writer: 'Quentin Tarantino'
} </pre>
<pre>for (var property in movie) {
} console.log(property);</pre>
</td>
</tr>
</table>
<div>In the basic case, the JavaScript version is fine. However, the JavaScript version uses statements. In CoffeeScript, you should prefer expressions. To see the power of expressions in this specific case compare getting an array of property names from the object in listing 2.</div>
</div>
<div>
<div>
<div>
<p>&nbsp;</p>
<p><em><strong>Listing 2 Comprehension as expression</strong></em></p>
<table>
<tr>
<th>CoffeeScript</th>
<th>JavaScript</th>
</tr>
<tr>
<td style="text-align: left;">
<pre>properties = (prop for prop of movie)</pre>
</td>
<td style="text-align: left;">
<pre>var properties = {};
for (var prop in movie) {
   properties.push(p);
}</pre>
</td>
</tr>
</table>
<p>The JavaScript version uses multiple statements and has to micromanage the state of the variables properties and p. The CoffeeScript version does not.</p>
<p><strong>Comprehending properties</strong></p>
<p>The property names of an object can be returned as an array using a comprehension:</p>
<pre>   name for name of {bob: 152, john: 139, tracy: 209}  # ['bob', 'john', 'tracy']</pre>
<p>&nbsp;<br />
Imagine now that your website has four pages named by the path to those pages. The object below shows an example:</p>
<pre>   views =

      '/reviews/pool-of-radiance': 121

      '/reviews/summer-games': 90

      '/reviews/wasteland': 139

      '/reviews/impossible-mission': 76</pre>
<p>&nbsp;</p>
<p>A list of pages from this object is obtained using the following comprehension:</p>
<pre>   url for url of views</pre>
<p>&nbsp;<br />
Resulting in an array containing the page names:</p>
<pre>   [ '/reviews/pool-of-radiance'

     '/reviews/summer-games'

     '/reviews/wasteland'

     '/reviews/impossible-mission' ]</pre>
<p>&nbsp;</p>
<p><strong>Comprehending values</strong></p>
<p>To get the property values from an object instead of the property names, use a slightly different comprehension format:</p>
<pre>   value for property, value of object</pre>
<p>&nbsp;<br />
For example,</p>
<pre>   score for name, score of {bob: 152, john: 139, tracy: 209} # [152, 139, 209]</pre>
<p>&nbsp;<br />
The number of views for each page is obtained using a comprehension</p>
<pre>   count for url, count of views</pre>
<p>&nbsp;<br />
For the four pages described earlier results in an array containing the page views for those pages:</p>
<pre>   [ 121, 90, 139, 76 ]</pre>
<p>&nbsp;<br />
<strong>Alternative format</strong></p>
<p>In the <em>total</em> function the comprehension looks like</p>
<pre>   for property, value of object
      expression</pre>
<p>&nbsp;<br />
This works the same as the format</p>
<pre>expression for property, value of object</pre>
<p>&nbsp;<br />
The expression will be evaluated for each property in the object. The comprehension can be used to collect and sum the view count for all of the pages:</p>
<p><em><strong>Example</strong></em></p>
<table>
<tr>
<th>CoffeeScript</th>
<th>JavaScript</th>
</tr>
<tr>
<td style="text-align: left;">
<pre>properties = (prop for prop of movie)</pre>
</td>
<td style="text-align: left;">
<pre>var properties = [];
for (var prop in movie) {
   properties.push(prop);
}
			</pre>
</td>
</tr>
</table>
<p>To keep track of how many views each page gets, you will need a function to increment the value stored against an individual page. To get the total number of views for all pages, you will need a function that sums all of the values of the object. Listing 3 is a first implementation of this program. A detailed discussion follows the listing:</p>
<p><strong>Listing 3 Page views</strong></p>
<p>views = {} #A</p>
<pre>views_increment = (key) -&gt;                    #B
  views[key] ?= 0                             #B
  views[key] = views[key] + 1                 #B
total = -&gt;</pre>
<pre>  sum = 0                                     #C</pre>
<pre>  for own url, count of views                 #C</pre>
<pre>     sum = sum + count                        #C</pre>
<pre>  sum                                         #C</pre>
<p><strong>#A The views object, created ex-nihilo</strong><br />
<strong> #B An increment helper function</strong><br />
<strong> #C A total function to add up the page views</strong></p>
<div>
<div>
<blockquote><p><em>Reduce!</em></p>
<p>If you were expecting the sum to be done inside the total function with a reduce on the array, then rest assured that you can and should use Array.reduce in CoffeScript.</p></blockquote>
</div>
</div>
</div>
<div> <strong>Getting started</strong></div>
<p>To begin, create a views object ex nihilo:</p>
<pre>   views = {}</pre>
<p>&nbsp;<br />
<strong>Dealing with undefined properties</strong></p>
<p>The views object does not yet have any properties. If there is a page called donatello that receives a view, how do you increment a donatello property that does not exist? If the views object does not have a donatello property, then this must be the first view to the page donatello and so the value should be set to 1. The existential operator</p>
<p>can be used to determine if a property is defined:</p>
<pre>   if !views['donatello']?
     views['donatello'] = 1</pre>
<p>&nbsp;<br />
This is a common pattern, so CoffeeScript has a shorter version of it called existential assignment. Put an existential operator in front of the assignment operator:</p>
<pre>   views['donatello'] ?= 0</pre>
<p>&nbsp;<br />
You will notice that the views_increment function takes the name of the property as the argument key, which it</p>
<p>uses as the property name. The specific case of donatello is then generalized: </p>
<pre>views[key] =? 0</pre>
<p>&nbsp;</p>
<p><strong>Updating values</strong></p>
<p>Once the views object has a property, the value can be incremented:</p>
<pre>   views[key] = views[key] + 1</pre>
<p>&nbsp;<br />
<strong>Getting the total</strong></p>
<p>To compute the total number of views for all pages, you can now use a comprehension on the views object: </p>
<pre>sum = 0
for own url, count of views
   sum = sum + count</pre>
<p>&nbsp;<br />
<strong>Own properties</strong></p>
<p>The total function adds an own to the comprehension, immediately after the for keyword: for own url, count of views</p>
<p>Objects can get properties that were not defined directly on them. In this case, it was important not to include any properties not defined directly on the object. Properties of an object that are not defined on the object come from prototypes.</p>
</div>
</div>
<div>
<div>
<div>
<blockquote><p><em><strong>TIP</strong></em></p>
<p><em>If you are using an object as a key-value store, always use own inside comprehensions on that object.</em></p></blockquote>
<p><strong>Summary</strong></p>
<p>Considering that objects as key-value stores provide code-as-data for CoffeeScript, you would expect an equally convenient way to do things with that data. Comprehensions provide dedicated syntax to do that. In this article, you learned how to write comprehensions for objects.</p>
</div>
</div>
</div>
<div class='wpfblike' ><fb:like href='http://userinexperience.com/?p=753' layout='default' show_faces='true' width='400' action='like' colorscheme='light' send='false' /></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=Zh7LnA1SU8M:hGXsd6AAYdQ:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?i=Zh7LnA1SU8M:hGXsd6AAYdQ:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=Zh7LnA1SU8M:hGXsd6AAYdQ:dnMXMwOfBR0"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?d=dnMXMwOfBR0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=Zh7LnA1SU8M:hGXsd6AAYdQ:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?i=Zh7LnA1SU8M:hGXsd6AAYdQ:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/userinexperience/tYGT/~4/Zh7LnA1SU8M" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://userinexperience.com/?feed=rss2&amp;p=753</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://userinexperience.com/?p=753</feedburner:origLink></item>
		<item>
		<title>CoffeeScript is for Closers</title>
		<link>http://feedproxy.google.com/~r/userinexperience/tYGT/~3/QVESqU9bNQQ/</link>
		<comments>http://userinexperience.com/?p=732#comments</comments>
		<pubDate>Thu, 08 Dec 2011 14:08:03 +0000</pubDate>
		<dc:creator>bsatrom</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[speaking]]></category>
		<category><![CDATA[CoffeeScript]]></category>
		<category><![CDATA[conferences]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://userinexperience.com/?p=732</guid>
		<description>&lt;p&gt;On November 3rd, I had the opportunity to give a talk on CoffeeScript at &lt;a href="http://reddirtjs.com"&gt;RedDirt.js&lt;/a&gt; in Oklahoma City. Some family circumstances kept me from being able to attend the event in person at the last minute&amp;#8211;and it looks like I missed some awesome talks&amp;#8211;but I was able to pre-record my session and provide that [...]</description>
			<content:encoded><![CDATA[<p>On November 3rd, I had the opportunity to give a talk on CoffeeScript at <a href="http://reddirtjs.com">RedDirt.js</a> in Oklahoma City. Some family circumstances kept me from being able to attend the event in person at the last minute&#8211;and it looks like I missed some awesome talks&#8211;but I was able to pre-record my session and provide that to the organizers for playback on the day of the conference. From what I heard, the session was pretty well received, so I’ve asked the organizers of RedDirt.js if I could upload the recording and make it available online.</p>
<p>Here it is, my talk on CoffeeScript from RedDirt.js, titled &#8220;CoffeeScript is for Closers.&#8221; Click on the embedded player below to watch the video (40 min), or click <a href="http://vimeo.com/33246634">here to view it on Vimeo</a>.</p>
<p><object width="400" height="225" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="src" value="http://vimeo.com/moogaloop.swf?clip_id=33246634&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=00adef&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" /><embed width="400" height="225" type="application/x-shockwave-flash" src="http://vimeo.com/moogaloop.swf?clip_id=33246634&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=00adef&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" allowfullscreen="true" allowscriptaccess="always" /></object></p>
<p><a href="http://vimeo.com/33246634">CoffeeScript is for Closers</a> from <a href="http://vimeo.com/user9546734">Brandon Satrom</a> on <a href="http://vimeo.com">Vimeo</a>.</p>
<p>Here are the links I shared at the end of the talk:</p>
<ul>
<li><a href="http://bit.ly/pLWIMf">Slides</a></li>
<li><a href="http://bit.ly/nfWYwn">CoffeeScript Website</a></li>
<li><a href="http://bit.ly/qdAXfn">CoffeeScript Annotated Source</a></li>
<li><a href="http://bit.ly/o1K6bL">CoffeeScript Koans</a></li>
<li><a href="http://autotelicum.github.com/Smooth-CoffeeScript/">Smooth CoffeeScript Book</a></li>
<li><a href="http://bit.ly/o9KieZ">Jeremy &amp; Brenden @ JSConf 2011</a></li>
<li><a href="http://bit.ly/mQkdtp">&#8220;Harmony of my Dreams&#8221; by Brendan Eich</a></li>
</ul>
<p>I would love to hear what you think, so let me know in the comments, below.</p>
<div class='wpfblike' ><fb:like href='http://userinexperience.com/?p=732' layout='default' show_faces='true' width='400' action='like' colorscheme='light' send='false' /></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=QVESqU9bNQQ:j_4Q6SnzcyQ:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?i=QVESqU9bNQQ:j_4Q6SnzcyQ:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=QVESqU9bNQQ:j_4Q6SnzcyQ:dnMXMwOfBR0"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?d=dnMXMwOfBR0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=QVESqU9bNQQ:j_4Q6SnzcyQ:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?i=QVESqU9bNQQ:j_4Q6SnzcyQ:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/userinexperience/tYGT/~4/QVESqU9bNQQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://userinexperience.com/?feed=rss2&amp;p=732</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://userinexperience.com/?p=732</feedburner:origLink></item>
		<item>
		<title>Automated Testing of Standard Output in Node.js</title>
		<link>http://feedproxy.google.com/~r/userinexperience/tYGT/~3/eiRejlxg3aM/</link>
		<comments>http://userinexperience.com/?p=714#comments</comments>
		<pubDate>Wed, 09 Nov 2011 08:00:46 +0000</pubDate>
		<dc:creator>bsatrom</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[BDD]]></category>
		<category><![CDATA[CoffeeScript]]></category>
		<category><![CDATA[jasmine]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[node.js]]></category>

		<guid isPermaLink="false">http://userinexperience.com/?p=714</guid>
		<description>&lt;p&gt;Summary: Many Node.js Applications rely heavily on Standard Output (stdout) like console.log, util.log, etc., for reporting application state, events and errors. By leveraging the power of JavaScript and a simple hook module, you can write unit tests that verify your application output.&lt;/p&gt; &lt;p&gt;Over the last several months, I’ve been spending a lot of time in [...]</description>
			<content:encoded><![CDATA[<p><strong>Summary</strong>: <em>Many Node.js Applications rely heavily on Standard Output (stdout) like console.log, util.log, etc., for reporting application state, events and errors. By leveraging the power of JavaScript and a simple hook module, you can write unit tests that verify your application output.</em></p>
<p>Over the last several months, I’ve been spending a lot of time in <a href="http://nodejs.org/">Node.js</a>. It started with my <a href="http://bsatrom.github.com/Knockout.Unobtrusive/">Knockout.Unobtrusive</a> and <a href="http://bsatrom.github.com/pinify/">Pinify</a> plugins, which I ported to <a href="http://coffeescript.org/">CoffeeScript</a>, leveraging Node to set-up <a href="http://coffeescript.org/#cake">Cake</a> builds and testing via <a href="https://github.com/kof/node-qunit">Qunit</a>. As a part of that effort, I also wrote my own Node package for sending <a href="http://growl.info/">Growl</a> notifications on Windows, 80s Hair-band style. It’s called <a href="https://github.com/bsatrom/wingrr">wingrr</a>, and you can get it at <a href="http://github.com/bsatrom/wingrr">http://github.com/bsatrom/wingrr</a>, or just run “npm install wingrr” in a console window.</p>
<p>Recently, I’ve been working on a few other projects&#8211;one, a simple port of the <a href="https://github.com/ry/node_chat">node_chat</a> application to CoffeeScript as an excuse to start using <a href="http://pivotal.github.com/jasmine/">Jasmine</a>; and another project using express and jade that I&#8217;m just getting rolling on this week. More on that one later.</p>
<p>In the meantime, I wanted to share something I learned while writing Jasmine tests (using the <a href="https://github.com/mhevery/jasmine-node">jasmine-node</a> package) for the node_chat application. node_chat is a simple chat server (a node chat server, who would have thought?) implementation and, as such, it relies on standard output, or stdout, to report errors and information to the “user.” For example, one method provided by the server for this application is “listen,” which, given a port and optional host, will listen to all http traffic at that location. Here’s my implementation, in CoffeeScript. (JavaScript purists can <a href="https://gist.github.com/raw/1349384/d1a1cb2be919e93a0f46093988470d2e4d66284c/server.js">click here for a not-generated-by-the-coffeescript-compiler equivalent</a>)</p>
<div id="gist-1349384" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="nv">exports = </span><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span></div><div class='line' id='LC2'><br/></div><div class='line' id='LC3'><span class="c1"># server logic omitted for brevity</span></div><div class='line' id='LC4'><br/></div><div class='line' id='LC5'><span class="nv">exports.listen = </span><span class="nf">(port, host, callback) -&gt;</span></div><div class='line' id='LC6'>&nbsp;&nbsp;<span class="k">try</span></div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">server</span><span class="p">.</span><span class="nx">listen</span> <span class="nx">port</span><span class="p">,</span> <span class="nx">host</span><span class="p">,</span> <span class="nx">callback</span></div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">util</span><span class="p">.</span><span class="nx">log</span> <span class="s">&quot;Server listening at http://</span><span class="si">#{</span><span class="nx">host</span> <span class="o">or</span> <span class="s">&quot;127.0.0.1&quot;</span><span class="si">}</span><span class="s">:</span><span class="si">#{</span><span class="nx">port</span><span class="si">}</span><span class="s">/&quot;</span></div><div class='line' id='LC9'>&nbsp;&nbsp;<span class="k">catch</span> <span class="nx">err</span></div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">util</span><span class="p">.</span><span class="nx">log</span> <span class="nx">err</span><span class="p">.</span><span class="nx">message</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1349384/d7ec7994351ac5d894e675b137068425e99cd76c/server.coffee" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1349384#file_server.coffee" style="float:right;margin-right:10px;color:#666">server.coffee</a>
            <a href="https://gist.github.com/1349384">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>Notice that I’m calling “util.log” (equivalent to sys.log in earlier versions of Node) to report that the server is listening, or any errors that may have occurred. As expected, this outputs to the console that the server is listening, as you can see in the image below.</p>
<p><a href="http://userinexperience.com/wp-content/uploads/SNAGHTML5902420.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="SNAGHTML5902420" src="http://userinexperience.com/wp-content/uploads/SNAGHTML5902420_thumb.png" alt="Console Output in Node.js" width="503" height="199" border="0" /></a></p>
<p>This is great, but I wanted to write unit tests that would start and interact with my server, and the best way to verify that my tests passed would be to inspect these messages. I <em>could</em> return these messages from each method, and then inspect the returned value—and I even did that for the first couple of tests—but that would mean that I’ve written production code for the sole purpose of asserting my expectations in a test, which feels dirty.</p>
<p>Instead, I thought it made more sense to hook into stdout myself, and inspect the output for my tests. I hoped that Node might provide some kind of object-based message pump for me to query, but I found no such feature (though do please leave me a comment here if I&#8217;ve overlooked something). So I was out of luck in terms of a standard, Node-provided way to inpect stdout from my tests.</p>
<p>Undaunted,  I thought a bit more about my problem. I figured I needed to:</p>
<ol>
<li>Determine the mechanism Node uses to write to stdout</li>
<li>Figure out how to &#8220;inject&#8221; an assertion into that mechanism</li>
</ol>
<p>With JavaScript, #2 would be a simple matter of &#8220;rewriting&#8221; the functionality used by #1. So it was really just a matter of figuring out the global objects that Node provides for stdout.</p>
<p>It turns out that Node handles all stdout via a global object called “process.stdout,” and calls to console (ie console.log) or util (ie util.puts or util.log) are merely wrappers for “process.stdout.write.” #1, check. For #2, I was able to override “write” by creating a separate JavaScript module whose only method, &#8220;setup,&#8221; accepts a callback stub to execute. Here’s my simple implementation (again, <a href="https://gist.github.com/raw/1349384/7bb62366768d9e41dd87234bc8bc127797b7e51f/hook_stdout.js">click here for the JavaScript version</a>):</p>
<div id="gist-1349384" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="nv">exports = </span><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span></div><div class='line' id='LC2'><br/></div><div class='line' id='LC3'><span class="nv">exports.setup = </span><span class="nf">(callback) -&gt;</span></div><div class='line' id='LC4'>&nbsp;&nbsp;<span class="nv">write = </span><span class="nx">process</span><span class="p">.</span><span class="nx">stdout</span><span class="p">.</span><span class="nx">write</span></div><div class='line' id='LC5'><br/></div><div class='line' id='LC6'>&nbsp;&nbsp;<span class="nv">process.stdout.write = </span><span class="p">(</span><span class="nf">(stub) -&gt;</span></div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nf">(string, encoding, fd) -&gt;</span></div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">stub</span><span class="p">.</span><span class="nx">apply</span> <span class="nx">process</span><span class="p">.</span><span class="nx">stdout</span><span class="p">,</span> <span class="nx">arguments</span></div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">callback</span> <span class="nx">string</span><span class="p">,</span> <span class="nx">encoding</span><span class="p">,</span> <span class="nx">fd</span><span class="p">)(</span><span class="nx">process</span><span class="p">.</span><span class="nx">stdout</span><span class="p">.</span><span class="nx">write</span><span class="p">)</span></div><div class='line' id='LC10'><br/></div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">return</span> <span class="o">-&gt;</span> <span class="nv">process.stdout.write = </span><span class="nx">write</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1349384/1f6222033bec5dd18c04c9dc387f347719cb87c4/hook_stdout.coffee" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1349384#file_hook_stdout.coffee" style="float:right;margin-right:10px;color:#666">hook_stdout.coffee</a>
            <a href="https://gist.github.com/1349384">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>Notice that my callback has access&#8211;via the string parameter&#8211;to the message being written to stdout. This is the value I’m passing into util.log above; and the value that I wanted to inspect in a test. Notice also that my setup method returns a function that “resets” process.stdout.write back to its original state. You’ll want to call that function after each test, otherwise your callback will fire for every write in your current instance of Node.</p>
<p>Once I had this module in hand, I was able use it in my tests. Here’s a Jasmine test for ensuring that calling server.listen emits the correct message:</p>
<div id="gist-1349384" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="nv">server = </span><span class="nx">require</span> <span class="s">&#39;../js/server&#39;</span></div><div class='line' id='LC2'><span class="nv">hook = </span><span class="nx">require</span> <span class="s">&#39;../js/hook_stdout&#39;</span></div><div class='line' id='LC3'><br/></div><div class='line' id='LC4'><span class="nx">describe</span> <span class="s">&#39;chat server&#39;</span><span class="p">,</span> <span class="o">-&gt;</span></div><div class='line' id='LC5'><br/></div><div class='line' id='LC6'>&nbsp;&nbsp;&nbsp;<span class="nx">it</span> <span class="s">&#39;should listen at localhost on a port I specify&#39;</span><span class="p">,</span> <span class="o">-&gt;</span></div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nv">unhook = </span><span class="nx">hook</span><span class="p">.</span><span class="nx">setup</span><span class="p">(</span><span class="nf">(string, encoding, fd) -&gt;</span></div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">expect</span><span class="p">(</span><span class="nx">string</span><span class="p">).</span><span class="nx">toContain</span> <span class="s">&#39;Server listening at http://127.0.0.1:3001/&#39;</span></div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">)</span></div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">server</span><span class="p">.</span><span class="nx">listen</span> <span class="s">&#39;3001&#39;</span>  	</div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nx">unhook</span><span class="p">()</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1349384/0d2f8be0aac5f827c3180018f83b5409f13f5f37/spec.coffee" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1349384#file_spec.coffee" style="float:right;margin-right:10px;color:#666">spec.coffee</a>
            <a href="https://gist.github.com/1349384">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>Given the current string provided to stdout, and thus, my callback, I was then able to call Jasmine’s expect() method and toContain() to assert that the string my server is outputting is the one I expected. Notice also that I call hook.setup just before I need it, and assign it to the local variable “unhook.” After my initial call to server.listen, I call unhook as a function, which resets writes back to their original state.</p>
<p>Now I can inspect stdout in my automated tests quickly and easily, and I’ve done all of this without having to modify my server code in any way to accommodate my tests. Feels like #winning to me. Hopefully you&#8217;ll find it useful, as well.</p>
<p>That’s that. Not a lengthy, or earth-shattering posts, by any means, but I thought it was worth sharing for anyone doing unit testing in Node applications. If you are, and you’re using a different or better approach for asserting stdout, please let me know by leaving a comment below!</p>
<div class='wpfblike' ><fb:like href='http://userinexperience.com/?p=714' layout='default' show_faces='true' width='400' action='like' colorscheme='light' send='false' /></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=eiRejlxg3aM:sQpc15MNHvs:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?i=eiRejlxg3aM:sQpc15MNHvs:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=eiRejlxg3aM:sQpc15MNHvs:dnMXMwOfBR0"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?d=dnMXMwOfBR0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=eiRejlxg3aM:sQpc15MNHvs:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?i=eiRejlxg3aM:sQpc15MNHvs:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/userinexperience/tYGT/~4/eiRejlxg3aM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://userinexperience.com/?feed=rss2&amp;p=714</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://userinexperience.com/?p=714</feedburner:origLink></item>
		<item>
		<title>HTML5.tx :: Links, Recap and a Thank You</title>
		<link>http://feedproxy.google.com/~r/userinexperience/tYGT/~3/Wg0wxpZRP2U/</link>
		<comments>http://userinexperience.com/?p=710#comments</comments>
		<pubDate>Mon, 24 Oct 2011 19:59:05 +0000</pubDate>
		<dc:creator>bsatrom</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://userinexperience.com/?p=710</guid>
		<description>&lt;p&gt;(This post is about three weeks late, I know.)&lt;/p&gt; &lt;p&gt;On October 8th, 2011, in Austin, TX, we held the first HTML5.tx event. We sold all 250 tickets two weeks ahead of time, and had over 240 people show the day of the event.&lt;/p&gt; &lt;p&gt;For an unproven conference, it was (and I know I’m biased) a [...]</description>
			<content:encoded><![CDATA[<p>(This post is about three weeks late, I know.)</p>
<p>On October 8th, 2011, in Austin, TX, we held the first HTML5.tx event. We sold all 250 tickets two weeks ahead of time, and had over 240 people show the day of the event.</p>
<p>For an unproven conference, it was (and I know I’m biased) a smashing success.</p>
<p>Photos of the event have been posted on Flickr <a href="http://bit.ly/html5txPics">here</a>.</p>
<p>For some nice conference recaps, see <a href="http://driftingcreatives.com/2011/10/12/html5tx-conference-experience/">here</a>, <a href="http://jakefolio.com/2011/10/html5-tx-review/">here</a>, <a href="http://mitchfincher.blogspot.com/2011/10/pictures-from-html5tx-october-8-2011.html">here</a>, <a href="http://thecodinghumanist.com/blog/archives/2011/10/11/html5tx">here</a> and <a href="http://billwoodland.com/blog/2011/10/23/html5-tx/">here</a>.</p>
<p>Our Pals Gavin and Martin from <a href="http://driftingcreatives.com">Drifting Creatives</a> have a nice Portfolio page up for HTML5.tx that you can see <a href="http://driftingcreatives.com/portfolio/html5tx/">here</a>.</p>
<p>We’re working on getting the videos up on the site, where they will be available for free. In the meantime, <a href="htp://csell.net">Clark</a> has published the recording for our HTML5 Smackdown session&nbsp; with the <a href="http://driftingcreatives.com/">Drifting Creatives</a> guys as Episode 61 of the Developer Smackdown podcast. <a href="http://developersmackdown.com/Archives/Show/61">Check it out here</a>.</p>
<p>If you attended HTML5.tx, and haven’t rated your sessions yet, <a href="http://speakerrate.com/events/1090-html5-tx">it’s not too late</a>. </p>
<p>Beyond that, I thought it best if—rather than trying to recreate the emotion of the event three weeks later—I posted the email I sent to all of the volunteers on our public DL the Monday after the event. Here it is, in near-entirety:</p>
<blockquote><p>To the HTML5.tx Planning Committee and friends,
<p>This weekend, over 240 people came together to learn from one another. You created a place for them to do that.
<p>Over 40 people joined us for the kickoff on Friday. 75 stayed late on Saturday. You all made them feel welcome, helped start and continue the many conversations this unique conference enabled.
<p>Close to 50 sessions were proposed for 14 slots. The final speaker slate represented some of the best web developers and designers, not just in Austin, but across Texas, and all the way to San Francisco and New York. You ignored the unproven state of our conference and pushed for the best content and speakers we could find.
<p>More than half of the attendees participated in at least one open space session. Fourteen sessions were proposed, meaning that 50% of the content at the conference was created by attendees. You insisted that we provide an open space, brought in one of the best facilitators around, and encouraged us to make open space an important part of the conference by making it the focus of the keynote.
<p>Countless people this weekend, from speakers to attendees alike, noted that this was one of the most well-organized, valuable conferences they had been to, local or otherwise. You made that happen by always thinking about our attendees first, and making sure no detail was overlooked. Though I’m sure each of us has a mental list of things we can improve upon next time, don’t miss this chance to feel good about everything <b><i>you did right</i></b>.
<p>Thank you, <a href="http://lostechies.com/derickbailey">Derick Bailey</a>, <a href="http://jakefolio.com/">Jake Smith</a>, Nola Stowe, <a href="http://lostechies.com/johnteague/">John Teague</a> and <a href="http://clubajax.org/">Mike Wilcox</a> for speaking up on this list and providing your input as we planned in public.
<p>Thank you, <b><a href="http://halanstevens.com/">Alan Stevens</a></b> for bringing open space to a new audience, and for truly being a part of this conference, instead of just “the talent.”
<p>Thank you, <b><a href="http://csell.net">Clark Sell</a></b>, for being my partner in crime and co-organizer of this conference. Always a pleasure, my friend. Next up, HTML5.wi. Beer, brats and JavaScript.
<p>Thank you, <b><a href="http://driftingcreatives.com/">Gavin Brahman</a>, <a href="http://carouth.com/">Jeff Carouth</a>, <a href="http://caseysoftware.com/">Keith Casey</a>, <a href="http://lostechies.com/sharoncichelli/">Sharon Cichelli</a>, <a href="http://frogslayer.com/">Sam Hooker</a>, <a href="http://driftingcreatives.com/">Martin Hooper</a>, <a href="http://robertstackhouse.com/">Robert Stackhouse</a>, Tim Thomas, Jake Wong</b> for being part of the planning committee and for making so much happen. Each of you made a much larger impact on this event than you likely realize. Thank you for putting up with my quirks, for your encouragement throughout, and for pushing this to be the best conference it could be.
<p>Thank you, <a href="http://caseysoftware.com/">Keith Casey</a>, <a href="http://getify.com">Kyle Simpson</a> and the growing <a href="http://hubaustin.com/">HubAustin</a> community, for allowing us to close at your facility. Consider HTML5.tx your biggest fan and promoter!
<p>In spite of what the 10:01 entry on the battle plan might have read. I <b><i>will</i></b> be doing this again, and I sincerely hope to have you alongside me.
<p>HTML5.tx. 100% Pure. Indeed, it was, because of each of you.
<p>Thank you, thank you, thank you.
<p>Brandon Satrom
<p>Unretired Conference Wrangler</p>
</blockquote>
<p>We are planning to do this again. Hope you’ll consider joining us!</p>
<div class='wpfblike' ><fb:like href='http://userinexperience.com/?p=710' layout='default' show_faces='true' width='400' action='like' colorscheme='light' send='false' /></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=Wg0wxpZRP2U:VAkBtgQOfK0:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?i=Wg0wxpZRP2U:VAkBtgQOfK0:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=Wg0wxpZRP2U:VAkBtgQOfK0:dnMXMwOfBR0"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?d=dnMXMwOfBR0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=Wg0wxpZRP2U:VAkBtgQOfK0:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?i=Wg0wxpZRP2U:VAkBtgQOfK0:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/userinexperience/tYGT/~4/Wg0wxpZRP2U" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://userinexperience.com/?feed=rss2&amp;p=710</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://userinexperience.com/?p=710</feedburner:origLink></item>
		<item>
		<title>HTML5 Forms with ASP.NET MVC and MvcContrib.FluentHtml</title>
		<link>http://feedproxy.google.com/~r/userinexperience/tYGT/~3/Pj9xAHs8Z1E/</link>
		<comments>http://userinexperience.com/?p=692#comments</comments>
		<pubDate>Fri, 02 Sep 2011 16:10:43 +0000</pubDate>
		<dc:creator>bsatrom</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[asp.net]]></category>
		<category><![CDATA[asp.net mvc]]></category>
		<category><![CDATA[FluentHtml]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[HTML5]]></category>
		<category><![CDATA[mvccontrib]]></category>

		<guid isPermaLink="false">http://userinexperience.com/?p=692</guid>
		<description>&lt;p&gt;Earlier this week, I wrapped up the third installment of my “Building Apps for HTML5” Series for MSDN Magazine (check out &lt;a href="http://msdn.microsoft.com/en-us/magazine/42f3dca7-3ca7-4b4f-80be-309f0a90349f"&gt;part 1&lt;/a&gt; and &lt;a href="http://msdn.microsoft.com/en-us/magazine/d39a40cd-cf1f-4852-a7cc-f1eff6ff217c"&gt;part 2&lt;/a&gt;, if you haven’t already), and there was an out of scope item that I didn’t have the space to cover, but thought would be a good blog [...]</description>
			<content:encoded><![CDATA[<p>Earlier this week, I wrapped up the third installment of my “Building Apps for HTML5” Series for MSDN Magazine (check out <a href="http://msdn.microsoft.com/en-us/magazine/42f3dca7-3ca7-4b4f-80be-309f0a90349f">part 1</a> and <a href="http://msdn.microsoft.com/en-us/magazine/d39a40cd-cf1f-4852-a7cc-f1eff6ff217c">part 2</a>, if you haven’t already), and there was an out of scope item that I didn’t have the space to cover, but thought would be a good blog post.</p>
<p>The article was about HTML5 Web Forms, essentially the new input types (email, tel, number, date, etc.), new attributes (autofocus, placeholder, etc.) and new form validation goodies (required, pattern, formnovalidate, etc.). It was a fun article to write, and it’s slated to drop in early November.</p>
<p>One of the questions that often comes up from .NET developers when I talk about HTML5 Web Forms is how these features integrate with ASP.NET Web Forms or MVC. In the article, I speak briefly about updates like <a href="http://bit.ly/nQzsld">VS 2010 SP1</a> and the mouthfully-named “<a href="http://bit.ly/qOG7Ni">Reliability Update 1 for .NET Framework 4</a>,” and Scott Hunter has a <a href="http://bit.ly/qE7jLz">nice, succinct blog post</a> that covers both, and which you can check out <a href="http://bit.ly/qE7jLz">here</a>.</p>
<p>What I wasn’t able to cover in the article, though, was some specifics around using these new input types and attributes with ASP.NET MVC, specifically how one would use these with Strongly-typed HTML helpers in MVC. That’s the purpose of this post.</p>
<p>But first, since the article isn’t out yet as I’m writing this, a quick primer on HTML5 Web Forms for those not familiar.</p>
<h3>What’s HTML5 Web Forms?</h3>
<p>HTML5 Web Forms (one of the earliest pieces of what we now call “HTML5”) lives in the official W3C HTML5 Specification, which you can read yourself at <a href="http://www.w3.org/TR/html5/forms.html">http://www.w3.org/TR/html5/forms.html</a>. A significant portion of the specification is dedicated to new types and content attributes for the input element, which can be found here: <a href="http://www.w3.org/TR/html5/the-input-element.html">http://www.w3.org/TR/html5/the-input-element.html</a>. For a more digestible resource on HTML5 Forms, I recommend the excellent Forms chapter (“<a href="http://diveintohtml5.info/forms.html">A Form of Madness</a>”) from <a href="http://diveintomark.org">Mark Pilgrim’s</a> <em><a href="http://www.amazon.com/HTML5-Up-Running-Mark-Pilgrim/dp/0596806027">HTML5: Up and Running</a>.</em></p>
<p>The specification introduces 13 new input types (&lt;input type=”?” /&gt;) for use in our forms. Here’s the list:</p>
<table width="400" border="0" cellspacing="0" cellpadding="2">
<tbody>
<tr>
<td valign="top" width="87">
<ul>
<li>
<div align="left">search</div>
</li>
<li>
<div align="left">email</div>
</li>
<li>
<div align="left">tel</div>
</li>
<li>
<div align="left">url</div>
</li>
<li>
<div align="left">datetime</div>
</li>
<li>
<div align="left">date</div>
</li>
<li>
<div align="left">month</div>
<p>&nbsp;</li>
</ul>
</td>
<td valign="top" width="313">
<ul>
<li>
<div align="left">week</div>
</li>
<li>
<div align="left">time</div>
</li>
<li>
<div align="left">datetime-local</div>
</li>
<li>
<div align="left">number</div>
</li>
<li>
<div align="left">range</div>
</li>
<li>
<div align="left">color</div>
<p>&nbsp;</li>
</ul>
</td>
</tr>
</tbody>
</table>
<p>Each of these new types comes with some interesting behaviors and features. Each also has varying levels of support in the major browsers, but since I cover that in depth in my article (and others have online), I’m not going to rehash it here. For the purposes of this post, let’s assume that I’ve decided to use these new features, am using feature detection (either rolling my own or via Modernizr) and have chosen a polyfilling library or two to fill the gaps in functionality back to older browsers. Of course, I probably should point out that there’s no reason NOT to use any of these new types today. If an older browser encounters a type it doesn’t recognize, it will just change the type attribute to “text,” which is what you’re already using. But newer browsers get all of the built-in validation and presentation provided by the browser.</p>
<h3>Using HTML5 Web Forms</h3>
<p>All you need to do to get started with HTML5 Forms is use any of the new input types or attributes on a form. Let’s take a look at the markup (snipped a bit) for a sample form (coincidentally, the same form from my article)</p>
<p><script src="https://gist.github.com/1187346.js?file=raw.html"></script></p>
<p><em>Note: If you cannot view the embedded Gist above for any reason, click <a href="https://raw.github.com/gist/1186946/403af09aa2596277b930c51b7cbbf29727f22089/raw.html">here</a> to view the embedded code.</em></p>
<p>Here’s the resulting form:</p>
<p><a href="http://userinexperience.com/wp-content/uploads/image.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="image" src="http://userinexperience.com/wp-content/uploads/image_thumb.png" alt="image" width="508" height="626" border="0" /></a></p>
<p>You probably noticed a few new things in the markup above, and I’ll summarize them briefly here (again, without detracting too much from the point of this post):</p>
<ol>
<li>New type=”” values on inputs (email, url, tel, date and number) – All of these do exactly what you’d expect them to.</li>
<li>A “required” attribute – Tells the browser that this field must have a value before the form can submitted</li>
<li>An “autofocus” attribute – Notifies the browser that a given field should automatically receive focus (a cursor) when the page loads</li>
<li>A “placeholder” attribute – Instructs the browser to overlay hint text when the field is empty. The first three fields above us this, as you can see from the screenshot.</li>
<li>A “pattern” attribute – Provides a regular expression for the browser to use when validating the form. Above, I’m telling the browser that I’ll only accept telephone numbers in “(xxx) xxx-xxxx” format.</li>
<li>“min” and “max” attributes – For type=”number” the minimum and maximum allowed values for the field to be valid.</li>
<li>&#8220;A “formnovalidate” attribute – Tells the browser to turn off validation for a submit field. In this case, I use the “Save for later” button to allow the user to save an order in process and return to it later.</li>
</ol>
<p>In addition to what I’ve listed above, a few of these fields provide some automatic validation when I invoke their type. The email field must contain a valid email, url a valid URL, etc.</p>
<h3>Enter ASP.NET MVC, Stage Right</h3>
<p>As great as these new features are, if you’re using ASP.NET MVC, you’re probably asking yourself a couple of questions right now.</p>
<p>1) How do I use this with strongly-typed HTML helpers?</p>
<p>2) How do I use this with existing DataAnnotations on my model?</p>
<p>Let’s take a look at each of those in turn.</p>
<h3></h3>
<h3>HTML5 Forms and HTML Helpers</h3>
<p>If you’re a fan of the HTML helpers in ASP.NET MVC, you probably don’t type this very often</p>
<blockquote><p><span style="font-family: 'Courier New';">&lt;input type=&#8221;text&#8221; id=&#8221;orderName&#8221; /&gt;</span></p></blockquote>
<p>And instead prefer something more like this:</p>
<blockquote>
<pre>@Html.TextBoxFor(m =&gt; m.Name)</pre>
</blockquote>
<p><span style="font-family: Georgia;">Or even just Html.TextBox. </span></p>
<pre></pre>
<p><span style="font-family: Georgia;">In the case of our first element, the Name field, using this with the new HTML5 attributes is easy:</span></p>
<pre></pre>
<pre></pre>
<p>&nbsp;</p>
<blockquote>
<pre>@Html.TextBoxFor(m =&gt; m.Name, new { required = "required",</pre>
<pre>                      autofocus = "autofocus",</pre>
<pre>                      placeholder = "ex. Huggie Reyes" })</pre>
</blockquote>
<p><span style="font-family: Georgia;">This will emit effectively the same markup as the original, raw field. So the good news is that, as you would expect, the new attributes work just fine with the HTML Helpers.</span></p>
<p>The real problem is with the rest of my fields, all of which use type values not yet fully supported by the HTML helpers (i.e. type=”email”). For these, I can use the @type property in the anonymous properties object, like so:</p>
<blockquote>
<pre>@Html.TextBoxFor(m =&gt; m.Email, new { @type = "email" , required = "required",</pre>
<pre>                      autofocus = "autofocus",</pre>
<pre>                      placeholder = "ex. hugo@dharma.com" })</pre>
</blockquote>
<p>There’s also no reason why you can’t just author markup by hand and keep the input values in sync with your model. But if you’re a attached to the helpers, or if you prefer the type be tied more closely to the helper call itself, the good news is that you have options.</p>
<h3>HTML5 Forms and MvcContrib.FluentHtml</h3>
<p>The best option, IMO, would be to check out <a href="http://mvccontrib.codeplex.com/">MvcContrib</a>, specifically the <a href="http://mvccontrib.codeplex.com/wikipage?title=FluentHtml&amp;referringTitle=Documentation">FluentHtml features</a> from <a href="http://lunaverse.wordpress.com">Tim Scott</a>. FluentHtml has been around for a while, but Tim recently added support for many of the new HTML5 input types and attributes. It’s not yet in an official release, but you can build from the source, grab the MvcContrib.FluentHtml assembly, and follow the setup instructions here. Once we’re all setup,  we can take the raw markup from my order form above and use Fluent Html to yield the following:</p>
<p><script src="https://gist.github.com/1187346.js?file=fluent.html"></script></p>
<p><em>Note: If you cannot view the embedded Gist above for any reason, click <a href="https://raw.github.com/gist/1187346/c6561a373e34745409dc83c19cb0ca802e11f1ec/fluent.html">here</a> to view the embedded code.</em></p>
<p>(While writing this post, I went ahead and implemented the FormNoValidate method on the SubmitButton type, so go grab the latest source for MvcContrib if you’re not up to date.)</p>
<p>Now, when you run the page again, you’ll see that functionally, everything still works as it did before, but you have the benefit of those strongly-typed helpers (and the elegance of the FluentHtml library, if you don’t mind my saying so.)</p>
<h3></h3>
<h3>That’s Nice, But What About My Model Metadata?</h3>
<p>In spite of all of this Fluent-y, typed goodness, I’m betting many of you are still bothered by one aspect of using the new input types and attributes on your forms, especially if you’re a fan of annotating your Models with validation attributes (DataAnnotations) like [Required], [Range] and [RegularExpression]. Chances are, when you saw the example markup above with required and pattern attributes, you thought to yourself “Awesome, so how can I use my existing DataAnnotations with these new attributes?”</p>
<p>If you asked that question, You’re probably using MVC Client Validation (introduced in MVC 2) or Unobtrusive Client Validation (introduced in MVC 3), whereby the Model metadata you implement on a given model is used by the framework to generate client validation scripts or data- attributes for use by the client validation framework. These are both fantastic approaches for keeping your validation DRY and consistent from the client to the server, and you should keep using them.</p>
<p>But the reason why HTML5 Forms Validation is so compelling is because it moves client validation squarely into the browser’s lap, meaning that no client-side JavaScript is needed to perform validation before a form is submitted to the server. Of course, script-based client validation should continue to be your first fallback option—with server validation as the last checkpoint—but leveraging in-browser validation for the growing number of users with a modern browser means increased performance and a better user experience.</p>
<p>“That’s great,” you say, “but what about those DataAnnotations?”</p>
<p>With the help of MvcContrib.FluentHtml and a couple of custom behaviors, we can quickly introduce a mechanism that will leverage our model metadata for validation, meaning that we can remove all instances of Pattern(), Required() and Limit() from our example fluent markup above, and the proper HTML attributes will be added on our behalf. Let’s assume that this is my model:</p>
<p><script src="https://gist.github.com/1187346.js?file=Order.cs"></script></p>
<p><em>Note: If you cannot view the embedded Gist above for any reason, click <a href="https://gist.github.com/raw/1187346/3a890f8d59c3c44e77c87047dd8ba165995f0401/Order.cs">here</a> to view the embedded code.</em></p>
<p>And, rather than manually specifying required, pattern and min/max on my markup (which would be repetitive), I want to have those attributes added for me when the appropriate Model attributes are present. MvcContrib.FluentHtml introduces a mechanism whereby I can define a series of behaviors that I want to apply to a single element, or an entire page. I start by implementing the IBehavior&lt;IMemberElement&gt; interface. Here’s an example where I’ve created a RegularExpressionBehavior:</p>
<p><script src="https://gist.github.com/1187346.js?file=RegularExpressionBehavior.cs"></script></p>
<p><em>Note: If you cannot view the embedded Gist above for any reason, click <a href="https://gist.github.com/raw/1187346/9ac5bbd85d4027394be6f49fb95096131f6148b3/RegularExpressionBehavior.cs">here</a> to view the embedded code.</em></p>
<p>Once I’ve created all of the behaviors I need (in this example, I need custom behaviors to fetch Required, RegularExpression and Range attributes), I’ll then create a ViewPage that inherits from ModelViewPage&lt;T&gt; (a type provided by MvcContrib.FluentHtml that I need to use the fluent helpers) and provides the base class with instances of my custom behaviors. Here’s the one I’ve created:</p>
<p><script src="https://gist.github.com/1187346.js?file=FluentHtml5ViewPage.cs"></script></p>
<p><em>Note: If you cannot view the embedded Gist above for any reason, click <a href="https://raw.github.com/gist/1187346/50f0e37d80f0e8aa9f32874946cfd3a74b74ba12/FluentHtml5ViewPage.cs">here</a> to view the embedded code.</em></p>
<p>Now, all that’s left for me to do is to inherit my ViewPage from the custom ViewPage, and remove the Required(), Pattern() and Limt() calls from my page. For Razor, just add the following to the top of your ViewPage</p>
<p>&nbsp;</p>
<blockquote><p>@inherits FluentHmlt5ViewPage&lt;Order&gt;</p></blockquote>
<p>Where “Order” is your Model or ViewModel. Obviously, you’ll need to tweak this if you’re using a different view engine.</p>
<p>After removing the statements we don’t need to specify on the view, our markup looks much cleaner, and it’s using Model metadata to set validation attributes for the browser!</p>
<p><script src="https://gist.github.com/1187346.js?file=fluentWithBehaviors.html"></script></p>
<p><em>Note: If you cannot view the embedded Gist above for any reason, click <a href="https://gist.github.com/raw/1187346/792bbe6d232c8f915ba9b9b57c696abd02e9d520/fluentWithBehaviors.html">here</a> to view the embedded code.</em></p>
<p>So there you have it, HTML5 Forms, ASP.NET MVC and Model validation all living in harmony together!</p>
<p>If you’re interested in trying out FluentHtml with HTML5 Forms and the custom behaviors I describe here, I’ve added a basic solution with the 3 custom behaviors and a custom ViewPage object to GitHub as <a href="https://github.com/bsatrom/FluentHTML5">FluentHTML5</a>. Feel free to <a href="https://github.com/bsatrom/FluentHTML5">download it here</a>, and let me know what you think. If its useful, I might expand this with other behaviors.</p>
<div class='wpfblike' ><fb:like href='http://userinexperience.com/?p=692' layout='default' show_faces='true' width='400' action='like' colorscheme='light' send='false' /></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=Pj9xAHs8Z1E:32lAECcTWzU:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?i=Pj9xAHs8Z1E:32lAECcTWzU:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=Pj9xAHs8Z1E:32lAECcTWzU:dnMXMwOfBR0"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?d=dnMXMwOfBR0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=Pj9xAHs8Z1E:32lAECcTWzU:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?i=Pj9xAHs8Z1E:32lAECcTWzU:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/userinexperience/tYGT/~4/Pj9xAHs8Z1E" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://userinexperience.com/?feed=rss2&amp;p=692</wfw:commentRss>
		<slash:comments>18</slash:comments>
		<feedburner:origLink>http://userinexperience.com/?p=692</feedburner:origLink></item>
		<item>
		<title>Introducing the Knockout.Unobtrusive Plugin</title>
		<link>http://feedproxy.google.com/~r/userinexperience/tYGT/~3/Vb3OSoe5cOU/</link>
		<comments>http://userinexperience.com/?p=689#comments</comments>
		<pubDate>Mon, 08 Aug 2011 21:26:29 +0000</pubDate>
		<dc:creator>bsatrom</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[knockout]]></category>
		<category><![CDATA[mvvm]]></category>
		<category><![CDATA[ui]]></category>
		<category><![CDATA[unobtrusive javascript]]></category>

		<guid isPermaLink="false">http://userinexperience.com/?p=689</guid>
		<description>&lt;p&gt;Last month, &lt;a href="http://userinexperience.com/?p=633"&gt;I blogged about how much I love KnockoutJS&lt;/a&gt;, a fantastic JavaScript MVVM framework for creating rich, dynamic UIs. In &lt;a href="http://userinexperience.com/?p=633"&gt;that post&lt;/a&gt;, I also shared my only real qualms with &lt;a href="http://knockoutjs.com/"&gt;Knockout&lt;/a&gt;: the exclusive use of data-bind attributes for binding a view to the underlying ViewModel. And while there is much about [...]</description>
			<content:encoded><![CDATA[<p>Last month, <a href="http://userinexperience.com/?p=633">I blogged about how much I love KnockoutJS</a>, a fantastic JavaScript MVVM framework for creating rich, dynamic UIs. In <a href="http://userinexperience.com/?p=633">that post</a>, I also shared my only real qualms with <a href="http://knockoutjs.com/">Knockout</a>: the exclusive use of data-bind attributes for binding a view to the underlying ViewModel. And while there is much about the declarative style bindings <a href="http://knockoutjs.com/">Knockout</a> uses that I like, I thought it would be a fun (and hopefully useful) exercise to take my original unobtrusive post and try to formalize my thinking into a plugin. <a href="http://lostechies.com/derickbailey/">Derick Bailey</a> deserves the credit for much of the inspiration here, so be sure to check out the <a href="http://lostechies.com/derickbailey/2011/07/24/awesome-model-binding-for-backbone-js/">awesome work he’s doing</a> with the <a href="https://github.com/derickbailey/backbone.modelbinding">Backbone.ModelBinding</a> plugin. </p>
<h4><a href="https://github.com/bsatrom/Knockout.Unobtrusive">Knockout.Unobtrusive :: Unobtrusive model binding syntax for KnockoutJS</a></h4>
<p>Over the last week, I’ve spent some time here and there taking the code from my <a href="http://userinexperience.com/?p=633">original post</a> and using it as inspiration to create a plugin for Knockout that allows developers to use script-based bindings, rather than the default data-bind syntax. The result is <a href="https://github.com/bsatrom/Knockout.Unobtrusive">Knockout.Unobtrusive</a>, which I’ve placed on GitHub. I should note here that using Knockout.Unobtrusive isn’t the only option if you’re looking to clean up some of the clutter in your data-bind attributes. <a href="http://www.knockmeout.net">Ryan Niemeyer</a> has a <a href="http://www.knockmeout.net/2011/08/simplifying-and-cleaning-up-views-in.html">great post on cleaning up Knockout Views</a> that I recommend you read. But, if you’re looking to go farther, read on!</p>
<p>This plugin was developed using a test-first approach, with <a href="https://github.com/jquery/qunit">qUnit</a> as my JavaScript test framework of choice. The core plugin itself was authored using <a href="http://jashkenas.github.com/coffee-script/">CoffeeScript</a>, and the full source can be found <a href="https://github.com/bsatrom/Knockout.Unobtrusive/blob/master/coffee/knockout.unobtrusive.coffee">here</a>.</p>
<p>
<p><em></em></p>
<p><a href="http://jashkenas.github.com/coffee-script/">CoffeeScript</a>, if you’re not familiar, is a language that compiles 1:1 to JavaScript. I’ve been using it for several weeks now, and I’m sold. During development, I’m running the CoffeeScript compiler locally, with instructions to watch the above coffee file for changes, and to re-compile that file into JavaScript on each change. The resulting JavaScript file is then run against my qUnit tests.
<p>Even if you’re not familiar with CoffeeScript,&nbsp; the code at the link above should be pretty easy to mentally parse. If, however, you would rather take a look at the JavaScript that CoffeeScript generates, you can check it out <a href="https://github.com/bsatrom/Knockout.Unobtrusive/blob/master/js/knockout.unobtrusive.js">here</a> in the source for Knockout.Unobtrusive.</p>
<h4>Getting Started with Knockout.Unobtrusive</h4>
<p>Getting started with the plugin is pretty easy. First, <a href="https://github.com/bsatrom/Knockout.Unobtrusive">download the source from my GitHub repository</a> and include a reference to <a href="https://github.com/bsatrom/Knockout.Unobtrusive/blob/master/js/knockout.unobtrusive.js">knockout.unobtrusive.js</a> just below Knockout proper.</p>
<p><script src="https://gist.github.com/1131800.js?file=scripts.html"></script></p>
<p><em>Note: If you cannot view the embedded Gist above for any reason, click <a href="https://gist.github.com/raw/1131800/e41961c1093a0672594ce0a6bd15bad05413d5ec/scripts.html">here</a> to view the embedded code.</em></p>
<p>Once you’ve added Knockout.Unobtrusive to your application, you can start moving your existing bindings (data-bind) into a bindings object, and/or create new bindings as needed. I have a <a href="http://jsfiddle.net/bsatrom/vRECM/">full example up on JSFiddle</a>, and embedded below, but let’s take a look at some of the HTML from that fiddle.</p>
<p><script src="https://gist.github.com/1131800.js?file=createSpeaker.html"></script></p>
<p><em>Note: If you cannot view the embedded Gist above for any reason, click <a href="https://gist.github.com/raw/1131800/7f2ce8d5d574657d376e2cf679726be0b01404b0/createSpeaker.html">here</a> to view the embedded code.</em></p>
<p>Similar to the example code used in my <a href="http://userinexperience.com/?p=633">original post</a>, Knockout.Unobtrusive ties the View (markup) and ViewModel together through the use of <em>id</em> or <em>name</em> attributes in my markup, and a <em>bindings</em> object passed into the plugin. Using the <em>id</em> and <em>name</em> properties above, we simply need to create a bindings object that “glues together” my View and ViewModel. We can do so by listing pairs of DOM element ids/names and ViewModel properties, organized by Knockout binding type (value, text, options, etc.).</p>
<p><script src="https://gist.github.com/1131800.js?file=koBindings.js"></script></p>
<p><em>Note: If you cannot view the embedded Gist above for any reason, click <a href="https://gist.github.com/raw/1131800/bfbd7cf3fff959cace79b86b0343095d32eba2e2/koBindings.js">here</a> to view the embedded code.</em></p>
<p>You’ll notice a couple of conventions at work here. Each property in the bindings object corresponds to a <a href="http://knockoutjs.com/documentation/introduction.html">binding provided by KnockoutJS</a>. Thus, “text,” “value,” “options” and the like are intended to be leveraged in similar situations as the default bindings. Where I previously had an input field similar to the following:</p>
<blockquote><p>&lt;input type=”text” <strong>data-bind</strong>=”value: name” &gt;&lt;/input&gt;</p>
</blockquote>
<p>I would instead do something like this in my HTML:</p>
<blockquote><p>&lt;input type=”text” <strong>id</strong>=”name”&gt;&lt;/input&gt;</p>
</blockquote>
<p>Or even this:</p>
<blockquote><p>&lt;input type=”text” <strong>name</strong>=”name”&gt;&lt;/input&gt; //name AND id are supported</p>
</blockquote>
<p>and add the following to my JavsScript bindings object:</p>
<blockquote><p>var bindings = {</p>
<p>&nbsp; value: [ { name: ‘name’ } ]</p>
<p>};</p>
</blockquote>
<p>Of course, Knockout.Unobtrusive uses several conventions, so anytime you have an exact match between an element id/name—like we do above—you can minimize the binding declaration like so:</p>
<blockquote><p>var bindings = {</p>
<p>&nbsp; value: [ ‘name’ ]</p>
<p>};</p>
</blockquote>
<p>Mixing and matching minimized and expanded properties works, too:</p>
<blockquote><p>var bindings = {</p>
<p>value: [ ‘name’, { twitterHandle: ‘handle’ } ]</p>
<p>};</p>
</blockquote>
<p>Note that Knockout.Unobtrusive doesn’t paint you into a script-only corner. Since the current version is effectively creating <em>data-bind</em> attributes on your behalf, using the bindings you specify, there’s nothing stopping you from using data-bind attributes along with script-based bindings. In fact, v0.1 of Knockout.Unobtrusive doesn’t yet support the creation of bindings in <a href="http://knockoutjs.com/documentation/template-binding.html">template blocks</a>, so you’ll need to continue to use data-bind for the time being.</p>
<p>Once I’ve defined my bindings object, and I’ve adjusted my markup with id or name attributes where appropriate, I need to call Knockout.Unobtrusive’s createBindings() method and pass in my bindings object. Of course, this needs to be done <em>before</em> I call ko.applyBindings()</p>
<p><script src="https://gist.github.com/1131800.js?file=createBindings.js"></script></p>
<p><em>Note: If you cannot view the embedded Gist above for any reason, click <a href="https://gist.github.com/raw/1131800/d02a94a37d846d21c1e0e841017c833c76155082/createBindings.js">here</a> to view the embedded code.</em></p>
<p>Now I’m off to the races, using KnockoutJS with clean views and all of my behavior defined in JavaScript! <a href="http://jsfiddle.net/bsatrom/vRECM/">Here’s a</a> <a href="http://jsfiddle.net/bsatrom/vRECM/">working sample</a>, courtesy of <a href="http://jsfiddle.net/">JSFiddle</a>.</p>
<p><iframe style="width: 100%; height: 650px" src="http://jsfiddle.net/bsatrom/vRECM/embedded/result,js,html,resources"></iframe></p>
<p>Note: If you cannot view the embedded Fiddle above for any reason, <a href="http://jsfiddle.net/bsatrom/vRECM/">click here</a> to view it at <a href="http://jsfiddle.net/">JSFiddle.net</a>.</p>
<p>For more information about Knockout.Unobtrusive, <a href="https://github.com/bsatrom/Knockout.Unobtrusive">visit the GitHub repository here</a>. The <a href="https://github.com/bsatrom/Knockout.Unobtrusive/blob/master/readme.md">Readme</a> goes into a bit more detail about currently supported bindings, conventions used in the plugin and plans for future features, so be sure to check that out. Keep in mind that this plugin is v0.1, so there’s still plenty of work to do. So if you have any questions, comments, issues or suggestions, feel free to leave them here as comments, or <a href="https://github.com/bsatrom/Knockout.Unobtrusive/issues">enter a issue or two</a> at the <a href="https://github.com/bsatrom/Knockout.Unobtrusive/">project site</a>.</p>
<p>So, what do you think? Am I onto something, or totally off the reservation? How would you improve this plugin, or what else do I need to add?</p>
<div class='wpfblike' ><fb:like href='http://userinexperience.com/?p=689' layout='default' show_faces='true' width='400' action='like' colorscheme='light' send='false' /></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=Vb3OSoe5cOU:oiZbwJDeseA:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?i=Vb3OSoe5cOU:oiZbwJDeseA:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=Vb3OSoe5cOU:oiZbwJDeseA:dnMXMwOfBR0"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?d=dnMXMwOfBR0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=Vb3OSoe5cOU:oiZbwJDeseA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?i=Vb3OSoe5cOU:oiZbwJDeseA:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/userinexperience/tYGT/~4/Vb3OSoe5cOU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://userinexperience.com/?feed=rss2&amp;p=689</wfw:commentRss>
		<slash:comments>18</slash:comments>
		<feedburner:origLink>http://userinexperience.com/?p=689</feedburner:origLink></item>
		<item>
		<title>Progressive .NET Tutorials from Skills Matter (and a free pass giveaway!)</title>
		<link>http://feedproxy.google.com/~r/userinexperience/tYGT/~3/CzdxwyXiiMU/</link>
		<comments>http://userinexperience.com/?p=662#comments</comments>
		<pubDate>Mon, 01 Aug 2011 13:48:28 +0000</pubDate>
		<dc:creator>bsatrom</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[conference]]></category>
		<category><![CDATA[cucumber]]></category>
		<category><![CDATA[tdd]]></category>

		<guid isPermaLink="false">http://userinexperience.com/?p=662</guid>
		<description>&lt;p&gt;The fine folks over at &lt;a href="http://skillsmatter.com"&gt;Skills Matter&lt;/a&gt; are putting on the fourth annual &lt;a href="http://skillsmatter.com/event/open-source-dot-net/progressive-dot-net-tutorials-2011/js-2405"&gt;Progressive .Net Tutorials&lt;/a&gt;, and if you’ll be anywhere London on September 5th-7th, you should be there. This is an amazing lineup of speakers and topics, and the full details are posted below. £425.00 for 3 days of John Skeet, Sebastien [...]</description>
			<content:encoded><![CDATA[<p>The fine folks over at <a href="http://skillsmatter.com">Skills Matter</a> are putting on the fourth annual <a href="http://skillsmatter.com/event/open-source-dot-net/progressive-dot-net-tutorials-2011/js-2405">Progressive .Net Tutorials</a>, and if you’ll be anywhere London on September 5th-7th, you should be there. This is an amazing lineup of speakers and topics, and the full details are posted below. £425.00 for 3 days of John Skeet, Sebastien Lambla, Gaspar Nagy, Ian Robinson, and more? A steal, I tell you!</p>
<p>I’m honestly quite jealous that I can’t hop on a plane and get there myself. Devastated, even. To help me feel better, the folks at <a href="http://skillsmatter.com">Skills Matter</a> are letting me give away <strong>two free passes</strong> to this event. So, if you want one, here’s what I want from you: <strong>Leave me a comment on this post and tell me who among the distinguished speakers below you want to see and why</strong>. In one week (Monday, August 8th), I’ll pick my favorite responses. Comments are threaded, so feel free to append, modify and enhance your answer as the week rolls on. The only request I have of the two winners is that they send me an email after the event describing their experience so that I can post it here later in the fall. Deal? Great.</p>
<p>If you’re not planning to throw your name in the hat for the passes, fret not, as I also have a discount code for you to use. When <a href="https://skillsmatter.com/register-online/conf/849">registering for the conference</a>, enter the promo code “<strong>PROGNET50</strong>” to get £50 off this event.</p>
<p>This should be an awesome event, and I can’t wait to hear why you’re exited about it!</p>
<p><img src="http://skillsmatter.com/custom/images/progressivenew.png" alt="Progressive .NET Tutorials" width="562" height="151" /></p>
<p><strong>EVENT DETAILS</strong><br />
<strong>SPEAKERS:</strong> Christian Hassa, Gaspar Nagy, Ian Cooper, Sebastien Lambla, Dylan Beattie , Simon Brown, Paul Stack, Damjan Vujnovic, Adam Granicz, Ian Robinson, Mark Rendle, Steven Robbins, Jon Skeet, Nathan Gloyn<br />
<strong>WHAT:</strong> Progressive .NET Tutorials 2011<br />
<strong>WHERE:</strong> The Skills Matter eXchange, London<br />
<strong>WHEN:</strong> 5th-7th Sep 2011 , 9:30AM<br />
<strong>COST: </strong>£425.00<br />
<strong>EVENT TAG:</strong> #prognet<br />
<strong>FULL DETAILS AND REGISTRATION:</strong> <a href="http://skillsmatter.com/event/open-source-dot-net/progressive-dot-net-tutorials-2011/js-2405">http://skillsmatter.com/event/open-source-dot-net/progressive-dot-net-tutorials-2011/<br />
</a><br />
<strong>READER OFFER:</strong> <a href="http://skillsmatter.com/event/open-source-dot-net/progressive-dot-net-tutorials-2011/js-2405">£50 discount off the ticket price, quoting Promocode: PROGNET50 when registering </a></p>
<p><strong>PROGRAM HIGHLIGHTS:</strong><br />
<strong>Monday September 5th Track 1 </strong><br />
09.30 &#8211; 13.00 GHERKIN ACCEPTANCE CRITERIA, Christian Hassa &amp; Gaspar Nagy<br />
14.00 &#8211; 17.30 AUTOMATING GHERKIN ACCEPTANCE CRITERIA, Christian Hassa &amp; Gaspar Nag</p>
<p><strong>Monday Track 2 </strong><br />
09.30 &#8211; 13.00 SOLVING THE PACKAGING PUZZLE, Ian Cooper &amp; Sebastien Lambla<br />
14.00 &#8211; 17.30 FRONT-END TIPS FOR BACK-END DEVS, Dylan Beattie</p>
<p><strong>Tuesday September 6th Track 1 </strong><br />
09.30 &#8211; 13.00 LOAD TESTING FOR DEVELOPERS, Simon Brown<br />
14.00 &#8211; 17.30 CI TO CONTINUOUS DELIVERY, Paul Stack</p>
<p><strong>Tuesday September 6th Track 2 </strong><br />
09:30 &#8211; 13:00 TEST-DRIVEN DEVELOPMENT IN JAVASCRIPT, Damjan Vujnovic<br />
14.00 &#8211; 17.30 ADVANCED WEBSHARPER TUTORIAL, Adam Granicz</p>
<p><strong>Wednesday September 7th Track 1 </strong><br />
09.30 &#8211; 13.00 RESTFUL WEB SERVICE DEVELOPMENT IN .NET, Ian Robinson<br />
14.00 &#8211; 17.30 INTRO TO NANCY &amp; SIMPLE.DATA, Mark Rendle &amp; Steven Robbins</p>
<p><strong>Wednesday September 7th Track 2 </strong><br />
09.30 &#8211; 13.00 ASYNC METHODS IN C#5, Jon Skeet<br />
14.00 &#8211; 17.30 TBD</p>
<p><strong>More information and registration: </strong><br />
<a href="http://skillsmatter.com/event/open-source-dot-net/progressive-dot-net-tutorials-2011/js-2405" target="_blank">Find more information about this years Progressive .NET Tutorials here</a>. If you would like to <a href="https://skillsmatter.com/register-online/conf/849/js-2372" target="_blank">register</a>, don&#8217;t forget to <a href="http://skillsmatter.com/event/open-source-dot-net/progressive-dot-net-tutorials-2011/js-2372" target="_blank">claim your £50 discount of the ticket price, by quoting Promocode: PROGNET50 when registering</a>.</p>
<div class='wpfblike' ><fb:like href='http://userinexperience.com/?p=662' layout='default' show_faces='true' width='400' action='like' colorscheme='light' send='false' /></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=CzdxwyXiiMU:bKhTCDONOxg:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?i=CzdxwyXiiMU:bKhTCDONOxg:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=CzdxwyXiiMU:bKhTCDONOxg:dnMXMwOfBR0"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?d=dnMXMwOfBR0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=CzdxwyXiiMU:bKhTCDONOxg:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?i=CzdxwyXiiMU:bKhTCDONOxg:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/userinexperience/tYGT/~4/CzdxwyXiiMU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://userinexperience.com/?feed=rss2&amp;p=662</wfw:commentRss>
		<slash:comments>5</slash:comments>
		<feedburner:origLink>http://userinexperience.com/?p=662</feedburner:origLink></item>
		<item>
		<title>KnockoutJS and Strongly-Typed Helpers in ASP.NET MVC</title>
		<link>http://feedproxy.google.com/~r/userinexperience/tYGT/~3/K2FnloH1jKY/</link>
		<comments>http://userinexperience.com/?p=656#comments</comments>
		<pubDate>Wed, 27 Jul 2011 18:47:23 +0000</pubDate>
		<dc:creator>bsatrom</dc:creator>
				<category><![CDATA[development]]></category>
		<category><![CDATA[asp.net]]></category>
		<category><![CDATA[asp.net mvc]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[knockout]]></category>
		<category><![CDATA[knockoutJS]]></category>
		<category><![CDATA[mvvm]]></category>

		<guid isPermaLink="false">http://userinexperience.com/?p=656</guid>
		<description>&lt;p&gt;A few weeks ago, &lt;a href="http://userinexperience.com/?p=618"&gt;I posted a screencast overview&lt;/a&gt; of &lt;a href="http://knockoutjs.com/"&gt;KnockoutJS&lt;/a&gt;, a JavaScript MVVM framework. Shortly after that, I published &lt;a href="http://userinexperience.com/?p=633"&gt;this post&lt;/a&gt;, where I share my take on using Knockout in a more unobtrusive style, eschewing the standard data-bind syntax in favor of a modelBinder object that creates those bindings for me.&lt;/p&gt; [...]</description>
			<content:encoded><![CDATA[<p>A few weeks ago, <a href="http://userinexperience.com/?p=618">I posted a screencast overview</a> of <a href="http://knockoutjs.com/">KnockoutJS</a>, a JavaScript MVVM framework. Shortly after that, I published <a href="http://userinexperience.com/?p=633">this post</a>, where I share my take on using Knockout in a more unobtrusive style, eschewing the standard data-bind syntax in favor of a modelBinder object that creates those bindings for me.</p>
<p>In both cases, I presented the markup in a pretty server-framework-agnostic way. Meaning specifically that I didn’t use any ASP.NET MVC HTML helpers. I did this on purpose, and to clearly illustrate that KnockoutJS cares not about your server framework. You can use it with ASP.NET MVC, Rails, PHP, Python, whatever.</p>
<p>I did, however, receive a few comments suggesting that I had left the reader or screencast watcher with the impression that Knockout cannot be used with the strongly-typed HTML helpers provided with ASP.NET MVC. This is not the case, so I wanted to take a moment and append my previous post and screencast with some quick examples of using Knockout alongside the ASP.NET MVC strongly-typed helpers.</p>
<p>For starters, let’s take a look at the Speaker Info fieldset from the Add Speaker page I used both in the <a href="http://userinexperience.com/?p=618">original screencast</a> and my <a href="http://userinexperience.com/?p=633">alternative binding post</a>.</p>
<p><script src="https://gist.github.com/1110056.js?file=data-bind.html"></script></p>
<p><em>Note: If you cannot view the embedded Gist above for any reason, click <a href="https://raw.github.com/gist/1110056/d32414b5fbad994ecd2faa9a733ccbed7a075954/data-bind.html">here</a> to view the embedded code.</em></p>
<p>Modifying this to use my strongly-typed helper methods in ASP.NET MVC is easy. I just need to use the appropriate helper method, and then set my data-bind attributes as properties in the anonymous object parameter MVC uses for HTML attributes.</p>
<p><script src="https://gist.github.com/1110056.js?file=data-bind_withMVC.html"></script></p>
<p><em>Note: If you cannot view the embedded Gist above for any reason, click <a href="https://raw.github.com/gist/1110056/b21f77c536ba57aa7dbdb81fb20c88821acf2b1e/data-bind_withMVC.html">here</a> to view the embedded code.</em></p>
<p><strong><em>They key thing to note here is that all of my data-bind properties have been changed to data_bind (underscore instead of dash)</em></strong>. Properties in C# cannot contain dashes (-), but underscores are allowed (_), and, by convention, ASP.NET MVC will convert any underscores appearing in the HTML attributes object to dashes.</p>
<p>If I’m using KnockoutJS with the default data-bind syntax—as most are—this is all I need to do to use Knockout and MVC strongly-typed helpers happily together.</p>
<p>If, on the other hand, I’m using Knockout with Unobtrusive bindings, as I <a href="http://userinexperience.com/?p=633">detail in my previous post</a>, I need to make a few difference changes. For unobtrusive bindings in Knockout, I’m not specifying data-bind attributes myself, so I can remove those from my helpers, like so:</p>
<p><script src="https://gist.github.com/1110056.js?file=MVCandUnobtrusive.html"></script></p>
<p><em>Note: If you cannot view the embedded Gist above for any reason, click <a href="https://raw.github.com/gist/1110056/0511737eb49adb8cc9a9e0dab9a23cc53e2ee42b/MVCandUnobtrusive.html">here</a> to view the embedded code.</em></p>
<p>With unobtrusive binding in Knockout, my JavaScript binding object contains a list of fields and bindings to create when the page executes. When the bindings are created, I use a convention to minimize typing so that when my modelBinder sees an input binding of ‘name’, it knows to look for a HTML field with an id=’name’ and, if found, sets the data-bind attribute to “value: name.”</p>
<p>When I’m using the ASP.NET MVC strongly-typed helpers with unobtrusive bindings, this convention won’t work as previously described, because ASP.NET MVC auto-generates field name and id attributes for me, and it uses the Model property name to do so. Since the model property for “Name” is capitalized, my convention breaks.</p>
<p>There are several ways to fix this. I could capitalize the first letter of all of my ViewModel properties in JavaScript, but that would be too easy. Instead, I decided to modify my modelBinder to support first-letter capitalization differences between my HTML and my ViewModel.</p>
<p><script src="https://gist.github.com/1110056.js?file=modelBinder.js"></script></p>
<p><em>Note: If you cannot view the embedded Gist above for any reason, click <a href="https://raw.github.com/gist/1110056/568861dbf92ab78861727d43225e3b890d49c753/modelBinder.js">here</a> to view the embedded code.</em></p>
<p>To my existing modelBinder object, I added a new private method called getElement, which will attempt to select an element from the DOM given the provided id. If it cannot find that element, it performs a simple capitalization on the first letter and tries again. Once I modify the setBinding method to call this new method, I’m good to go, and I can now used the MVC-generated id attributes with my existing unobtrusive Knockout bindings.</p>
<p>Simple as that! Whether I’m using the default data-bind syntax in KnockoutJS, or doing <a href="http://userinexperience.com/?p=633">something crazy</a>, the ASP.NET MVC strongly-typed helpers and <a href="http://knockoutjs.com/">KnockoutJS</a> can play together quite nicely.</p>
<pre><em>Click <a href="https://gist.github.com/1110056">here</a> for the complete Gist used in this post.</em></pre>
<div class='wpfblike' ><fb:like href='http://userinexperience.com/?p=656' layout='default' show_faces='true' width='400' action='like' colorscheme='light' send='false' /></div><div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=K2FnloH1jKY:qH0mGK6DVAA:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?i=K2FnloH1jKY:qH0mGK6DVAA:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=K2FnloH1jKY:qH0mGK6DVAA:dnMXMwOfBR0"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?d=dnMXMwOfBR0" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/userinexperience/tYGT?a=K2FnloH1jKY:qH0mGK6DVAA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/userinexperience/tYGT?i=K2FnloH1jKY:qH0mGK6DVAA:F7zBnMyn0Lo" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/userinexperience/tYGT/~4/K2FnloH1jKY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://userinexperience.com/?feed=rss2&amp;p=656</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://userinexperience.com/?p=656</feedburner:origLink></item>
	</channel>
</rss>

