fbonetti / elm-rails

View helpers for incorporating Elm modules into Rails views
MIT License
75 stars 20 forks source link

Working with Turbolinks #23

Open ghivert opened 7 years ago

ghivert commented 7 years ago

Hello !

I'm trying to use elm-rails to render elm on a rails server using turbolinks. However, turbolinks badly handle elm-embed tags. On first load, the javascript is correctly loaded, but if I load the page through turbolinks, the javascript is not executed (and it's rather bad because all HTML is written in Elm).

Any idea to fix this ?

kirchner commented 7 years ago

I think, when using turbolinks, rather then adding an event listener for DOMContentLoaded, you have to use the events provided by turbolinks (here is a list). So the js loading your elm app should look sth like this:

document.addEventListener('turbolinks:load', () => {
  const node = document.getElementById('elm-container');

  Elm.Main.embed(node);
});

You still could run into the problem that your elm app is loaded several times on revisits to the page containing this javascript. (Not on hard reloads using the browser.)

aaronshim commented 7 years ago

@kirchner Are there suggestions on how to avoid the problem of the Elm app loading several times? I've tried the following approach but I'm wondering whether there are saner solutions:

document.addEventListener('turbolinks:load', () => {

  // Only load if Elm hasn't previously loaded
  if (document.getElementsByClassName('elm-already-run').length == 0) {

    // Use global state to mark as already having run-- eww!
    let marker = document.createElement('div');
    marker.className = 'elm-already-run';
    document.body.appendChild(marker);

    const node = document.getElementById('elm-container');
    Elm.Main.embed(node);
  }
})
kirchner commented 7 years ago

@aaronshim we ended up doing sth like this

// app/javascript/packs/elm_app.js

import Elm from ‘ElmApp/Main’

$(“#elm-container”).empty();

const container = $(“#elm-container”)
const flags = JSON.parse($(“#elm-flags”).data(“data-flags”))

var app = Elm.ElmApp.Main.embed(container, flags)

where the html template looks like this

// app/views/foos/show.html.slim

#elm-container
#elm-flags(data-flags=@flags.to_json)

= javascript_pack_tag “elm_app”

probably not so much better i think =)