{"id":1237,"date":"2012-12-02T22:12:29","date_gmt":"2012-12-03T05:12:29","guid":{"rendered":"http:\/\/thesmithfam.org\/blog\/?p=1237"},"modified":"2019-08-12T07:15:07","modified_gmt":"2019-08-12T13:15:07","slug":"angularjs-is-too-humble-to-say-youre-doing-it-wrong","status":"publish","type":"post","link":"https:\/\/thesmithfam.org\/blog\/2012\/12\/02\/angularjs-is-too-humble-to-say-youre-doing-it-wrong\/","title":{"rendered":"AngularJS is too humble to say you&#8217;re doing it wrong"},"content":{"rendered":"<p>For years, web application developers have used DOM manipulation tools like <a href=\"http:\/\/jquery.com\/\">jQuery<\/a> to control their user interface. Astute developers have taken it to the next level with client-side templating tools like <a href=\"http:\/\/mustache.github.com\/\">Mustache<\/a> and <a href=\"http:\/\/handlebarsjs.com\/\">Handlebars.js<\/a> to build sophisticated user interfaces on the client side.<\/p>\n<p>And then <a href=\"http:\/\/angularjs.org\/\">AngularJS<\/a> came along.<\/p>\n<p>And we all realized we&#8217;ve been doing it wrong.<\/p>\n<p>Way wrong.<\/p>\n<h2>The Old Way<\/h2>\n<p>Remember before you discovered AngularJS? Back when your code was organized like this:<\/p>\n<ol>\n<li>HTML that defines your page<\/li>\n<li>JavaScript that downloads AJAX data<\/li>\n<li>HTML that defines a client side template<br \/>(yeah, this: <tt>&lt;script type=\"text\/html\"&gt;...&lt;\/script&gt;<\/tt>)<\/li>\n<li>JavaScript that renders the client-side template<\/li>\n<li>JavaScript that injects the rendered template HTML into the DOM<\/li>\n<\/ol>\n<p>You thought that was pretty cool. &#8220;Hey look,&#8221; you said, &#8220;I&#8217;ve off-loaded template rendering to the browser!&#8221;. Yeah, you were pretty cool.<\/p>\n<p>But then AngularJS showed you how you were wrong. You could accomplish the same client-side magic with a <strong>lot<\/strong> less code.<\/p>\n<h2>The New Way<\/h2>\n<p>Under AngularJS, your code can be organized like this:<\/p>\n<ol>\n<li>HTML that defines your page and client-side templates inline<\/li>\n<li>JavaScript that downloads AJAX data<\/li>\n<\/ol>\n<p>How does that even work? I mean, you&#8217;ve got like <strong>less than half of the bullet points<\/strong> now.<\/p>\n<p>The answer: <strong>Data Binding<\/strong>.<\/p>\n<p>Data Binding is the secret sauce of AngularJS (along with a couple dozen other delicious spices and condiments). Oh, and it&#8217;s not a secret at all. The code is actually <a href=\"https:\/\/github.com\/angular\/angular.js\">pretty easy to read<\/a>, despite being pure magic awesomeness on environmentally-friendly steroids.<\/p>\n<h2>Shall We Do Show-and-Tell?<\/h2>\n<h3>The old way<\/h3>\n<p>This should be very familiar. You&#8217;ve got an HTML page, and you want to add some dynamic content with a client-side template:<\/p>\n<p>Here&#8217;s the page HTML:<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;html&gt;\r\n  &lt;body&gt;\r\n    &lt;div id=&quot;my-list-of-animals&quot;&gt;\r\n    &lt;\/div&gt;\r\n  &lt;\/body&gt;\r\n&lt;\/html&gt;\r\n<\/pre>\n<p>Let&#8217;s use Handlebars for the client-side template:<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;script id=&quot;animal-template&quot; type=&quot;text\/x-handlebars-template&quot;&gt;\r\n  &lt;div&gt;\r\n    &lt;div&gt;{{animalName}}&lt;\/div&gt;\r\n    &lt;div&gt;{{favoriteFood}}&lt;\/div&gt;\r\n  &lt;\/div&gt;\r\n&lt;\/script&gt;\r\n<\/pre>\n<p>And you need some JavaScript to download the AJAX data, render the client side template, and inject it into the DOM:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n$.get(&quot;\/api\/animals\/&quot;, function(response) {\r\n  var source = $(&quot;#animal-template&quot;).html();\r\n  var template = Handlebars.compile(source);\r\n  $.each(response, function() {\r\n    var html = template(this);\r\n    $(&quot;#my-list-of-animals&quot;).append(html);\r\n  });\r\n});\r\n<\/pre>\n<p>Put all that together somehow, and wow, that&#8217;s a lot of code to do something that should be very simple.<\/p>\n<p>That covers all 5 bullet points above. You&#8217;re still cool, right?<\/p>\n<h3>The AngularJS Way<\/h3>\n<p>Remember how there are only two bullet points. Well, here they are:<\/p>\n<p>First, your page HTML:<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n&lt;html ng-app&gt;\r\n  &lt;body&gt;\r\n    &lt;div ng-controller=&quot;MyAnimalController&quot;&gt;\r\n      &lt;div ng-repeat=&quot;animal in animals&quot;&gt;\r\n        &lt;div&gt;{{animal.animalName}}&lt;\/div&gt;\r\n        &lt;div&gt;{{animal.favoriteFood}}&lt;\/div&gt;\r\n      &lt;\/div&gt;\r\n    &lt;\/div&gt;\r\n  &lt;\/body&gt;\r\n&lt;\/html&gt;\r\n<\/pre>\n<p>Did you see that? There&#8217;s no &lt;script&gt; hack. The template is right inside the page! Right there. In-line. Right where you wanted it all along, but never had the guts to ask. But I digress.<\/p>\n<p>Second, the JavaScript:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nfunction MyAnimalController($scope, $http) {\r\n  $http.get(&quot;\/api\/animals\/&quot;).success(function(response) {\r\n    $scope.animals = response;\r\n  });\r\n}\r\n<\/pre>\n<p>And that&#8217;s it. It really is glorious. The AngularJS team really distilled the client-side template problem to its essence and produced an elegant solution. But don&#8217;t take my word for it. Check out the win list below.<\/p>\n<h2>Win List<\/h2>\n<p>Look at all the prizes you won by using AngularJS:<\/p>\n<ol>\n<li><b>CSS classes are just for CSS now.<\/b><br \/>\nYou used to abuse the HTML class attribute so you could find elements in the DOM with jQuery. Now, your class attributes are <b>only<\/b> for CSS. You don&#8217;t have to wonder anymore whether a particular class is used by JavaScript or CSS. The answer is always CSS: The way nature intended<\/li>\n<li><b>No &lt;script&gt; hacks.<\/b><br \/>\nYou don&#8217;t have to trick the browser into ignoring your client-side templates anymore. Don&#8217;t you feel cleaner?<\/li>\n<li><b>Client side templates are cohesive with your page<\/b><br \/>\nYou used to have a pile of client-side template files scattered throughout your project, or all crammed into your HTML &lt;head&gt;. Now they are right in the page, exactly where you wanted to read them in the first place.<\/li>\n<li><b>You don&#8217;t have to name every template<\/b><br \/>\nYou used to name each &lt;script&gt; element with an &#8220;id&#8221; attribute to make it findable by jQuery. You can nuke those strings in your JavaScript and HTML, and not worry about them getting out-of-sync.<\/li>\n<li><b>You have control over the scope of your JavaScript<\/b><br \/>\nPreviously you had to worry about your jQuery selectors casting too wide a net and selecting elements beyond what you intended. For example, suppose there <b>happened<\/b> to be an element in the page somewhere with class &#8220;animal&#8221;, and you didn&#8217;t know about it. Then you wrote a jQuery selector like $(&#8220;.animal&#8221;). <b>Boom<\/b>, you just mofidied an element you didn&#8217;t intend to. With AngularJS, your JavaScript <b>cannot<\/b> reach outside the ng-controller demarkation.<\/li>\n<li><b>You don&#8217;t have to remember to clean up HTML on refresh<\/b><br \/>\nLet&#8217;s say I want to refresh the animal list in this example. Under jQuery, I have to remember to do this: <tt>$(\"#my-list-of-animals\").html(\"\")<\/tt> before I start <tt>.append()<\/tt>ing new animals. In AngularJS, I just replace <tt>$scope.animals<\/tt> with the newly downloaded list, and it automatically clears out the old HTML.<\/li>\n<li><b>Your JavaScript is cleaner<\/b><br \/>\nYour JavaScript has no CSS selectors anymore. It used to be littered with strings to locate elemenents in the DOM. Now it&#8217;s just got business logic. Pure, sweet business logic.<\/li>\n<li><b>You can unit test your JavaScript without a DOM<\/b><br \/>\nI should have mentioned this <b>first<\/b>. Notice how my JavaScript has no knowledge of a DOM? It doesn&#8217;t even know there&#8217;s HTML involved at all. This makes it much easier to unit test, because you don&#8217;t need to load a big chunk of fixture HTML to test your JavaScript. AngularJS provides <a href=\"http:\/\/docs.angularjs.org\/guide\/dev_guide.unit-testing\">some great docs on testing<\/a> too.\n<\/li>\n<\/ol>\n<h2>Almost Too Humble<\/h2>\n<p>I started reading about AngularJS and re-working parts of my projects to use it in earnest only a few weeks ago. A day into the effort, the light bulb went on for me:<\/p>\n<p><center><b style=\"font-size: 120%\">I&#8217;ve been doing this all wrong<\/b><\/center><\/p>\n<p>At that point, I started to wonder why the AngularJS team didn&#8217;t write article after article with the same title: &#8220;You&#8217;re Doing It Wrong&#8221;. And that&#8217;s what inspired me to write this.<\/p>\n<p>So there you have it. An opinionated blog post about an opinionated framework.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>For years, web application developers have used DOM manipulation tools like jQuery to control their user interface. Astute developers have taken it to the next level with client-side templating tools like Mustache and Handlebars.js to build sophisticated user interfaces on the client side. And then AngularJS came along. And we all realized we&#8217;ve been doing [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-1237","post","type-post","status-publish","format-standard","hentry","category-code-and-cruft"],"_links":{"self":[{"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/posts\/1237","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/comments?post=1237"}],"version-history":[{"count":39,"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/posts\/1237\/revisions"}],"predecessor-version":[{"id":1502,"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/posts\/1237\/revisions\/1502"}],"wp:attachment":[{"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/media?parent=1237"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/categories?post=1237"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/tags?post=1237"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}