Skip to content

Instantly share code, notes, and snippets.

@matfournier
Last active February 4, 2019 21:31
Show Gist options
  • Save matfournier/245adc2daf5e20172d3a5ad086a6f0eb to your computer and use it in GitHub Desktop.
Save matfournier/245adc2daf5e20172d3a5ad086a6f0eb to your computer and use it in GitHub Desktop.
Examples of counters in various languages/frameworks for js
angular.module('counterApp', []);
angular.module('counterApp')
.controller('counterCtrl', function() {
var limit = 10;
this.reset = function() {
this.count = 0;
};
this.reset();
this.increment = function() {
this.count = this.count + 1;
};
this.decrement = function() {
this.count = this.count - 1;
};
this.isLimitExceeded = function() {
return this.count >= limit;
};
this.countIsZero = function() {
return this.count === 0;
};
});
/*-------------Store Service-------------*/
class store {
/*-------------Create Store-------------*/
createStore(reducer) {
let state;
let listeners = [];
const getState = () => state;
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
};
const subscribe = (listener) => {
listeners.push(listener);
return () => {
listeners = listeners.filter(l => l !==listener);
};
};
dispatch({});
/*
Instead of returning the store,
we assign it to the StoreService.
If we were to assign it to the component then
the store would be gone when the component gets
destroyed.
*/
this.store = { getState, dispatch, subscribe };
}
}
/*-------------Counter Component-------------*/
class CounterCtrl {
constructor(CounterStore) {
this.value;
this.CounterStore = CounterStore;
this.setState = () => this.value = this.CounterStore.store.getState();
}
dispatch(action) {
this.lastAction = {
prevState: this.value,
action
}
this.CounterStore.store.dispatch({
type: action
});
}
$onInit() {
//create reducer
const reducer = (state = 0, action) => {
switch(action.type) {
case 'INCREMENT':
return ++state
case 'DECREMENT':
return --state
default:
return state
};
}
//create the store with the reducer
this.CounterStore.createStore(reducer);
//subscribe to store with setState
this.unsubscribe = this.CounterStore.store.subscribe(this.setState);
//render initial state
this.setState();
}
$onDestroy() {
this.unsubscribe();
}
}
const counterComponent = {
controller: CounterCtrl,
template: `
<h1>{{$ctrl.value}}</h1>
<button ng-click="$ctrl.dispatch('INCREMENT')">+</button>
<button ng-click="$ctrl.dispatch('DECREMENT')">-</button>
<pre>
{{$ctrl.lastAction | json:2}}
</pre>
`
};
/*--------------MODULE-------------*/
angular.module('app', [])
.component('counter', counterComponent)
.service('CounterStore', store);
import Browser
import Html exposing (Html, button, div, text)
import Html.Events exposing (onClick)
main =
Browser.sandbox { init = 0, update = update, view = view }
type Msg = Increment | Decrement
update msg model =
case msg of
Increment ->
model + 1
Decrement ->
model - 1
view model =
div []
[ button [ onClick Decrement ] [ text "-" ]
, div [] [ text (String.fromInt model) ]
, button [ onClick Increment ] [ text "+" ]
]
module Example.Count where
import Prelude
import Data.Maybe (Maybe(..))
import Halogen as H
import Halogen.HTML as HH
import Halogen.HTML.Events as HE
data Query a
= Increase a
| Decrease a
type State = { value :: Int }
component :: forall m. H.Component HH.HTML Query Unit Void m
component = H.component
{ initialState: const initialState
, render
, eval
, receiver: const Nothing
}
where
initialState :: State
initialState = { value: 0 }
render :: State -> H.ComponentHTML Query
render state =
HH.div_
[ HH.h3_
[ HH.text "A counter" ]
, HH.div_
[ HH.button
[ HE.onClick $ HE.input_ Increase ]
[ HH.text "+" ]
]
, HH.div_
[ HH.text $ show state.value ]
, HH.div_
[ HH.button
[ HE.onClick $ HE.input_ Decrease ]
[ HH.text "-" ]
]
]
eval :: Query ~> H.ComponentDSL State Query Void m
eval (Increase next) =
H.modify (\state -> state { value = state.value + 1 }) $> next
eval (Decrease next) =
H.modify (\state -> state { value = state.value - 1 }) $> next
module Main where
import Prelude
import Effect (Effect)
import Hedwig as H
import Hedwig ((:>))
type Model = Int
init :: Model
init = 0
data Msg = Increment | Decrement
update :: Model -> Msg -> Model
update model = case _ of
Increment -> model + 1
Decrement -> model - 1
view :: Model -> H.Html Msg
view model = H.main [H.id "main"] [
H.button [H.onClick Decrement] [H.text "-"],
H.text (show model),
H.button [H.onClick Increment] [H.text "+"]
]
main :: Effect Unit
main = do
H.mount "main" {
init: init :> [],
update: \msg model -> update msg model :> [],
view
}
module Actions where
import Prelude
import Effect.Console (log)
import React.Basic (Component, JSX, StateUpdate(..), createComponent, make, runUpdate)
import React.Basic.DOM as R
import React.Basic.DOM.Events (capture_)
component :: Component Props
component = createComponent "Counter"
type Props =
{ label :: String
}
data Action
= Increment
actions :: Props -> JSX
actions = make component { initialState, render }
where
initialState = { counter: 0 }
update self = case _ of
Increment ->
UpdateAndSideEffects
(self.state { counter = self.state.counter + 1 })
\{ state } -> log $ "Count: " <> show state.counter
send = runUpdate update
render self =
R.button
{ onClick: capture_ $ send self Increment
, children: [ R.text (self.props.label <> ": " <> show self.state.counter) ]
}
module Counter where
import Prelude
import React.Basic (Component, JSX, createComponent, make)
import React.Basic.DOM as R
import React.Basic.DOM.Events (capture_)
component :: Component Props
component = createComponent "Counter"
type Props =
{ label :: String
}
counter :: Props -> JSX
counter = make component { initialState, render }
where
initialState = { counter: 0 }
render self =
R.button
{ onClick: capture_ $ self.setState \s -> s { counter = s.counter + 1 }
, children: [ R.text (self.props.label <> ": " <> show self.state.counter) ]
}
module Main where
import Prelude
import Control.Monad.Eff (Eff)
import DOM (DOM)
import DOM.HTML (window) as DOM
import DOM.HTML.Types (htmlDocumentToParentNode) as DOM
import DOM.HTML.Window (document) as DOM
import DOM.Node.ParentNode (querySelector, QuerySelector(..)) as DOM
import Data.Maybe (Maybe, fromJust)
import Partial.Unsafe (unsafePartial)
import React (ReactComponent)
import React (createFactory) as R
import React.DOM (text, button, p') as R
import React.DOM.Props as RP
import ReactDOM as RDOM
import Thermite as T
data Action = Increment | Decrement
type State = { counter :: Int }
initialState :: State
initialState = { counter: 0 }
render :: forall a. T.Render State a Action
render dispatch _ state _ =
[ R.p' [ R.text "Value: "
, R.text $ show state.counter
]
, R.p' [ R.button [ RP.onClick \_ -> dispatch Increment ]
[ R.text "Increment" ]
, R.button [ RP.onClick \_ -> dispatch Decrement ]
[ R.text "Decrement" ]
]
]
performAction :: forall a b. T.PerformAction a State b Action
performAction Increment _ _ = void $ T.cotransform $ \state -> state { counter = state.counter + 1 }
performAction Decrement _ _ = void $ T.cotransform $ \state -> state { counter = state.counter - 1 }
spec :: forall a b. T.Spec a State b Action
spec = T.simpleSpec performAction render
main :: forall eff. Eff (dom :: DOM | eff) (Maybe ReactComponent)
main = unsafePartial do
let component = T.createClass spec initialState
document <- DOM.window >>= DOM.document
container <- fromJust <$> DOM.querySelector (DOM.QuerySelector "#container") (DOM.htmlDocumentToParentNode document)
RDOM.render (R.createFactory component {}) container
var Counter = React.createClass({
incrementCount: function(){
this.setState({
count: this.state.count + 1
});
},
decrementCount: function(){
this.setState({
count: this.state.count - 1
});
},
getInitialState: function(){
return {
count: 0
}
},
render: function(){
return (
<div className="counter">
<h1>{this.state.count}</h1>
<button className="btn" onClick={this.incrementCount}>Increment</button>
<button className="btn" onClick={this.decrementCount}>Decrement</button>
</div>
);
}
});
React.render(
<Counter />,
document.body
);
// https://egghead.io/series/getting-started-with-redux
const counter = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
const { createStore } = Redux;
const store = createStore(counter);
var Counter = ({
value,
onIncrement,
onDecrement
}) => (
<div className='redux'>
<h1>{value}</h1>
<button onClick={onIncrement}>+</button>
<button onClick={onDecrement}>-</button>
</div>
);
const render = () => {
ReactDOM.render(
<Counter
value={store.getState()}
onIncrement={()=> store.dispatch({type: 'INCREMENT'})}
onDecrement={()=> store.dispatch({type: 'DECREMENT'})}
/>,
document.querySelector('body')
);
};
store.subscribe(render);
render();
console.clear();
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
if (state.count < 100) {
state.count += 1;
}
},
decrement(state) {
if (state.count > 0) {
state.count += -1;
}
},
reset(state) {
state.count = 0;
}
}
})
Vue.component('counter', {
name: 'counter',
template: `
<div class="counter">
<p class="counter__display">{{ count }}</p>
<div class="counter__buttons">
<button class="button counter__increment" @click="increment"><i class="fa fa-plus"></i></button>
<button class="button counter__decrement" @click="decrement"><i class="fa fa-minus"></i></button>
<button class="button counter__reset" @click="reset"><i class="fa fa-refresh"></i></button>
</div>
</div>
`,
computed: {
count () {
return store.state.count;
}
},
methods: {
increment() {
store.commit('increment');
},
decrement() {
store.commit('decrement');
},
reset() {
store.commit('reset');
}
}
})
const app = new Vue({
el: '#app',
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment