Elm + Polymer = ?
How to integrate Polymer in your stack?
Tech Lead @ Meetic


k.lebrun@meetic-corp.com
kevinlebrun





Retrouvez-nous sur https://goo.gl/Cqbdup
P.S. : Nous recrutons, https://goo.gl/dvuMso ;)
Elm
A counter component
- show the current value
- decrease the value
- increase the value
type alias Model =
Int
view : Model -> Html Msg
view model =
div []
[ button [ onClick Decrement ] [ text "-" ]
, span [] [ text (toString model) ]
, button [ onClick Increment ] [ text "+" ]
]

type Msg
= Increment
| Decrement
update : Msg -> Model -> Model
update msg model =
case msg of
Increment ->
model + 1
Decrement ->
model - 1

main : Program Never
main =
beginnerProgram
{ model = 0
, view = view
, update = update
}


www.meetup.com/Meetup-Elm-Paris
Interop
How to communicate with the outside world?
Elm Interop - Ports
var app = Elm.Counter.embed(node, { value : this.value });
app.ports.change.subscribe(value => {
this.value = value;
});
app.ports.set.send(this.value);

Elm Interop - Virtual DOM
div []
[ button [ onClick Decrement ] [ text "-" ]
, span [] [ text <| toString model ]
, button [ onClick Increment ] [ text "+" ]
]

Elm Interop - Native
Polymer Interop - Attributes I
Polymer({
is: "my-counter",
properties: {
value: {
type: Number,
value: -1,
notify: true,
},
},
increment() {
this.value++;
},
decrement() {
this.value--;
},
});

Polymer Interop - Attributes II
<my-counter id="counter" value=1></my-counter>
<script>
var counter = document.getElementById('counter');
counter.addEventListener('value-changed', function (e) {
console.log(e.detail.value);
});
</script>

Polymer Interop - Events I
Polymer({
is: "my-counter",
properties: {
value: Number,
},
increment() {
this.value++;
this.fire('change', this.value);
},
decrement() {
this.value--;
this.fire('change', this.value);
},
});

Polymer Interop - Events II
<my-counter id="counter" value=1></my-counter>
<script>
var counter = document.getElementById('counter');
counter.addEventListener('change', function (e) {
console.log(e.detail);
});
</script>

Polymer Interop - Methods I
Polymer({
is: "my-counter",
properties: {
value: Number,
},
increment() {
this.value++;
},
decrement() {
this.value--;
},
logValue() {
console.log(this.value);
},
});

Polymer Interop - Methods II
<my-counter id="counter" value=1></my-counter>
<script>
var counter = document.getElementById('counter');
counter.logValue();
</script>




Counter value
Counter
Counter reset
<p>
In the document,<br>
the value is <span class="value">0</span>
</p>
<div id="counter"></div>
<my-counter-controls id="controls"></my-counter-controls>

var node = document.getElementById('counter');
var counter = Elm.Counter.embed(node, { value : 0 });
counter.ports.change.subscribe(value => {
document.querySelector('.value').textContent = value;
});
var controls = document.getElementById('controls');
controls.addEventListener('reset', function (e) {
counter.ports.set.send(0);
});

<dom-module id="my-counter-controls">
<template>
<p>Controls: <button on-click="reset">Reset</button></p>
</template>
<script>
(function () {
Polymer({
is: "my-counter-controls",
reset() {
this.fire('reset');
},
})
})();
</script>
</dom-module>




Counter value
Counter
Counter reset
<p>
In the document,<br>
the value is <span class="value">1</span>
</p>
<my-elm-counter id="counter" value=1></my-elm-counter>

var counter = document.getElementById('counter');
counter.addEventListener('value-changed', function (e) {
document.querySelector('.value').textContent = e.detail.value;
});

var app;
Polymer({
is: "my-elm-counter",
properties: {
value: {
type: Number,
value: 0,
notify: true,
},
},
reset() {
this.value = 0;
app.ports.set.send(this.value);
},
ready() {
app = Elm.Counter.embed(this.$.embed, { value : this.value });
app.ports.change.subscribe(value => {
this.value = value;
});
},
});




Counter value
Counter
Counter reset
onValueChanged tagger =
on "value-changed" <| Json.map tagger detailValue
value =
attribute "value"
myCounter =
node "my-counter"
view : Model -> Html Msg
view model =
div []
[ myCounter [ value <| toString model , onValueChanged Change ] []
, p []
[ text "Controls:"
, button [ onClick Reset ] [ text "Reset" ]
]
]

Polymer + Elm = ?
paperCard =
node "paper-card"
paperButton =
node "paper-button"
view : Model -> Html Msg
view model =
div []
[ paperCard
[ attribute "heading" ("Counter: " ++ (toString model)) ]
[ div [ class "card-content" ] [ text (toString model) ]
, div [ class "card-actions" ]
[ paperButton [ onClick Decrement ] [ text "Decrement" ]
, paperButton [ onClick Increment ] [ text "Increment" ]
]
]
]

The content is not updated
<script>
window.Polymer = {
dom: 'shadow',
lazyRegister: true
};
</script>

Solution I - Disable Shady DOM
But it only works with native Shadow DOM...
view : Model -> Html Msg
view model =
Html.Keyed.node "div"
[]
[ ( toString model
, paperCard [ attribute "heading" ("Counter: " ++ (toString model)) ]
[ div [ class "card-content" ] [ text (toString model) ]
, div [ class "card-actions" ]
[ paperButton [ onClick Decrement ] [ text "Decrement" ]
, paperButton [ onClick Increment ] [ text "Increment" ]
]
]
)
]
Solution II - Use Elm Html.Keyed.node

Q/A

github.com/kevinlebrun/elm-polymer
Elm+Polymer=?
By Kevin Le Brun
Elm+Polymer=?
How to integrate Polymer in your stack?
- 2,815