-
Notifications
You must be signed in to change notification settings - Fork 22
Multiple counters issue#40 #41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
b2354d5
adds @w0rm "View Theater" Elm Architecture diagram. closes https://gi...
nelsonic e8a3212
add Section 10 with instructions for Multiple Counters on the Same Pa...
nelsonic 4c44077
new line in example/counter-reset (line length linting)
nelsonic b11473c
borrow code from example/counter-reset for Multiple Counters example #40
nelsonic c65d491
Step 10.1 refactor example/counter-reset to use model = { counters: [...
nelsonic ca87db0
add correct Creative Commons License Attribution 4.0 International (C...
nelsonic f2ae57b
update link to tweet https://twitter.com/01k/status/98652860263535820...
nelsonic 50ab6b3
fix attirbution to Kolja Wilcke https://twitter.com/01k/status/986528...
nelsonic 0cc51b2
add multiple instances example for multiple counters quest #40
nelsonic 781772f
[WiP] busy refactoring for multiple counters #40
nelsonic 4a543ca
refactor view and update functions to accomodate multiple counters fo...
nelsonic ced7ab9
add CSS to float multiple counters for #40
nelsonic ff85e59
set default values for action and index in multiple-countes/counter.j...
nelsonic 2f19809
finish writeup on multiple counters for #40
nelsonic 78fcd81
adds link to https://github.com/dwyl/learn-elm-architecture-in-javasc...
nelsonic 45475fe
re-use counter.js from example/counter-reset in examples/multiple-cou...
nelsonic 7d6871e
re-use counter.js from example/counter-reset in examples/multiple-cou...
nelsonic File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
52 changes: 52 additions & 0 deletions
examples/multiple-counters-instances/index.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
<!DOCTYPE html> | ||
<html lang="en-GB"> | ||
<head> | ||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> | ||
<meta name="viewport" | ||
content="width=device-width, initial-scale=1.0, user-scalable=yes"> | ||
<title>Elm Architecture in JS - Counter Reset</title> | ||
<link rel="shortcut icon" | ||
href="http://www.dwyl.io/images/favicon.ico" type="image/x-icon"> | ||
</head> | ||
<body> | ||
<script src="../counter-reset/counter.js" data-cover></script> <!-- load counter once --> | ||
<div id="app" class="counter"></div> | ||
<div id="app1" class="counter"></div> | ||
<div id="app2" class="counter"></div> | ||
<script> // Mount as many apps as you like: | ||
mount(0, update, view, 'app'); | ||
mount(1, update, view, 'app1'); | ||
mount(2, update, view, 'app2'); | ||
</script> | ||
|
||
<style> | ||
.counter { | ||
border: 1px solid black; | ||
width: 28%; | ||
float: left; | ||
margin: 1%; | ||
padding: 1%; | ||
} | ||
body{ | ||
font-family: Courier, "Lucida Console", monospace; | ||
font-size: 4em; | ||
text-align: center; | ||
} | ||
button { | ||
font-size: 0.5em; color:white; border:5px solid; border-radius: 0.5em; | ||
padding:0.1em; margin: 0.2em auto; | ||
display: block; width: 90%; | ||
} | ||
.inc { | ||
background-color: #2ecc71; border-color: #27ae60; | ||
} | ||
.dec { | ||
background-color: #e74c3c; border-color: #c0392b; | ||
} | ||
.reset { | ||
background-color: #f39c12; border-color: #e67e22; | ||
} | ||
</style> | ||
|
||
</body> | ||
</html> |
89 changes: 89 additions & 0 deletions
examples/multiple-counters/counter.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
// Define the Component's Actions: | ||
var Inc = 'inc'; // increment the counter | ||
var Dec = 'dec'; // decrement the counter | ||
var Res = 'reset'; // reset counter: git.io/v9KJk | ||
|
||
function update(model, action) { // Update function takes the current state | ||
var parts = action ? action.split('-') : []; // e.g: inc-0 where 0 is the counter "id" | ||
var act = parts[0]; | ||
var index = parts[1] || 0; | ||
var new_model = JSON.parse(JSON.stringify(model)) // "clone" the model | ||
switch(act) { // and an action (String) runs a switch | ||
case Inc: | ||
new_model.counters[index] = model.counters[index] + 1; | ||
break; | ||
case Dec: | ||
new_model.counters[index] = model.counters[index] - 1; | ||
break; | ||
case Res: // use ES6 Array.fill to create a new array with values set to 0: | ||
new_model.counters[index] = 0; | ||
break; | ||
default: return model; // if action not defined, return curent state. | ||
} | ||
return new_model; | ||
} | ||
|
||
function view(signal, model, root) { | ||
empty(root); // clear root element before re-rendering the App (DOM). | ||
model.counters.map(function(counter, index) { | ||
return container(index, [ // wrap DOM nodes in an "container" | ||
button('+', signal, Inc + '-' + index), // append index to action | ||
div('count', counter), // create div w/ count as text | ||
button('-', signal, Dec + '-' + index), // decrement counter | ||
button('Reset', signal, Res + '-' + index) // reset counter | ||
]); | ||
}).forEach(function (el) { root.appendChild(el) }); // forEach is ES5 so IE9+ | ||
} | ||
|
||
// Mount Function receives all MUV and mounts the app in the "root" DOM Element | ||
function mount(model, update, view, root_element_id) { | ||
var root = document.getElementById(root_element_id); // root DOM element | ||
function signal(action) { // signal function takes action | ||
return function callback() { // and returns callback | ||
model = update(model, action); // update model according to action | ||
view(signal, model, root); // subsequent re-rendering | ||
}; | ||
}; | ||
view(signal, model, root); // render initial model (once) | ||
} | ||
|
||
// The following are "Helper" Functions which each "Do ONLY One Thing" and are | ||
// used in the "View" function to render the Model (State) to the Browser DOM: | ||
|
||
// empty the contents of a given DOM element "node" (before re-rendering) | ||
function empty(node) { | ||
while (node.firstChild) { | ||
node.removeChild(node.firstChild); | ||
} | ||
} // Inspired by: stackoverflow.com/a/3955238/1148249 | ||
|
||
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/section | ||
function container(index, elements) { | ||
var con = document.createElement('section'); | ||
con.id = index; | ||
con.className = 'counter'; | ||
elements.forEach(function(el) { con.appendChild(el) }); | ||
return con; | ||
} | ||
|
||
function button(text, signal, action) { | ||
var button = document.createElement('button'); | ||
var text = document.createTextNode(text); // human-readable button text | ||
button.appendChild(text); // text goes *inside* not attrib | ||
button.className = action.split('-')[0]; // use action as CSS class | ||
button.id = action; | ||
// console.log(signal, ' action:', action) | ||
button.onclick = signal(action); // onclick tells how to process | ||
return button; // return the DOM node(s) | ||
} // how to create a button in JavaScript: stackoverflow.com/a/8650996/1148249 | ||
|
||
function div(divid, text) { | ||
var div = document.createElement('div'); | ||
div.id = divid; | ||
div.className = divid; | ||
if(text !== undefined) { // if text is passed in render it in a "Text Node" | ||
var txt = document.createTextNode(text); | ||
div.appendChild(txt); | ||
} | ||
return div; | ||
} |
29 changes: 29 additions & 0 deletions
examples/multiple-counters/index.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<!DOCTYPE html> | ||
<html lang="en-GB"> | ||
<head> | ||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> | ||
<meta name="viewport" | ||
content="width=device-width, initial-scale=1.0, user-scalable=yes"> | ||
<title>Elm Architecture in JS - Counter Reset</title> | ||
<link rel="shortcut icon" | ||
href="http://www.dwyl.io/images/favicon.ico" type="image/x-icon"> | ||
<!-- CSS Styles are 100% optional. but they make it look *much* nicer --> | ||
<link rel="stylesheet" href="../style.css"> | ||
</head> | ||
<body> | ||
<div id="app"></div> | ||
<script src="counter.js" data-cover></script> <!-- load counter --> | ||
<script> mount({counters:[0, 1, 2]}, update, view, 'app'); </script> | ||
<!-- Below this point is all related to the Tests for the App --> | ||
<div id="test-app"></div> <!-- Create a test-app div to mount the app --> | ||
<div id="qunit"></div> <!-- test results are displayed here --> | ||
<!-- Load the QUnit CSS file from CDN - require to display our tests --> | ||
<link rel="stylesheet" href="https://code.jquery.com/qunit/qunit-1.18.0.css"> | ||
<!-- Load the QUnit Testing Framework from CDN - to run the tests --> | ||
<script src="https://code.jquery.com/qunit/qunit-1.18.0.js"></script> | ||
<!-- Load Blanket.js from CDN - for test coverage stats --> | ||
<script src="https://cdnjs.cloudflare.com/ajax/libs/blanket.js/1.1.4/blanket.js"> | ||
</script> | ||
<script src="test.js"></script> <!-- always load test.js last --> | ||
</body> | ||
</html> |
74 changes: 74 additions & 0 deletions
examples/multiple-counters/test.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
var id = 'test-app'; | ||
|
||
test('update({counters:[0]}) returns {counters:[0]} (current state unmodified)', | ||
function(assert) { | ||
var result = update({counters:[0]}); | ||
assert.equal(result.counters[0], 0); | ||
}); | ||
|
||
test('Test Update increment: update(1, "inc") returns 2', function(assert) { | ||
var result = update({counters: [1] }, "inc"); | ||
console.log('result', result); | ||
assert.equal(result.counters[0], 2); | ||
}); | ||
|
||
|
||
test('Test Update decrement: update(1, "dec") returns 0', function(assert) { | ||
var result = update({counters: [1] }, "dec"); | ||
assert.equal(result.counters[0], 0); | ||
}); | ||
|
||
test('Test negative state: update(-9, "inc") returns -8', function(assert) { | ||
var result = update({counters: [-9] }, "inc"); | ||
assert.equal(result.counters[0], -8); | ||
}); | ||
|
||
test('mount({model: 7, update: update, view: view}, "' | ||
+ id +'") sets initial state to 7', function(assert) { | ||
mount({counters:[7]}, update, view, id); | ||
var state = document.getElementById(id) | ||
.getElementsByClassName('count')[0].textContent; | ||
assert.equal(state, 7); | ||
}); | ||
|
||
test('empty("test-app") should clear DOM in root node', function(assert) { | ||
empty(document.getElementById(id)); | ||
mount({counters:[7]}, update, view, id); | ||
empty(document.getElementById(id)); | ||
var result = document.getElementById(id).innerHtml | ||
assert.equal(result, undefined); | ||
}); | ||
|
||
test('click on "+" button to re-render state (increment model by 1)', | ||
function(assert) { | ||
document.body.appendChild(div(id)); | ||
mount({counters:[7]}, update, view, id); | ||
document.getElementById(id).getElementsByClassName('inc')[0].click(); | ||
var state = document.getElementById(id) | ||
.getElementsByClassName('count')[0].textContent; | ||
assert.equal(state, 8); // model was incremented successfully | ||
empty(document.getElementById(id)); // clean up after tests | ||
}); | ||
|
||
// Reset Functionality | ||
|
||
test('Test reset counter when model/state is 6 returns 0', function(assert) { | ||
var result = update({counters:[7]}, "reset"); | ||
assert.equal(result.counters[0], 0); | ||
}); | ||
|
||
test('reset button should be present on page', function(assert) { | ||
var reset = document.getElementsByClassName('reset'); | ||
assert.equal(reset.length, 3); | ||
}); | ||
|
||
test('Click reset button resets state to 0', function(assert) { | ||
mount({counters:[7]}, update, view, id); | ||
var root = document.getElementById(id); | ||
assert.equal(root.getElementsByClassName('count')[0].textContent, 7); | ||
var btn = root.getElementsByClassName("reset")[0]; // click reset button | ||
btn.click(); // Click the Reset button! | ||
var state = root.getElementsByClassName('count')[0].textContent; | ||
assert.equal(state, 0); // state was successfully reset to 0! | ||
empty(root); // clean up after tests | ||
}); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.