TodoMVC with Web and jQuery
This page walks through the TodoMVC variant written with Web and jQuery. It shows the same model as TodoMVC with Silk, on the same page. Its view has the shape of TodoMVC with Web. One class binds and renders, and one widget shows a todo. Web builds, and jQuery does the rest. This page shows only what differs from the Web variant. It builds on TodoMVC with jQuery for jQuery’s own words.
Taking Web-JQuery in
The package imports 'amber/jquery/Web-JQuery' beside 'amber/web/Web'. Web-JQuery comes with @ambers/contrib-jquery 0.8.2, and brings Wrappers-JQuery along. It puts jQuery under Web, as the Web page says. A brush answers asJQuery. TagBrush fromJQuery: makes a brush on a jQuery, and HTMLCanvas onJQuery: a canvas that renders into one. A widget, a block and a string answer appendToJQuery:, which renders them into a jQuery.
The page
web-jquery.html is silk.html with its own title, its own bundle, and its own class to start, WebJQueryTodoApp. Its parts carry the hidden attribute as there.
The view
The view is the package TodoMVC-Web-JQuery, with two classes, WebJQueryTodoApp and WebJQueryTodoItem. It keeps the todos under todos-amber-web-jquery. WebJQueryTodoApp has three slots. todoList is the TodoList. app is a jQuery on the .todoapp section, and listElement one on the ul. start attaches it to '.todoapp' asJQuery. The bindings are those of the jQuery variant, find:, on:do:, val and prop:, and followRoute binds hashchange on window asJQuery.
Rendering
render renders the same five things as the Web variant. The list is emptied with jQuery, and each todo renders itself into it:
renderList
listElement empty.
todoList shownTodos do: [ :each | (WebJQueryTodoItem on: each in: self) appendToJQuery: listElement ]
appendToJQuery: sent to a widget makes a canvas on the jQuery and renders the widget on it. The counter is a block rendered the same way:
renderCount
| count |
count := app find: '.todo-count'.
count empty.
[ :html |
html strong: todoList activeCount.
html with: ' ', todoList activeCountLabel ] appendToJQuery: count
The three other things are jQuery’s, as in the jQuery variant. prop:value: sets hidden and checked, and each: with toggleClass:value: marks the links.
One todo
WebJQueryTodoItem is a Widget, with the four slots of WebTodoItem. Its renderOn: is that of WebTodoItem, line for line. The tag messages build the item, class: and the checked attribute set its state, and the on...: messages bind it. The widget keeps the brushes listItem and edit.
Editing
The editing goes through jQuery. asJQuery on a brush answers a jQuery on its element:
startEditing
listItem asJQuery addClass: 'editing'.
edit asJQuery val: todo title.
self bindEdit.
edit asJQuery trigger: 'focus'
addClass: adds one class and keeps the others. bindEdit binds Enter, Escape and blur on edit asJQuery, as JQueryTodoItem >> bindEdit does, and takes the blur handler off with off:with:. The Web variant has no word for that, and keeps a guard instead. This one does not need it.
What each point costs
The table of TodoMVC with Silk, for this variant:
| The specification says | Where it is | What it takes |
|---|---|---|
| Hide main and footer with no todos | renderVisibility |
two prop:value: |
| Focus the input on load | web-jquery.html |
autofocus, from the template |
| Enter adds, trimmed, empty ignored | bindNewTodo, TodoList >> add: |
one on:do:; the model trims |
| Mark all as complete | bindToggleAll, renderToggleAll |
one on:do:, one prop:value: |
| Mark all cleared after Clear completed | renderToggleAll, TodoList >> allAreCompleted |
nothing; the model answers false for no todos |
Toggle, class completed |
WebJQueryTodoItem >> renderOn:, WebJQueryTodoApp >> toggle: |
one onChange:, one class:, one attribute |
| Destroy button on hover | WebJQueryTodoItem >> renderOn:, WebJQueryTodoApp >> remove: |
one onClick:; the stylesheet shows the button |
| Double-click edits | WebJQueryTodoItem >> renderOn:, startEditing |
one onDblClick:, one method |
| Enter or blur saves, Escape cancels, empty destroys | WebJQueryTodoItem >> bindEdit, WebJQueryTodoApp >> retitle:to:, TodoList >> retitle:to: |
two on:do:; the model removes the todo |
| The counter, item or items | renderCount, TodoList >> activeCountLabel |
one block rendered; the model words it |
| Clear completed, hidden when none | bindClearCompleted, renderVisibility |
one on:do:, one prop:value: |
Persistence under todos-amber-web-jquery |
start, TodoStore |
one key; the model saves |
Routing, class selected, kept on reload |
followRoute, routeTo:, renderFilters |
one on:do: on the window, one fromRoute: per link |
Each thing the Web variant reaches the DOM for has a jQuery word here. Finding an element inside another is find:. Reading a value or a property is val and prop:, and setting one is prop:value:. One class among others is addClass:, a handler taken back is off:with:, and the window is window asJQuery. Nothing reaches past the two. The cost is two APIs on one element. The item builds with brushes and edits with jQueries, and asJQuery is the step between them, four times.
The tests of the view
WebJQueryTodoAppTest, in TodoMVC-Web-JQuery-Tests, answers attach:to: with a WebJQueryTodoApp attached to anElement asJQuery. The 25 tests of TodoAppTest are the same as for the other variants.
Running it
Open http://localhost:4000/web-jquery.html, and try it as TodoMVC with Silk says. The todos are in localStorage under todos-amber-web-jquery. The test runner of Helios runs the 25 tests of WebJQueryTodoAppTest on the page.