web-dev-qa-db-ja.com

BackBonejsでビューをレンダリングする際にjavascriptを呼び出す。レンダリング後のコールバック?

見よ、バックボーンビューのレンダリング呼び出し:

render: function() {
  $(this.el).html(this.template({title: 'test'}));  //#1
  this.renderScatterChart();
  return this;
},

だから、私は#1で標準レンダリングを呼び出します。次に、divを検索するメソッド[今回は、libをグラフ化するためのラッパーです]を呼び出します。 divはrender呼び出しによってレンダリングされます。しかし、この時点では、まだDOMに接続されていません(右?)。そのため、チャートコールは悲しいことに死にます。

これのパターンは何ですか?レンダリング後のコールバックがあると聞いてみたいです。これを回避するためにいくつかのハックを試しましたが、チャートが機能することもありますが、イベントがバインドされません。

22
whatbird

この種のことに対する私の通常のアプローチは、ブラウザが再び制御を取得したときに何かが発生するように調整するために、タイムアウトがゼロの setTimeout を使用することです。これを試して:

_render: function() {
    $(this.el).html(this.template({title: 'test'}));

    var _this = this;
    setTimeout(function() {
        _this.renderScatterChart();
    }, 0);

    return this;
}
_

または、renderScatterChartがすでに適切なthisにバインドされている場合:

_render: function() {
    $(this.el).html(this.template({title: 'test'}));
    setTimeout(this.renderScatterChart, 0);
    return this;
}
_

何をしているのかをより明確にしたい場合は、 __.defer_ を使用することもできます。

defer_.defer(function, [*arguments])

setTimeoutを遅延0で使用するのと同様に、現在の呼び出しスタックがクリアされるまで関数の呼び出しを延期します。

したがって、次のようにすることもできます。

_// Assuming that `renderScatterChart` is bound to the appropriate `this`...
render: function() {
    $(this.el).html(this.template({title: 'test'}));
    _(this.renderScatterChart).defer();
    return this;
}

// or if it isn't bound...
render: function() {
    $(this.el).html(this.template({title: 'test'}));

    var _this = this;
    _(function() {
        _this.renderScatterChart();
    }).defer();

    return this;
}
_
45
mu is too short

私はこれが答えられることを知っています、しかし私が共有するだろうと思いました。 Underscore jsは、これを_.defer関数でカバーしています。

render: function() {
    $(this.el).html(this.template({title: 'test'}));  //#1
    _.defer( function( view ){ view.renderScatterChart();}, this );
    return this;
},

アンダースコアのドキュメントによると、これは事実上、受け入れられているソリューションと同じです。

26
Xesued

これは、.elがDOMに挿入される前にrenderを実行するためです。私の自明のコードを確認してください(Backbone.jsが含まれている空白のページで実行してください):

function someThirdPartyPlugin(id){
   if( $('#' +id).length ===0  ){
    console.log('Plugin crashed');
   }else{
    console.log('Hey no hacks needed!!!'); 
   }
}

var SomeView = Backbone.View.extend({
    id : 'div1',
    render : function(){
      this.$el.append("<p>Hello third party I'm Backbone</p>");
      someThirdPartyPlugin( this.$el.attr('id') );
      return this;
  }
}); 
var SomeView2 = Backbone.View.extend({
    id : 'div2',
    render : function(){
      this.$el.append("<p>Hello third party I'm Backbone</p>");
      someThirdPartyPlugin( this.$el.attr('id') );
      return this;
  }
}); 

var myView1 = new SomeView();
$('body').append( myView1.render().el );
var myView2 = new SomeView2();
$('body').append( myView2.el );
myView2.render();
3
Daniel Aranda

あなたがしたのと同じ問題を抱えていました...ハイチャートで。私はBackbone.LayoutManagerを使用していて、postRenderコールバックを追加するためにコードをハッキングすることになりました。これをBackbone.jsの一部として見たい

1
Shreyas

これを行うことができます(renderSactterChartが「jQuery化」オブジェクトで動作する場合):

render: function() {
  this.$el.html(this.template({title: 'test'}));  //#1
  this.$el.renderScatterChart();
  return this;
},

(これは実際のDOM要素ではありません...)

1
Andy

setTimeoutハックを使用したくない場合は、この方法の方が「通常」だと思います。

render()によって追加された要素を操作する必要がある関数に$ el要素を渡すだけで、$ elでDOM操作を実行できます。

1
dotslashlu

これは次のように行う必要があります。

render: function() {
  Marionette.ItemView.prototype.render.apply(this, arguments);
  your code ...
}

マリオネットを使用したサンプルですが、アイデアはバックボーンビューでも機能します

0
user2846569

さて、これはすでに答えられていますが、将来の参考のために、私はこの問題を数回経験しました。カスタムイベントを追加して解決しました。この場合は、次のようになります。

render: function() {
  $(this.el).html(this.template({title: 'test'}));  //#1

  this.on('someView:append', function() {
      this.renderScatterChart();
  }, this);

  return this;
}

そして、要素をDOMに追加すると、次のようにトリガーします。

myView.trigger('someView:append');

さて、それは確かに美しい解決策ではありません。レンダリングされたビューをDOMに追加するものに、このイベントをトリガーする責任を追加します。コードの構造に応じて、適合性が向上または低下する可能性があります。繰り返しになりますが、私はこれを将来の参考資料および代替案として投稿しています。

詳細: http://backbonejs.org/#Events

0
julioolvr