4

問題空間

分割ペイン スタイルの UI を作成できるように、いくつかのネストされた Ember ビューをレンダリングしています。ビューが最初にレンダリングされるときにビューのサイズを変更して、幅が等しくなるようにしたいと考えています。子ビューを相互に見たくないので、サブクラスを使用してEmber.ContainerView、コンテンツとドラッグ可能なスプリッター ハンドルを保持しています。

Ember.View#didInsertElement子ビューが完全にレンダリングされるまで待つ必要があるため、コンテナー ビューでは使用できません。

私の(試みられた)解決策

この回答で提示されているコードを使用しています:テンプレートが完全にレンダリングされるのを待つ方法。これにより、Ember.View を再度開いてテンプレートが起動したときに自動的に設定さisRenderedれるすべてのEmber.Viewインスタンスにプロパティが追加されます。didInsertElement

Ember.View.reopen

  didInsertElement: ->
    res = @_super();
    @_setIsRendered();
    res

  _setIsRendered: ->
    if (!! @$())
      @set('isRendered', true)
    else
      Ember.run.next this, ->
        @_setIsRendered()

Ember.ContainerViewすべてのコンテナ ビューにプロパティを追加するために再度開いてみましchildViewsRenderedたが、Ember は反対し、childViews に項目が 1 つしかないコンテナ ビューに対して非常に奇妙な IndexOutOfBounds エラーをスローしました。

コレクションのコードを次の mixin に入れることになりました。

App.ChildrenRendered = Ember.Mixin.create

  childViewsRendered: (->
    res = @get('childViews').everyProperty('isRendered')
    console.log('childViewsRendered', res, this)

    # Pointer to this most offensive object for debugging
    window.wtf = this
    res
  ).property('childViews.@each.isRendered')

  _runChildViewsDidRender: (->
    if @get('childViewsRendered')
      console.log('trying to invoke childViewsDidRender')
      Ember.tryInvoke(this, 'childViewsDidRender')
  ).observes('childViewsRendered')

そして、私はこのようなクラスを持っています:

App.SplitterView = Ember.ContainerView.extend App.ChildrenRendered,
  # ...(some properties)...
  init: ->
    child_views = @get('childViews')
    child_views.pushObjects([App.WindowView.create(), App.WindowView.create()])

機能するもの:

  • App.SplitterView#childViewsRenderedビューがレンダリングされる前に一度計算されるため、false
  • ビューは Ember によって処理 (挿入およびレンダリング) され、独自のisRenderedプロパティが適切に設定されます。
  • 後で実行すると、window.wtf.get('childViews').everyProperty('isRendered')が返されますtrue

機能しないもの:

  • 計算されたプロパティchildViewsRenderedが再び更新されることはありません。
  • 配列要素メンバーのダミー値の計算されたプロパティchildViewも機能していないようです。
4

1 に答える 1

0

jsFiddleがないと、あなたが言ったこととあなたが提供したスニペットしか見ることができませんが、あなたがやろうとしているのは、何かをする前にコンテナのすべての子ビューがDOMにあることを確認することだけのようです.はい?

その場合...ビューが追加さchildViewsれると、ご存知のように、それらは自動的にレンダリングされ、DOM に挿入されます。これはすべて、同じ RunLoop 内で発生します。したがって、すべての子が「inDOM」になるまで関数の実行を遅らせるには、観察childViews.@eachEmber.run.nextて次の RunLoop まで実行を遅らせるのと同じくらい簡単です。ここに例があります

App.SomeContainerView = Em.ContainerView.extend
  init: ->
    @_super() # run default init
    # add 2 of our 4 views
    @get('childViews').pushObjects [@aView.create(), @bView.create()]

  # a non-cached (volatile) computed property to check if children are inDOM
  # just used for demo purposes
  childrenAreInDom: (->
    @get('childViews').every (v) ->
      v.state is "inDOM"
  ).property().volatile()

  # our observer
  observeChildren: (->
    # if the container isn't inDOM yet the afterRender function we add below 
    # will handle it, if views are added/removed after that then we handle it here
    return unless @state is "inDOM"
    # output to console if every childview are inDOM
    console.log "observeChildren", @get('childrenAreInDom')
    # the above will always be false since we're still in the same RunLoop
    # next RunLoop our function will run
    Ember.run.next @, 'doWhatever'
  ).observes('childViews.@each') # observe changes in the childViews array

  afterRender: ->
    console.log "afterRender", @get('childrenAreInDom')
    Ember.run.next @, 'doWhatever'

  # the function we want to run eventually after children are inDOM
  doWhatever: ->
    console.log "doWhatever"
    # print out childrenAreInDom one more time.. it will be true
    console.log "childrenAreInDom:", @get('childrenAreInDom')

  # some views to insert
  aView: Em.View.extend
    template: Em.Handlebars.compile("A")
  bView: Em.View.extend
    template: Em.Handlebars.compile("B")
  cView: Em.View.extend
    template: Em.Handlebars.compile("C")
  dView: Em.View.extend
    template: Em.Handlebars.compile("D")

テンプレートに {{view App.SomeContainerView}} を含めると、コンソールに次のように表示されます。

afterRender false
doWhatever
childrenAreInDom true 

コンテナーが既に DOM にある後、pushObjects を介してプログラムで cView & dView を追加すると、次のように表示されます。

observeChildren false
doWhatever
childrenAreInDom true 

これがまさにあなたが望むものではない場合でも、うまくいけば、Mixin のナンセンスなしで必要な場所に到達するのに役立ちます:D

于 2012-12-05T08:49:47.157 に答える