├── .gitignore
├── logo.png
├── counter.gif
├── logo.afdesign
├── package.json
├── CONTRIBUTING.md
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adrianmcli/omg-counters/HEAD/logo.png
--------------------------------------------------------------------------------
/counter.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adrianmcli/omg-counters/HEAD/counter.gif
--------------------------------------------------------------------------------
/logo.afdesign:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adrianmcli/omg-counters/HEAD/logo.afdesign
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "doctoc": "doctoc README.md"
4 | },
5 | "devDependencies": {
6 | "doctoc": "^1.2.0"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to contribute
2 |
3 | We are always looking to add more frameworks to our list. The proper way to do this is to fork the repo, make your changes, and then submit a pull request. In your submission, make sure to run [doctoc](https://github.com/thlorenz/doctoc) on the README.md file in order to generate an up-to-date table of contents.
4 |
5 | You can do this by running:
6 |
7 | ```
8 | npm install
9 | npm run doctoc
10 | ```
11 |
12 | Each example should also have a live example. It's recommended to make this live example on [WebpackBin](http://www.webpackbin.com/), but if your language/framework requires another sandbox, that should be viable as well.
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ↕️️ Increment/decrement counters using various frontend frameworks.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | ---
15 |
16 |
17 |
18 |
19 |
20 | ### _When a hello world is too simple, but a todo app is too complex._
21 |
22 | _No counters were harmed in the making of these examples._
23 |
24 | ### Attribution
25 |
26 | * AngularJS ([@housseindjirdeh](https://github.com/housseindjirdeh))
27 | * Angular 2+ ([@ashwin-sureshkumar](https://github.com/ashwin-sureshkumar))
28 | * MobX ([@teesloane](https://github.com/teesloane))
29 | * Choo ([@jelanithompson](https://github.com/JelaniThompson))
30 | * Marko ([@patrick-steele-idem](https://github.com/patrick-steele-idem))
31 |
32 | ### Table of Contents
33 |
34 |
35 |
36 |
37 |
38 | - [Vanilla JS](#vanilla-js)
39 | - [jQuery](#jquery)
40 | - [RxJS](#rxjs)
41 | - [React](#react)
42 | - [React + Redux](#react--redux)
43 | - [AngularJS](#angularjs)
44 | - [Angular 2+](#angular-2)
45 | - [Hyperapp](#hyperapp)
46 | - [Vue.js](#vuejs)
47 | - [Elm](#elm)
48 | - [Cycle.js](#cyclejs)
49 | - [Jumpsuit](#jumpsuit)
50 | - [Mobx](#mobx)
51 | - [Choo](#choo)
52 | - [Marko](#marko)
53 |
54 |
55 |
56 | _Don't see your favorite framework? Make a PR! (see [contributing guidelines](CONTRIBUTING.md))_
57 |
58 | # Vanilla JS
59 |
60 | ```html
61 |
62 |
63 | Increment
64 | Decrement
65 | ```
66 |
67 | ```js
68 | // javascript
69 | let count = 0
70 | const $count = document.getElementsByClassName('count')[0]
71 | $count.textContent = count
72 | function increment() { $count.textContent = ++count }
73 | function decrement() { $count.textContent = --count }
74 | ```
75 |
76 | [Live Example on WebpackBin](http://www.webpackbin.com/NyXDu7ytz)
77 |
78 | # jQuery
79 |
80 | ```html
81 |
82 |
83 | Increment
84 | Decrement
85 | ```
86 |
87 | ```js
88 | // javascript
89 | let count = 0
90 | $('.count').text(count)
91 | $('.increment').on('click', () => $('.count').text(++count))
92 | $('.decrement').on('click', () => $('.count').text(--count))
93 | ```
94 |
95 | [Live Example on WebpackBin](http://www.webpackbin.com/VyZb9Z1KG)
96 |
97 | # RxJS
98 |
99 | ```html
100 |
101 | //
102 | // Increment
103 | // Decrement
104 | ```
105 |
106 | ```js
107 | // javascript
108 | const $factory = id => Rx.Observable.fromEvent(document.getElementById(id), 'click')
109 | const setCount = count => document.getElementById('count').textContent = count
110 |
111 | const inc$ = $factory('increment').mapTo(1)
112 | const dec$ = $factory('decrement').mapTo(-1)
113 |
114 | Rx.Observable.merge(inc$, dec$)
115 | .startWith(0)
116 | .scan((a, b) => a + b)
117 | .subscribe(setCount)
118 | ```
119 |
120 | [Live Example on WebpackBin](http://www.webpackbin.com/NkLKZwkFM)
121 |
122 | # React
123 |
124 | ```jsx
125 | class Counter extends React.Component {
126 | state = {count: 0}
127 |
128 | increment = e =>
129 | this.setState({ count: this.state.count + 1 })
130 |
131 | decrement = e =>
132 | this.setState({ count: this.state.count - 1 })
133 |
134 | render = () =>
135 |
136 |
{this.state.count}
137 | Increment
138 | Decrement
139 |
140 | }
141 | ```
142 |
143 | [Live Example on WebpackBin](http://www.webpackbin.com/4kvMWMkKG)
144 |
145 | # React + Redux
146 |
147 | ```jsx
148 | import { createStore } from 'redux'
149 |
150 | const reducer = (state = 0, action) => {
151 | switch (action.type) {
152 | case 'INCREMENT': return state + 1
153 | case 'DECREMENT': return state - 1
154 | default: return state
155 | }
156 | }
157 |
158 | const store = createStore(reducer)
159 |
160 | var Counter = ({ count, onIncrement, onDecrement }) => (
161 |
162 |
{count}
163 | Increment
164 | Decrement
165 |
166 | )
167 |
168 | const render = () => {
169 | ReactDOM.render(
170 | store.dispatch({type: 'INCREMENT'})}
173 | onDecrement={()=> store.dispatch({type: 'DECREMENT'})}
174 | />,
175 | document.querySelector('body')
176 | )
177 | }
178 |
179 | store.subscribe(render)
180 | render()
181 | ```
182 |
183 | [Live Example on WebpackBin](http://www.webpackbin.com/N175AO1tz)
184 |
185 | # AngularJS
186 |
187 | ```js
188 | const CounterComponent = {
189 | template: `
190 |
191 |
{{ $ctrl.counter }}
192 | Increment
193 | Decrement
194 |
195 | `,
196 | controller: class CounterController {
197 | constructor() {
198 | this.counter = 0
199 | }
200 |
201 | increaseCounter() {
202 | this.counter++
203 | }
204 |
205 | decreaseCounter() {
206 | this.counter--
207 | }
208 | }
209 | }
210 |
211 | export default CounterComponent
212 | ```
213 |
214 | [Live Example on WebpackBin](http://www.webpackbin.com/4JwFUVetz)
215 |
216 | # Angular 2+
217 |
218 | ```js
219 | import { Component } from '@angular/core'
220 |
221 | @Component({
222 | selector: 'counter',
223 | template : `
224 |
225 |
{{counter}}
226 | Increment
227 | Decrement
228 |
229 | `
230 | })
231 | export class CounterComponent {
232 | counter: number = 0
233 |
234 | onIncrement() {
235 | this.counter++
236 | }
237 |
238 | onDecrement() {
239 | this.counter--
240 | }
241 | }
242 | ```
243 |
244 | [Live Example on WebpackBin](http://www.webpackbin.com/4kFun-lFM)
245 |
246 | # Hyperapp
247 |
248 | ```jsx
249 | app({
250 | model: 0,
251 | update: {
252 | add: model => model + 1,
253 | sub: model => model - 1
254 | },
255 | view: (model, actions) =>
256 |
257 |
{model}
258 | Increment
259 | Decrement
260 |
261 | })
262 | ```
263 |
264 | [Live Example on WebpackBin](http://www.webpackbin.com/VJ-dzMJYz)
265 |
266 | # Vue.js
267 |
268 | ```html
269 |
270 |
271 |
{{ count }}
272 | Increment
273 | Decrement
274 |
275 | ```
276 |
277 | ```js
278 | // javascript
279 | new Vue({
280 | el: '#app',
281 | data: { count: 0 },
282 | methods: {
283 | increment: function() { this.count++ },
284 | decrement: function() { this.count-- }
285 | }
286 | })
287 | ```
288 |
289 | [Live Example on WebpackBin](http://www.webpackbin.com/VyxxXfJYM)
290 |
291 | # Elm
292 |
293 | ```elm
294 | import Html exposing (beginnerProgram, div, h1, button, text)
295 | import Html.Events exposing (onClick)
296 |
297 |
298 | main =
299 | beginnerProgram { model = 0, view = view, update = update }
300 |
301 |
302 | view model =
303 | div []
304 | [ h1 [] [ text (toString model) ]
305 | , button [ onClick Increment ] [ text "increment" ]
306 | , button [ onClick Decrement ] [ text "decrement" ]
307 | ]
308 |
309 |
310 | type Msg = Increment | Decrement
311 |
312 |
313 | update msg model =
314 | case msg of
315 | Increment ->
316 | model + 1
317 |
318 | Decrement ->
319 | model - 1
320 | ```
321 |
322 | [Live Example](http://elm-lang.org/examples/buttons)
323 |
324 | # Cycle.js
325 |
326 | ```js
327 | const xs = xstream.default
328 | const {div, button, h1, makeDOMDriver} = CycleDOM
329 |
330 | function main(sources) {
331 | const action$ = xs.merge(
332 | sources.DOM.select('.dec').events('click').mapTo(-1),
333 | sources.DOM.select('.inc').events('click').mapTo(+1)
334 | )
335 | const count$ = action$.fold((x, y) => x + y, 0)
336 | const vdom$ = count$.map(count =>
337 | div([
338 | h1(count.toString()),
339 | button('.dec', 'Decrement'),
340 | button('.inc', 'Increment')
341 | ])
342 | )
343 | return { DOM: vdom$ }
344 | }
345 | ```
346 |
347 | [Live Example on JSBin](https://jsbin.com/huxoduh/1/edit?html,js,output)
348 |
349 | # Jumpsuit
350 |
351 | ```js
352 | const CounterState = State({
353 | initial: { count: 0 },
354 | increment: ({ count }) => ({ count: count + 1 }),
355 | decrement: ({ count }) => ({ count: count - 1 })
356 | })
357 |
358 | const Counter = Component({
359 | render() {
360 | return (
361 |
362 |
{ this.props.count }
363 | Increment
364 | Decrement
365 |
366 | )
367 | }
368 | }, (state) => ({ count: state.counter.count }))
369 |
370 | const globalState = { counter: CounterState }
371 | Render(globalState, )
372 | ```
373 |
374 | [Live Example on WebpackBin](http://www.webpackbin.com/4JkiMmkKM)
375 |
376 | # Mobx
377 |
378 | ```jsx
379 | const store = new class CounterStore {
380 | @observable count = 0
381 | @action increment = () => this.count++
382 | @action decrement = () => this.count--
383 | }
384 |
385 | const Counter = observer(() => {
386 | return (
387 |
388 |
{store.count}
389 | Increment
390 | Decrement
391 |
392 | )
393 | })
394 | ```
395 |
396 | [Live Example on JSBin](http://jsbin.com/zedoco/2/edit?js,output)
397 |
398 | # Choo
399 | ```js
400 | app.model({
401 | state: { count: 0 },
402 | reducers: {
403 | increment: (state) => ({ count: state.count + 1 }),
404 | decrement: (state) => ({ count: state.count - 1 })
405 | }
406 | })
407 |
408 | const view = (state, previousState, send) => {
409 | return html`
410 |
${state.count}
411 | Increment
412 | Decrement `
413 |
414 | function increment() { send('increment') }
415 | function decrement() { send('decrement') }
416 | }
417 |
418 | app.router([['/', view]])
419 | document.body.appendChild(app.start())
420 | ```
421 | [View on WebpackBin](http://www.webpackbin.com/Nk8CLwg5M)
422 |
423 | # Marko
424 |
425 | ```marko
426 | class {
427 | onCreate() {
428 | this.state = {count: 0};
429 | }
430 |
431 | increment(delta) {
432 | this.state.count += delta;
433 | }
434 | }
435 |
436 |
437 |
${state.count}
438 | Increment
439 | Decrement
440 |
441 | ```
442 | [Try Online at markojs.com](http://markojs.com/try-online/?gist=8aa2a490d9426648d9fee81b7964606f)
--------------------------------------------------------------------------------