import xs from 'xstream'
import {div, input, p, button} from '@cycle/dom'
function Phonebooth ({DOM}) {
const type$ = DOM.select('input')
.events('input')
.map(e => e.target.value)
.startWith('Steve')
const click$ = DOM.select('button')
.events('click')
.mapTo('Batman')
return {
DOM: xs.merge(type$, click$).map(name => div([
input({props: {value: name}}),
p(['Your name is ' + name + '.']),
button(['Put on costume'])
])),
focus: click$
}
}
export default Phonebooth
The same file in a TypeScript implementation using Angular (2.4.9):
import {Component,ViewChild} from '@angular/core';
@Component({
selector: '#app',
template: `
<input #field [(ngModel)]="name"><br/>
<p>Your name is {{name}}.</p>
<button (click)="change()">Put on costume</button>
`
})
export class Phonebooth {
@ViewChild('field') input
name = 'Steve'
change() {
this.name = 'Batman'
this.input.nativeElement.focus()
}
}
The same file in a component implementation using AngularJS (1.5.8):
import angular from 'angular'
angular.module('phoneboothapp')
.component('phonebooth', {
template: `
<input ng-model="$ctrl.name"><br/>
<p>Your name is {{$ctrl.name}}.</p>
<button ng-click="$ctrl.change()">Put on costume</button>
`,
controller: class Phonebooth {
constructor ($element) {
this.field = $element.find('input')[0]
this.name = 'Steve'
}
change () {
this.name = 'Batman'
this.field.focus()
}
}
})
The same file in an es6 implementation using Cyclow (0.5.0):
import {Block} from 'cyclow'
const Phonebooth = () => Block({
on: {
'in.init': () => state => ({name: 'Steve'}),
'dom.text': text => state => ({name: text}),
'dom.click': () => ({
state: () => ({name: 'Batman'}),
'dom.action': el => el.firstElementChild.focus()
})
},
view: ({name}) => ({
attrs: {id: 'app'},
content: [
{
tag: 'input',
attrs: {value: name},
on: {keyup: (e, next) => next({text: e.target.value})}
},
{tag: 'p', content: `Your name is ${name}.`},
{tag: 'button', content: 'Put on costume', on: {click: 'click'}}
]
})
})
export default Phonebooth
The same file in a react-elm-components implementation using Elm (0.17.1):
port module Phonebooth exposing (main)
import Html exposing (Html, Attribute, div, input, text, button, p)
import Html.App as App
import Html.Attributes exposing (..)
import Html.Events exposing (onInput, onClick)
main =
App.beginnerProgram { model = model, view = view, update = update }
-- MODEL
type alias Model =
{ name : String
}
model : Model
model =
{ name = "Steve" }
-- UPDATE
type Msg
= ChangeName String
| SuitUp
update : Msg -> Model -> Model
update msg model =
case msg of
ChangeName newName ->
{ model | name = newName }
SuitUp ->
{ name = "Batman" }
-- VIEW
view : Model -> Html Msg
view model =
div []
[ div [] [ input [ onInput ChangeName, value model.name ] [] ]
, p []
[ text "Your name is "
, text model.name
]
, button [ onClick SuitUp ] [ text "Put on costume" ]
]
The same file in a createClass implementation using React (15.3.1):
import React from 'react'
let Phonebooth = React.createClass({
getInitialState: () => ({name: 'Steve'}),
change () {
this.setState({name: 'Batman'})
this.refs.field.focus()
},
type (e) {
this.setState({name: e.target.value})
},
render () {
let name = this.state.name
return <div>
<div><input ref='field' onChange={this.type} value={name} /></div>
<p>Your name is {name}</p>
<button onClick={this.change}>Put on costume</button>
</div>
}
})
export default Phonebooth
The same file in a vanilla implementation using Vue (1.0.26):
import Vue from 'vue'
Vue.component('phonebooth', {
template: `
<input v-model="name" v-el:input><br/>
<p>Your name is {{name}}.</p>
<button v-on:click="change">Put on costume</button>
`,
data: () => ({name: 'Steve'}),
methods: {
change () {
this.name = 'Batman'
this.$els.input.focus()
}
}
})