Elm => Javascript – What is Elm? – main-loop



Elm => Javascript – What is Elm? – main-loop

0 0


elm-to-js-slides


On Github JuanCaicedo / elm-to-js-slides

Elm => Javascript

Who am I?

What are we going to talk about?

  • Good things about Elm
  • main-loop
  • hyperscript-helpers
  • Rendering arbitrary lists
  • Updating functionally

What is Elm?

  • Compile to js
  • Fully functional
  • Flux architecture

Why is that good?

  • Testable
  • Refactorable
  • Easy to find errors

main-loop

Wire up the virtual dom

              
var mainLoop = require('main-loop');
var vdom = require('virtual-dom');

var render = function(state) {
  // Code for rendering a view
};

var initialState = {
  title: 'test'
};

var loop = mainLoop(initialState, render, vdom);

document.querySelector('#content').appendChild(loop.target);
              
            

Then call update

              
loop.update({
  title: 'new title'
});
              
            

hyperscript-helpers

Write html like Elm

In Elm

              
render state =
  h1 [] [ text state.title ]
              
            

In Javascript

              
var hh = require('hyperscript-helpers');
var h1 = hh.h1;

var render = function(state){
  h1('.title', state.title);
};
              
            

Rendering arbitrary lists

Initial state

              
/* Initial state */
var initialState =  {
  selectedLegislators: [{
    firstName: 'Juan',
    lastName: 'Caicedo'
  }, {
    firstName: 'Foo',
    lastName: 'Bar'
  }],
  availableLegislators: [{
    firstName: 'Senator',
    lastName: 'One'
  }, {
    firstName: 'Congresswoman',
    lastName: 'Two'
  }]
};
              
            

Main render function

              
var render = function (state) {
  return div('.container', [
    legislatorTableView('Your Team', state.selectedLegislators),
    legislatorTableView('Available', state.availableLegislators)
  ]);
};
              
            

Single table

              
var legislatorTableView = function (title, legislators) {
  return div('.col-xs-6', [
    h1(title),
    table('.table.table-striped', [
      tbody(
        R.map(legislatorView, legislators)
      )
    ])
  ]);
};
              
            

Single row

              
var legislatorView = function (legislator) {
  return tr('.container-fluid', [
    td('.col-xs-6', legislator.firstName),
    td('.col-xs-6', legislator.lastName)
  ]);
});
              
            

Dealing with updates

Create Actions

              
var action = function(type, data) {
  return {
    type: type,
    data: data
  };
};
              
            

Instantiate Event Emmiter

              
var emitter = new EventEmitter();
              
            

Set up an address

              
function address(action) {
  emitter.emit('update', action);
};
              
            

Listen to update events

              
emitter.on('update', function(action) {
  var newState = update(loop.state, action);
  loop.update(newState);
});
              
            

Calculate a new state

              
var update = function (state, action) {
  var newSelected;
  var newAvailable;

  // fallback case
  var newState = state;

  if (action.type === 'Drop') {
    // move from Selected to Available
  } else if (action.type === 'Select') {
    // move from Available to Selected
  }
  return newState;
};
              
            

How do you do that?

              
newSelected = R.append(action.data, state.selectedLegislators);
newAvailable = R.reject(R.equals(action.data), state.availableLegislators);

newState = R.merge(state, {
  selectedLegislators: newSelected,
  availableLegislators: newAvailable
});
              
            

Pass address to render

              
var render = R.curry(function (address, state) {
  return div('.container', [
    legislatorTableView(address, 'Drop', 'Your Team', state.selectedLegislators),
    legislatorTableView(address, 'Select', 'Available', state.availableLegislators)
  ]);
});
              
            

Update how we instantiate loop

              
var loop = mainLoop(initialState, render(address), vdom);
              
            

Pass address and type to table

              
var legislatorTableView = function (address, type, title, legislators) {
  return div('.col-xs-6', [
    h1(title),
    table('.table.table-striped', [
      tbody(
        R.map(legislatorView(address, type), legislators)
      )
    ])
  ]);
};
              
            

Pass address and type to legislatorView

              
var legislatorView = R.curry(function (address, type, legislator) {
  return tr('.container-fluid', {
    onclick: function(ev) {
      address(action(type, legislator));
    }
  }, [
    td('.col-xs-6', legislator.firstName),
    td('.col-xs-6', legislator.lastName)
  ]);
});
              
            

More resources

Elm => Javascript