Skip to content

Commit

Permalink
Fancier CounterList
Browse files Browse the repository at this point in the history
  • Loading branch information
Anler Hernandez Peral committed Feb 5, 2016
1 parent 3bc16ad commit 915c842
Show file tree
Hide file tree
Showing 9 changed files with 404 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Run any example with `npm run ex<number of the example>`, eg: `npm run ex1`
1. [Simple counter](https://github.com/kaleidos/olmo/blob/master/examples/01-counter) / [demo](http://kaleidos.github.io/olmo/examples/01-counter/)
2. [Counter pair](https://github.com/kaleidos/olmo/blob/master/examples/02-counter-pair) / [demo](http://kaleidos.github.io/olmo/examples/02-counter-pair/)
3. [List of counters](https://github.com/kaleidos/olmo/blob/master/examples/03-list-of-counters) / [demo](http://kaleidos.github.io/olmo/examples/03-list-of-counters/)
4. [Fancier list of counters](https://github.com/kaleidos/olmo/blob/master/examples/04-list-of-counters) / [demo](http://kaleidos.github.io/olmo/examples/04-list-of-counters/)

## Testing ##

Expand Down
12 changes: 12 additions & 0 deletions examples/04-list-of-counters/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
In this example you can see how to dynamically create and update other components.

Important points of this example:

* The use partially applying "action creators" thanks to the use of algebraic data types (ADT):
``` JavaScript
Modify: ['id', 'counterAction']
...
Action.Modify(id)
```

Note: There's not typechecking involve inside of the ADTs, and the strings 'id' and 'counterAction' are attribute names that are going to be present inside the action object passed to the update function.
38 changes: 38 additions & 0 deletions examples/04-list-of-counters/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import StartApp from 'olmo/start-app';
import Signal from 'olmo/signal';
import Task from 'olmo/task';

import snabbdom from 'snabbdom';
import snabbdomProps from 'snabbdom/modules/props';
import snabbdomEvents from 'snabbdom/modules/eventlisteners';

import CounterList from './counter-list';


const patch = snabbdom.init([snabbdomProps, snabbdomEvents]);

function render([oldHtml, newHtml]) {
return Task.of(() => patch(oldHtml, newHtml));
}

export default function App() {
var {html, model, tasks} = StartApp.AppSimple({
init: CounterList.init(),
update: CounterList.update,
view: CounterList.view
});

return {
html,
model,
// tasks perform side-effects
tasks: Signal.merge(
tasks,
// rendering is just a side-effect
html
.startWith(document.getElementById('root'))
.pairwise()
.flatMap(render)
)
};
}
176 changes: 176 additions & 0 deletions examples/04-list-of-counters/bundle.js

Large diffs are not rendered by default.

95 changes: 95 additions & 0 deletions examples/04-list-of-counters/counter-list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import Events from 'olmo/html-events';
import { forwardTo } from 'olmo/signal';
import ActionType from 'olmo/actions';

import { html } from 'snabbdom-jsx';

import Counter from './counter';


// model
export function init(countersWithID=[], nextID=1) {
return { countersWithID, nextID };
}

function nextID(prevID) {
return prevID + 1;
}


// actions
export const Action = ActionType({
Add: [],
Modify: ['id', 'counterAction'],
Remove: ['id']
});


// update
export const update = Action.case('CounterList', {

Add: (action, model) => {
const counter = Counter.init();
const id = model.nextID;
const counterWithID = {id, counter};

return init(
model.countersWithID.concat(counterWithID),
nextID(id)
);
},

Modify: (action, model) => {
return init(
model.countersWithID.map(counterWithID => {
const {id, counter} = counterWithID;
if (id === action.id) {
return {
id,
counter: Counter.update(action.counterAction, counter)
};
} else {
return counterWithID
}
}),
model.nextID
);
},

Remove: (action, model) => {
return init(
model.countersWithID.filter(counterWithID => counterWithID.id !== action.id),
model.nextID
);
}

});


export function view(address, model) {
const listOfCounters = model.countersWithID.map(counterWithID => {
const {id, counter} = counterWithID;
const counterAddress = forwardTo(address, Action.Modify(id));
const context = {
address: counterAddress,
remove: Events.message(address, Action.Remove(id))
};

return (
<li>
{Counter.viewWithRemoveButton(context, counter)}
</li>
)
});

return (
<div>
<button on-click={Events.message(address, Action.Add())}>Add Counter</button>
<ul>
{listOfCounters}
</ul>
</div>
);
}

export default {init, view, update};
55 changes: 55 additions & 0 deletions examples/04-list-of-counters/counter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import Events from 'olmo/html-events';
import ActionType from 'olmo/actions';

import { html } from 'snabbdom-jsx';


// model
export function init(initialValue=0) {
return initialValue;
}

// actions
export const Action = ActionType({
Increment: [],
Decrement: []
});

// update
export const update = Action.case('Counter', {

Increment: (action, model) => model + 1,

Decrement: (action, model) => model - 1,

});


export function view(address, model) {
return (
<div>
<p>{model}</p>
<p>
<button on-click={Events.message(address, Action.Decrement())}>Decrement</button>
<button on-click={Events.message(address, Action.Increment())}>Increment</button>
</p>
</div>
);
}


export function viewWithRemoveButton(context, model) {
const {address, remove} = context;
return (
<div>
<p>{model}</p>
<p>
<button on-click={Events.message(address, Action.Decrement())}>Decrement</button>
<button on-click={Events.message(address, Action.Increment())}>Increment</button>
<button on-click={remove}>Remove</button>
</p>
</div>
)
}

export default {init, update, view, viewWithRemoveButton};
21 changes: 21 additions & 0 deletions examples/04-list-of-counters/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="description" content="">
<meta name="viewport" content="width=device-width">

<title>Elm Architecture Tutorial</title>
<style>
html,head,body { padding:0; margin:0; }
body { font-family: calibri, helvetica, arial, sans-serif; }
</style>
</head>

<body>
<div id="root"></div>

<script src="bundle.js"></script>
</body>
</html>
4 changes: 4 additions & 0 deletions examples/04-list-of-counters/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { runApp } from 'olmo/start-app';
import App from './app';

runApp(App());
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
"ex2:build": "webpack ./examples/02-counter-pair/index.js && cp bundle.js index.html ./examples/02-counter-pair",
"ex3": "webpack-dev-server --inline --entry ./examples/03-list-of-counters/index.js",
"ex3:build": "webpack ./examples/03-list-of-counters/index.js && cp bundle.js index.html ./examples/03-list-of-counters",
"ex4": "webpack-dev-server --inline --entry ./examples/04-list-of-counters/index.js",
"ex4:build": "webpack ./examples/04-list-of-counters/index.js && cp bundle.js index.html ./examples/04-list-of-counters",
"test": "babel-tape-runner test/**/*.js | faucet",
"test:watch": "watch 'npm test' src/ test/ -d"
},
Expand Down

0 comments on commit 915c842

Please sign in to comment.