読み書きプログラミング

日常のプログラミングで気づいたことを綴っています

Advent Calendar 5 - ライブHTMLの詳細

Meteorはでは、テンプレートHTMLにヘルパーメソッドでリアクティブなデータを盛り込むとそのHTMLの該当部分が自動的に更新されます。以下はMeteorの公式ドキュメントの例。

<body>
{{> players}}
</body>

<template name="players">
  {{#each topScorers}}
    <div>{{name}}</div>
  {{/each}}
</template>
Template.players.topScorers = function () {
  return Users.find({score: {$gt: 100}}, {sort: {score: -1}});
};

この再描画のメカニズムですが、HTML自体の書き直しです。なので再描画前のDOMの情報は保持されません。これは場合によっては困ります。例えば、Twitterウィジェットを表示する場合、何も工夫しないと描画がくずれてしまいます。

<head>
    <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
</head>
<body>
{{> timelines}}
</body>

<template name="timelines">
  {{#each timelines}}
  <a class="twitter-timeline" href="#" data-widget-id="{{this.widgetId}}"></a>
  {{/each}}
</template>
Template.timelines.timelines = -> share.Timeline.find()

くずれる理由は2つあって、1つにはTwitterウィジェットを追加したらウィジェットの描画を呼び出す必要があること、それからTLの更新はウィジェットに任せること、です。以下、修正版。

<head>
    <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
</head>
<body>
{{> timelines}}
</body>

<template name="timelines">
  {{#each timelines}}
    {{> timeline}}
  {{/each}}
</template>

<template name="timeline">
  {{#constant}}
  <a class="twitter-timeline" href="#" data-widget-id="{{this.widgetId}}"></a>
  {{/constant}}
</template>

>|coffee
Template.timelines.timelines = -> share.Timeline.find()

Template.timeline.created = -> @created = true
Template.timeline.rendered = ->
if @created
@created = false
twttr?.widgets.load()
|