A month ago Gordon L. Hempton wrote about twelve JavaScript frameworks in the Client-Side MVC space. His rating criteria were different to mine. One that really sticks out is that I like the logic not forcing the template HTML to migrate to <script> tags. Depending on the sophistication of the app, I like to be able to see the app in a browser or DreamWeaver when the framework is not running. It gives me a way of gauging the composition of the app. It appeals to a WYSIWYG leaning that I have. I like my UI frameworks to be built for designability if you like.

Addy Osmani has a number of implementation of a Todo app on a Github Pages site. For composition purposes, this really is the definitive place presently. Using those, I’m going to scrutinize the HTML and how it the app looks without JavaScript. I checked out Addy’s repo, then recursively deleted all javascript files, before loading the main page for each into a browser.

Angular

In the browser:

In DreamWeaver:

What I like is that I can see the repeating item in it’s mustache templating style: {᠎{todo.content}᠎}. What I don't like is that I can't see the "X item(s) left" message, that live updates. Angular leaves your template HTML in-situ - where it would be if there were no angular logic happening to it. Here's the todo list in code (ng:repeat` is the looping construct):

<div id="todos">
    <ul id="todo-list">
      <li class="todo" ng:class="'editing-' + todo.editing + ' done-' + todo.done" ng:repeat="todo in todos">
        <div class="display">
          <input class="check" type="checkbox" name="todo.done" / >
          <div ng:click="editTodo(todo)" class="todo-content"> {‌{ todo.content }} </div>
          <span class="todo-destroy" ng:click="removeTodo(todo)"></span>
       </div>
      <div class="edit">
        <form ng:submit="finishEditing(todo)">
            <input class="todo-input" my:focus="todo.editing" my:blur="finishEditing(todo)" name="todo.content" type="text">
        </form>
      </div>
      </li>
    </ul>
</div>

Backbone

Missing is the repeating Todos. Instead, in the page, there is a @<ul id="todo-list"></ul>@ placeholder for Backbone to insert child elements to later. Here’s the template, in canonical Backbone (hidden inside a <script> tag):

	<!-- Templates -->

    <script type="text/template" id="item-template">
      <div class="todo <%= done ? 'done' : '' %>">
        <div class="display">
          <input class="check" type="checkbox" <%= done ? 'checked="checked"' : '' %> />
          <label class="todo-content"><%= content %></label>
          <span class="todo-destroy"></span>
        </div>
        <div class="edit">
          <input class="todo-input" type="text" value="<%= content %>" />
        </div>
      </div>
    </script>

There’s no ng:repeat equivalent code in the HTML, that’s done in JavaScript.

Knockout

I’m not sure if the way the Todo app was coded with knockout is the only way, but the line that would show an individual Todo item from the list of Todos looks like @<div class="todo-content" data-bind="text: content, event: { dblclick: edit }" style="cursor: pointer;"></div>@. Without the frameworks attached, there’s nothing to see for that DIV. If I hard-code TODO-CONTENT in that DIV, and reload, then it looks more like Angular:

It is nice to see the inline templating rather than the template in a <script> tag like Angular:

<div id="todos">
    <div data-bind="visible: todos().length">
        <input id="check-all" class="check" type="checkbox" data-bind="checked: allCompleted" />
        <label for="check-all">Mark all as complete</label>
    </div>
    <ul id="todo-list" data-bind="foreach: todos">
        <li data-bind="css: { editing: editing }">
            <div class="todo" data-bind="css: { done : done }">
                <div class="display">
                    <input class="check" type="checkbox" data-bind="checked: done" />
                    <div class="todo-content" data-bind="text: content, event: { dblclick: edit }" style="cursor: pointer;"></div>
                    <span class="todo-destroy" data-bind="click: $root.remove"></span>
                </div>
                <div class="edit">
                    <input class="todo-input" data-bind="value: content, valueUpdate: 'afterkeydown', enterKey: stopEditing, event: { blur: stopEditing }"/>
                </div>
            </div>
        </li>
    </ul>
</div>

Knockback

Screenshot - as Backbone’s

Knockback is a very pragmatic merger of the best features of Backbone and Knockout. Unlike many of the websites for these technologies, Knockback’s site tries to instantly sell the technology to the developer. Like Backbone, Knockback keeps templates separate. Here’s their todo list: @<ul class="todo-list" data-bind="template: {name: 'item-template', foreach: todo_list.todos}"></ul>@. Here is the template for that:

<script type="text/x-jquery-tmpl" id="item-template">
  <li>
    <div class="todo" data-bind="css: {done: done, editing: edit_mode}">
      <div class="display">
        <input class="check" type="checkbox" data-bind="checked: done" />
        <div class="todo-text" data-bind="text: text, dblclick: toggleEditMode"></div>
        <div class="todo-destroy" data-bind="click: destroyTodo"></div>
      </div>
      <div class="edit">
        <input class="todo-input" type="text" data-bind="value: text, event: {keyup: onEnterEndEdit}" />
      </div>
    </div>
  </li>
</script>

Broke

Screenshot - as Backbone’s

The template logic is in JavaScript files, which I really don’t like:

todo.templates= {
    list: '<ul class="items">' +
        '' +
    '</ul>'
    ,view: genericTaskTemplate
    ,create: ''
    ,update: '<li class="item" data-app_label="{‌{ task.__class__._meta.appLabel }}" data-model="{‌{ task.__class__._meta.modelName }}" data-pk="{‌{ task.pk }}">'+
        '<form action="#/task/update/{‌{ task.pk }}/">' +
            '<input type="text" name="title" value="{‌{ task.title }}" />' +
        '</form>' +
    '</li>'
};

Sammy

Screenshot - as Backbone’s

The template logic is in separate .template file, which seems unnecessary given it’s just an extended HTML format.

<h2 data-type="list" data-id="<%= list.id %>"></h2>
<% $.each(todos, function(index, todo) { %>
  <li data-type="todo" data-id="<%= todo.id %>" class="<%= todo.done ? 'done' : '' %>">
    <div class="todo">
      <div class="display">
        <input class="check" type="checkbox" <%= todo.done ? 'checked' : '' %>/>
        <span class="trashcan" data-type="todo" data-id="<%= todo.id %>"></span>
        <span contenteditable="true" data-type="todo" data-id="<%= todo.id %>" class="todo-item"><%= todo.name %></span>
      </div>
    </div>
  </li>
<% }); %>

Ember

<script type="text/x-handlebars">
{{#view id="todos"}}
  {{#collection id="todo-list" contentBinding="Todos.todosController" tagName="ul" itemClassBinding="content.isDone"}}
    {{view Ember.Checkbox titleBinding="content.title" valueBinding="content.isDone"}}
  {{/collection}}
{{/view}}
</script>

You should know by now that I’m really going to like Ember’s templating. From my point of view this one is in last position!

ExtJs

Screenshot - as Backbone’s

The template logic is in JavaScript files. ExtJs is not so much HTML augmented with Client-Side MVC capability like the rest are. It’s more of a departure from HTML and a reality built on it’s own DSL which can be highly attractive in its own right. I’m only including it because Addy has it on his list. In this case, the ExtJS grammar is showing inlined HTML in the pertinent list of Todos section:

Ext.define('Todo.view.TaskList' , {
    store: 'Tasks',
    loadMask: false,
    itemSelector: 'div.row',
    extend: 'Ext.view.View',
    alias : 'widget.taskList',
    tpl: Ext.create('Ext.XTemplate',
        '<tpl for=".">',
            '<div class="row">',
                '<input type="checkbox" {[values.checked ? "checked" : ""]} />',
                '<span class="{[values.checked ? "checked" : ""]}">{label}</span>',
            '</div>',
        '</tpl>',
        {compiled: true}
    )
});

Fidel

Screenshot - as Backbone’s

<script type="text/template" id="item-template">
  <li class="todo {!= todo.done ? 'done' : '' !}" data-todoid="{!= todo.guid !}">
    <div class="display">
      <input class="check" type="checkbox" {!= todo.done ? 'checked="checked"' : '' !} />
      <div class="todo-content">{!= todo.name !}</div>
      <span data-action="destroyTodo" class="todo-destroy"></span>
    </div>
    <div class="edit">
      <input class="todo-input" type="text" value="" />
    </div>
  </li>
</script>

Like Backbone, or this example, there’s no ng:repeat equivalent code in the HTML. It is done in JavaScript instead.

JavaScriptMVC

Screenshot - like Backbone’s. Template nesting (inside <script> tags) looks powerful:

<script type='text/ejs' id='todosEJS'>
	<% for(var i =0; i < this.length ; i++){ %>
		<li <%= this[i]%>>
		<%= $.View('todoEJS',this[i] ) %>
		</li>
	<% } %>
</script>
<script type='text/ejs' id='todoEJS'>
	<input type='checkbox' name='complete' 
		<%= this.complete ? "checked" : "" %>>
	<span class=''><%= (this.text || "empty todo ...")%></span>
	<span class='destroy'></span>
</script>

JQuery with Handlebars

Screenshot - like Backbone’s. Separate template again:

<script type="text/x-handlebars-template" id="todo-template">
{{#this}}
<li {{#if done}}class="done"{{/if}} data-id="{‌{id}}">
	<div class="view">
		<input class="toggle" type="checkbox" {{#if done}}checked{{/if}}>
		<label>{{title}}</label>
		<a class="destroy"></a>
	</div>
	<input class="edit" type="text" value="{‌{title}}">
</li>
{{/this}}
</script>

Spine

Screenshot - as Backbone’s. Template again leverages <script> again but is inline with the HTML that contains it. Looping is not in the grammar though, so is performed by JavaScript as the template is acted on.

<div class="items">
  <script type="text/html" id="task-template">
    <div class="item {‌{if done}}done{‌{/if}}">
      <div class="view" title="Double click to edit...">
        <input type="checkbox" {{if done}}checked="checked"{{/if}}>
        <span>${name}</span> <a class="destroy"></a>
      </div>

      <form class="edit">
        <input type="text" name="name" value="${nam‌e}">
      </form>
    </div>
  </script>
</div>

YUI Library

Screenshot as Backbone’s. As is the norm the template is in a &lt;script> tag, with the looping in Javascript.

<script type="text/x-template" id="todo-item-template">
    <div class="todo-view">
        <input type="checkbox" class="todo-checkbox" {checked}>
        <span class="todo-content" tabindex="0">{text}</span>
    </div>

    <div class="todo-edit">
        <input type="text" class="todo-input" value="{text}">
    </div>

    <a href="#" class="todo-remove" title="Remove this task">
        <span class="todo-remove-icon"></span>
    </a>
</script>

Batman

(added 14 Feb)

Batman’s Todo is in it’s own GitHub Repo, and not Addy’s one (yet). Batman uses CoffeeScript instead of JavaScript, which is alluring in its own right. Here’s the screenshot:

Like Knockout, the bound field is not visible in design mode. Similarly, the number of items statistic is also missing. Lastly the <a> tag for ‘delete’ is missing a and thus does not appear as a link. The other frameworks were using fancy images for this, so that is probably the same for them too, but not apparent in their demos. I’ve hacked those things in (hard-coded) and taken another screenshot for your enjoyment:

The good news (to me) is that the Batman extends HTML like Angular and Knockout.

Conclusion.

Only Angular, Knockout and Batman allow me to see what’s what in design mode, and see the mechanism of looping in the extended HTML grammar. That’s the opposite of one of Gordon L. Hempton’s “good” criteria.

It is also interesting that one of these has Microsoft patronage, and another has Google support. I wonder if there’s a Dart port “Dangular” in the future from the Google fellows :-P

After thought.

Angular’s Todo list implementation could be even better in design mode, if it encoded stats like so:

<div id="todo-stats">
  <span class="todo-count" ng:show="hasTodos()">
	{‌{statsCount()}} item{‌{statsPlural()}} left.
  </span>
  <span class="todo-clear" ng:show="hasFinishedTodos()">
    <a ng:click="clearCompletedItems()">
      Clear {‌{finishedTodos()}} completed item{‌{finsihedPlural()}}
    </a>
  </span>
</div>

Instead of the way it is now:

<div id="todo-stats">
  <span class="todo-count" ng:show="hasTodos()">
    <ng:pluralize count="remainingTodos()" when="{'0' : 'No items left.', '1': '1 item left.', 'other' : '{} items left.' }">
    </ng:pluralize>
  </span>
  <span class="todo-clear" ng:show="hasFinishedTodos()">
    <a ng:click="clearCompletedItems()">
      Clear <ng:pluralize count="finishedTodos()" when="{'1': '1 completed item', 'other' : '{} completed items' }"></ng:pluralize>
    </a>
  </span>
</div>

We’d get a design mode view like so:

Apr 19, 2012: This article was syndicated by DZone



Published

February 13th, 2012
Reads: 36,999

Syndicated by DZone.com
Reads:

Tags

Categories

Comments formerly in Disqus, but exported and mounted statically ...


Mon, 13 Feb 2012Addy Osmani

Excellent post. Would love to get some of your input from this in on the TodoMVC repo as we're currently rewriting all of the Todo apps to be more consistant in implementation (and design). Anything we can do to better minimize the templating differences so people can focus on the framework implementations themselves would be great.

Mon, 13 Feb 2012allanebdrup

I'm thinking about this exact same thing. Getting a good view of the html in a html editor without running JavaScript.
I'm trying out an experiment with a new open source "programming language" for designers, so you don't have to struggle with JavaScript.
It's all simple declarations inside the HTML.
I would love to hear what you think, you can see my experiment here:
http://ddeclr.appspot.com/

Edit: Inspired by all these todo-list apps, I did a todo-list example in declr as well and gave a link back to this blogpost.

Tue, 14 Feb 2012Boris Smus

Thanks for the post! I'm curious what your development workflow is. I for one never find myself wanting to preview how my JS-heavy application looks without JavaScript enabled, so your criteria seems artificial at first glance.

Tue, 14 Feb 2012Guest

Care to throw Batman into the mix?

Wed, 15 Feb 2012Anselmo Silva

Wat! WYSIWYG? Why not just some fake data and watch it on the browser ... isn't that easy?

Wed, 15 Feb 2012Tim

regarding this point:

One that really sticks out is that I like the logic not forcing the template HTML to migrate to <script> tags. Depending on the sophistication of the app, I like to be able to see the app in a browser or DreamWeaver when the framework is not running.

have you looked at https://github.com/hij1nx/weld and its successor https://github.com/flatiron...

Wed, 15 Feb 2012brandon

Dreamweaver? Ew... Real developers don't use WYSIWYG editors.

Thu, 16 Feb 2012Greg MacLellan

One of the major problems with WYSIWYG design mode is it almost inevitably leads you to having crappy markup. Now, I haven't touched DreamWeaver in years, so maybe the tools are better now, I can't really say. I've played with VisualStudio's design mode to create WebForm apps within the last couple years, and worse, had to maintain webforms apps with their horrible in-line styles and superfluous markup, and it's a nightmare.

The idea of looking at it in HTML though is you retain full control and can create markup that makes sense. Especially when coupled with something like less, you can write very clean and easy to maintain HTML and style it with CSS. You'll necessarily have to wrap some content with extra div's to be able to apply CSS correctly, but if you're using a CSS framework like Twitter's Boostrap, even this is pretty painless.

One of the other problems is even if you don't care about clean HTML/CSS, WYSIWYG eventually breaks down as the app gets complex. What happens when you want multi-language support? If/else blocks where parts of the UI are different depending on conditions? Often you can't display both because they are displayed in the same spot, and your design doesn't have extra room (for example: If I'm logged in, I see "Hi your name : Preferences | Inbox | Logout" but otherwise "Login | Signup"). Designing "responsive" layouts that dynamically change as you resize from desktop to mobile? Not saying this stuff can't be done in WYSIWYG, I just personally think there comes a point (quickly) where you spend more effort trying to get things to work/display correctly in WYSIWYG than you do actually building the actual logic, and as soon as you hit that point you're wasting your time.

These days, I think most web dev's are just dropping to HTML and trying to go for clean markup over usability in WYSIWYG. This is why you see such "bad" results when you're using WYSIWYG editors: most people aren't designing for WYSIWYG.

Fri, 17 Feb 2012@sbussard

imo weld beats them all for cleanliness https://github.com/hij1nx/weld

Tue, 12 Jun 2012Sutikshan Dubey

Hi Paul,
I am sure, by now you might have guided your teams in development of serious business app (screens with Tree-View controls, data grid) aka real busy screens with loads of business logic. How was the experience with Angular. Would you recommend something else.

Tue, 19 Feb 2013Jamietshaw

FYI, the text on your site doesn’t print very well.

Fri, 27 Jun 2014Evan

I have the same opinion as you. "Real developers don't use WYSIWYG editors"? Nah, this is wrong. If they do, I hope they don't use any text editor anymore, because every character they typed they can see!!!