Skip to content

Commit ee9c95d

Browse files
committed
expand section 9 to explain the code a bit better ... #60
1 parent 26e661e commit ee9c95d

File tree

2 files changed

+86
-8
lines changed

2 files changed

+86
-8
lines changed

Diff for: examples/todo-list/todo-app.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ function render_main (model, signal) {
191191
return !item.done;
192192
case '#/completed':
193193
return item.done;
194-
default:
194+
default: // if hash doesn't match Active/Completed render ALL todos:
195195
return item;
196196
}
197197
})

Diff for: todo-list.md

+85-7
Original file line numberDiff line numberDiff line change
@@ -2939,31 +2939,109 @@ test.only('9. Routing > should allow me to display active/completed/all items',
29392939

29402940
#### 9. Routing _Implementation_
29412941

2942+
Given that we are using "hash" based routing,
2943+
where the content of the app changes in response to the hash portion of the URL
2944+
implementing routing is a matter of _filtering_ the Todo List items
2945+
in response to the hash.
2946+
2947+
There 3 steps to implementing this:
2948+
2949+
1. Create an Event Listener for the `window.onhashchange` event
2950+
which invokes `signal('ROUTE')`.
2951+
2952+
2. Create a `'ROUTE'` case in the `update` function
2953+
which sets the `model.hash` value.
2954+
2955+
3. Based on the `model.hash` value defined above,
2956+
filter the `model.todos`.
2957+
29422958
Since this is the _final_ quest in the TodoMVC/Todo List App,
2943-
the solution is _not_ included here.
2944-
Spend some time trying to make the test assertions pass.
2959+
the we encourage you to attempt to write this
2960+
before/without looking at the "solution".
2961+
2962+
Remember that you only want to write the _minimum_ code
2963+
necessary to make the test assertions pass.
29452964

29462965
If you get "_stuck_" consult the code in `todo-app.js`.
29472966

2948-
#### 9.1 Routing _Bonus_
29492967

2950-
As a _bonus_ level,
2951-
you can add the following event listener to your `subscriptions`
2952-
to make the router work when the url (hash) changes in the browser:
2968+
#### 9.1 Routing _Event Listener_
2969+
2970+
Add the following event listener to your `subscriptions`
2971+
to "listen" for when the URL hash changes:
2972+
29532973

29542974
```js
29552975
window.onhashchange = function route () {
29562976
signal('ROUTE')();
29572977
}
29582978
```
2959-
And the `'ROUTE'` `case` to your `update` function:
2979+
2980+
#### 9.2 ROUTE `case`
2981+
2982+
Add the `'ROUTE'` `case`
2983+
to your `update` function:
2984+
29602985
```js
29612986
case 'ROUTE':
29622987
new_model.hash = (window && window.location && window.location.hash) ?
29632988
window.location.hash : '#/';
29642989
break;
29652990
```
2991+
***OR***, if you are confident that your app
2992+
will _always_ run in a Web Browser with a `window.location.hash` property:
2993+
2994+
```js
2995+
case 'ROUTE':
2996+
new_model.hash = window.location.hash;
2997+
break;
2998+
```
29662999

3000+
#### But _Why...?_
3001+
3002+
**Question**: Why do we "copy" the `window.location.hash`
3003+
to `model.hash` instead of just "getting" it from `window.location.hash`
3004+
each time we need to know what the hash is? <br />
3005+
3006+
**Answer**: technically, we could _avoid_ having
3007+
the `'ROUTE'` case in `update` completely
3008+
and just use the `window.location.hash`
3009+
instead of `model.hash`,
3010+
the _reason_ we add this "step"
3011+
is that we want to have a "single source of truth" in the `model`.
3012+
This is a _good_ habit to have
3013+
as it makes _debugging_ your application
3014+
_much_ easier because you _know **exactly**_
3015+
what the "full state" of the application is/was at any point in time.
3016+
3017+
You will often read/hear the expression "_easier to **reason about**_",
3018+
all this means is that you can "work through" something in your head
3019+
without getting "confused" by having "too many things to keep track of".
3020+
3021+
3022+
#### 9.3 _Filter_ the `model.todos` based on `model.hash`
3023+
3024+
We need to do the filtering "_non-destructively_",
3025+
so it needs to happen in the **`view`** (_just before rendering_)
3026+
rather than
3027+
3028+
> _**Question**: is this "**logic in the view**"...?_ <br />
3029+
> _**Answer**: **Yes**, it is **presentation logic**.
3030+
The `view` function, **`render_main` in this case
3031+
is merely **filtering** the data **non-destructively** before rendering it.
3032+
Using `Array.filter` is a "fancy" (concise) way of writing an `if` statement.
3033+
`if` statements are "OK" in views because they are
3034+
"conditional presentation logic"
3035+
i.e. only show this section `if` a certain variable is set. <br />_
3036+
_By using `Array.filter` followed by `Array.map` we render a **subset**
3037+
of the `model.todos` **without** "**mutating**" the `model.todos` Array.
3038+
In other words if the URL hash is `'#/completed'`
3039+
the user only wants to see the "completed" items,
3040+
we don't want to "lose" the todos that are not yet complete,
3041+
we just want to "hide" them temporarily,
3042+
if we were to apply this filter in the `update` function it would
3043+
"lose" the other todos (i.e. destroy the data!)
3044+
the best way to filter data non-destructively is in the **view**_
29673045

29683046
# Done!
29693047

0 commit comments

Comments
 (0)