Mithril.js でちょっとはまった(いや、かなり)

2015年9月29日

Mithril.jsを始めてみて、早速というか、すごく初歩的な事かもしれないけど

バーチャルDOMという事での罠にはまりました。

バーチャルDOMはバーチャルな訳ですよ。

バーチャル

ということは、実際にリアルにはそこに無いわけで

何を言っているかわからないと思うが

もう少し具体例を出すと

Mithril.jsで動的にul・liのリスト構造を表示させる。

このul・liの各アイテムは、ドラッグ&ドロップ出来るようにする。

ドラッグ&ドロップは、sortable.jsという感じの別のjsライブラリを使う。

var MyComponent = {
  controller: function() {
    return({
      list: [1,2,3,4,5];
    });
  },

  view: function(ctrl) {
    return([
      m('ul#sortedList', [
        ctrl.list.forEach( function(item) {
          m('li', m('div', item));
        });
      ]);
    ]);
  }
}

m.mount(document.body, MyComponent);

$('#sortedList').sortable({});

といった感じでリストを出力したいと思います。

このリストをドラッグ&ドロップにしたいときに、最初は上記のように

m.mountの行の下に置いてみました。

この場合、たまに動くけど、たまに動かないといった微妙な挙動になり、結構悩みました。

で、よくよく考えたら、m.mountをした時点でバーチャルがギリギリリアルになっていないのではないか?

という事でした。

たぶんこれはビンゴで、実際どのように解決したのかというと

mというメソッドの第2パラメータにconfigアトリビュートを追加します。

configというのは、リアルDOMの描画が終わった後に処理をさせたい内容を定義できる特殊なアトリビュートという事のようです。

sortableLoad = function(element, isInit, context) {
  //don't redraw if we did once already
  if (isInit) return;

  var ctx = element.getContext("2d");
  /* draws stuff */

  $(element).sortable({});
}

var MyComponent = {
  controller: function() {
    return({
      list: [1,2,3,4,5];
    });
  },

  view: function(ctrl) {
    return([
      m('ul#sortedList', {config: sortableLoad}, [
        ctrl.list.forEach( function(item) {
          m('li', m('div', item));
        });
      ]);
    ]);
  }
}

m.mount(document.body, MyComponent);

先ほどのコードを、このような形に修正することで、

$('#sortedList’)が実際に描画された後に、sortableLoadというメソッドが呼び出されるようになります。

めでたし!

アンケート