diff --git a/elmish.md b/elmish.md
index 513793d5..c89478fb 100644
--- a/elmish.md
+++ b/elmish.md
@@ -1797,13 +1797,109 @@ refer to the completed code:
+### `onclick` `attribute` to invoke the "dispatcher" when element clicked
+
+In order to allow click/tap interactions with buttons,
+we need to add an `onclick` attribute which then _invokes_ the desired update.
+
+Add the following _test code_ to your `test/elmish.test.js` file:
+```js
+test.only('elmish.add_attributes onclick=signal(action) events!', function (t) {
+ const root = document.getElementById(id);
+ elmish.empty(root);
+ let counter = 0; // global to this test.
+ function signal (action) { // simplified version of TEA "dispatcher" function
+ return function callback() {
+ switch (action) {
+ case 'inc':
+ counter++; // "mutating" ("impure") counters for test simplicity.
+ break;
+ }
+ }
+ }
+
+ root.appendChild( // signal('inc') should be applied as "onclick" function:
+ elmish.add_attributes(["id=btn", signal('inc')],
+ document.createElement('button'))
+ );
+
+ // "click" the button!
+ document.getElementById("btn").click()
+ // confirm that the counter was incremented by the onclick being triggered:
+ t.equal(counter, 1, "Counter incremented via onclick attribute (function)!");
+ elmish.empty(root);
+ t.end();
+});
+```
+
+Run the test:
+```sh
+node test/elmish.test.js
+```
+![onclick-test-failing](https://user-images.githubusercontent.com/194400/43955072-99712c7e-9c96-11e8-94a0-8c6d6d9169cb.png)
+
+Making this test pass requires a little knowledge of how JavaScript
+does "type checking" and the fact that we can "pass around" functions
+as variables.
+
+The amount of code required to make this test pass is _minimal,_
+you could even get it down to ***1 line***.
+The key is thinking through what the test is doing
+and figuring out how to apply an `onclick` function to a DOM node.
+
+Relevant/useful reading:
+
++ https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onclick
++ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof
++ https://stackoverflow.com/questions/6956258/adding-onclick-event-to-dynamically-added-button
++ https://stackoverflow.com/questions/14569320/simulating-button-click-in-javascript
+
+
+
+
### `subscriptions` for event listeners
+In Elm, when we want to "listen" for an event or "external input"
+we use ***`subscriptions`***. Examples are:
+
++ [Keyboard events](http://package.elm-lang.org/packages/elm-lang/keyboard/latest/Keyboard)
++ [Mouse movements](http://package.elm-lang.org/packages/elm-lang/mouse/latest/Mouse)
++ Browser locations changes
++ [Websocket events](http://package.elm-lang.org/packages/elm-lang/websocket/latest/WebSocket)
+
+In order to listen for and respond to Keyboard events,
+specifically the **`Enter`** and **`[Escape]`** key press,
+we need a way of "attaching" event listeners to the DOM
+when mounting our App.
+To demonstrate **`subscriptions`**,
+let's _briefly re-visit_ the Counter Example
+and consider an alternative User Interaction/Experience: Keyboard!
+#### Use-case: Use Up/Down Keyboard (Arrow) Keys to Increment/Decrement Counter
+Let's start by making a "copy" of the code in `/examples/counter-reset`:
+```sh
+mkdir examples/counter-reset-keyboard
+cp examples/counter-reset/* examples/counter-reset-keyboard/
+```
+
+First step is to _re-factor_ the code in
+`examples/counter-reset-keyboard/counter.js`
+to use the "DOM" functions we've been creating for `Elm`(_ish_).
+This will _simplify_ the `counter.js` down to the _bare minimum_.
+
+
+
+
+#### How do We _Test_ for Subscription Events?
+
+
+
+
+
That's it for now! `Elm`(_ish_) is "ready" to be _used_
for our TodoMVC App!
diff --git a/examples/todo-list/elmish.js b/examples/todo-list/elmish.js
index c658e767..e3bc8eb9 100644
--- a/examples/todo-list/elmish.js
+++ b/examples/todo-list/elmish.js
@@ -47,7 +47,8 @@ function mount (model, update, view, root_element_id, subscriptions) {
* `add_attributes` applies the desired attribute(s) to the specified DOM node.
* Note: this function is "impure" because it "mutates" the node.
* however it is idempotent; the "side effect" is only applied once.
-* @param {Array.} attrlist list of attributes to be applied to the node
+* @param {Array./} attrlist list of attributes to be applied
+* to the node accepts both String and Function (for onclick handlers).
* @param {Object} node DOM node upon which attribute(s) should be applied
* @example
* // returns node with attributes applied
@@ -56,6 +57,9 @@ function mount (model, update, view, root_element_id, subscriptions) {
function add_attributes (attrlist, node) {
if(attrlist && attrlist.length) {
attrlist.forEach(function (attr) { // apply all props in array
+ // do not attempt to "split" an onclick function as it's not a string!
+ if (typeof attr === 'function') { node.onclick = attr; return node; }
+ // apply any attributes that are *not* functions (i.e. Strings):
var a = attr.split('=');
switch(a[0]) {
case 'autofocus':
@@ -90,7 +94,7 @@ function add_attributes (attrlist, node) {
break;
default:
break;
- }
+ } // end switch
});
}
return node;
diff --git a/test/elmish.test.js b/test/elmish.test.js
index 2d5cd74c..bf9ecea8 100644
--- a/test/elmish.test.js
+++ b/test/elmish.test.js
@@ -423,24 +423,30 @@ test('elmish.mount sets model in localStorage', function (t) {
t.end()
});
-test.only('elmish.add_attributes onclick=signal(action) events!', function (t) {
+test('elmish.add_attributes onclick=signal(action) events!', function (t) {
const root = document.getElementById(id);
elmish.empty(root);
- let counter = 0;
- function signal(action) {
+ let counter = 0; // global to this test.
+ function signal (action) { // simplified version of TEA "dispacher" function
return function callback() {
- counter++
+ switch (action) {
+ case 'inc':
+ counter++; // "mutating" ("impure") counters for test simplicity.
+ break;
+ }
}
}
- let btn = document.createElement('button');
+
root.appendChild(
- elmish.add_attributes(["id=btn", "onclick=" + signal('inc')], btn)
+ elmish.add_attributes(["id=btn", signal('inc')],
+ document.createElement('button'))
);
// "click" the button!
document.getElementById("btn").click()
- t.equal(counter, 1, "Counter incremented");
-
+ // confirm that the counter was incremented by the onclick being triggered:
+ t.equal(counter, 1, "Counter incremented via onclick attribute (function)!");
+ elmish.empty(root);
t.end();
});