使用带有嵌套视图的`afterRender`钩子 [英] Using `afterRender` hook with nested views

查看:98
本文介绍了使用带有嵌套视图的`afterRender`钩子的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果您希望先看到代码,这里是jsFiddle

我想做的是简单的:在当前路线中的所有视图完成渲染后,从jQuery和jsPlumb库中执行一些(实际上很多)视图层Javascript代码。在获得此解决方案的帮助之后,发现刚刚更新的ember-latest已经更新为包含 afterRender挂钩,我决定升级。我现在有全能的 afterRender 钩子。

What I want to do is simple: execute some (actually a lot) of view layer Javascript code from jQuery and jsPlumb libraries after ALL the views in the current route have finished rendering. After getting some help from this solution and finding that ember-latest has just been updated to include afterRender hook, I decided to upgrade. I now have the almighty afterRender hook.

我插入到dom中的所有视图都有一个与它们关联的类。所以我一直在测试的方式,看看所有的视图是否在dom中使用 $('。block')。size(),看看它是否匹配预期的数字。

All the views I am inserting into the dom have a block class associated with them. So the way I have been testing to see if all the views are in the dom is using $('.block').size() and seeing if it matches expected number.

然而,当我尝试在我的应用程序中使用这个钩子时,我面临一些问题。调用 connectOutlets 之后,首先尝试在路由器中调用 afterRender 。当我打印出dom中的块数时,我总是只得到1个块,而应该有10个。

However I am facing some issues when I try to use this hook in my application. I first tried to call the afterRender in the router, after the calls to connectOutlets. I always get only 1 block when I print out the number of blocks in dom while there should be 10.

如果我把这段代码放在 didInsertElement 视图:

If I put this code in didInsertElement of my local block view:

didInsertElement: () ->
    knob = this.$("##{@get 'knobId'}")
    name = this.$(".name")
    main = this.$(".main") #block html content will be injected into main
    knob.hide()

    Ember.run.scheduleOnce('afterRender', this, ()->
      console.log ">> block count: ", $(".block").size()
    )
    ...

然后我得到以下输出:

>> block count: 1
>> block count: 10
>> block count: 10
>> block count: 10
>> block count: 10
>> block count: 10
>> block count: 10
>> block count: 10
>> block count: 10
>> block count: 10

由于某些原因,第一次迭代我只得到1块在dom后,我得到所有10.我不知道为什么。但是这里的主要问题是,如果我把钩子放在 didInsertElement 之内,根据数据(在本例中为10),该代码将被执行任意数量的视图。但是,我只想在所有视图完成渲染后才运行一次代码。

For some reason the first iteration I only get 1 block in the dom and after that I get all 10. I am not sure why. But the main issue here is that if I put the hook inside didInsertElement, the code gets executed for an arbitrary number of views depending on data (in this example 10). However I only want to run this code once after all views have finished rendering.

请注意,我正在使用的视图具有嵌套数据。我试图在jsFiddle上复制,但我失败了,这似乎在工作所有人都在小提琴上找到和花花公子。也许是因为我的观点是大而复杂的,这是造成一些同步问题?无论如何,我想我们可以使用小提琴作为讨论解决方案的一种方式,我可以在本地进行测试。

Note that the view I am working with has nested data. I tried to reproduce this on jsFiddle, but I failed in the sense that it seems to work all find and dandy on the fiddle. Maybe because my views are big and complex it is causing some synchronization issues? In any event, I think we can use the fiddle as a way to discuss a solution and I can test it locally.

我试图解决这个问题的一个黑客是使用 Ember.run.later 。这在我的本地机器上解决了这个问题。但是,使用计时器这样做是非常羊粪,因为不同的浏览器或机器可能需要更长的时间来呈现视图。

One hack I tried to do to get around the issue is to schedule my code to run after 500ms delay using Ember.run.later. That did solve the issue on my local machine. However, using a timer to do this is very sheep dung and does not work reliably since different browsers or machines may take longer to render the views.

这是一个我已经花了很多时间尝试找到一个解决方案。我很乐意在这里重现问题或找到解决方案的任何帮助。

This is a though one to reproduce and I have already spent much time trying to find a solution. I would appreciate any help in reproducing the problem here or finding a solution.

编辑(解决方法):感谢帮助我解决这个问题问题,通过查看关于类似问题的这篇文章,我想出了以下临时解决方法,我将其放在路由器代码:

Edit (workaround): Thanks to look for helping me troubleshoot this problem, and by looking at this post about a similar problem, I came up with the following temporary workaround, which I put inside the router code:

    # Keep trying until there are two or more blocks in DOM
    blocksLoaded = ->
      console.log "blocks number ...: ", $('.block').size()
      if $('.block').size() > 1
        console.log "Yay!...we have ", $('.block').size()
        startTraversingBlocks()
      else
        Ember.run.next(this, ()->
          blocksLoaded()
        )

    blocksLoaded()

这将输出:

blockies number ...: 0
blockies number ...: 1
blockies number ...: 1
blockies number ...: 1
...
blockies number ...: 1
blockies number ...: 10
Yay!...we have 10

正如卢克指出出来,这里的问题是我的嵌套视图正在渲染几个RunLoops。当我刷新浏览器时,我在测试期间每隔4到10次之间得到不同数量的块号码...:1

As Luke pointed out, the problem here is that my nested views are being rendered over several RunLoops. when I refresh the browser I get a different number of blockies number ...: 1 output everytime, anywhere between 4 and 10 times during my tests.

在我看来,这不是一个很好的解决方案,但它似乎适用于我的用例。我觉得这里有一个钩子,允许一个访问DOM,当保证来自视图的所有元素都可以通过jQuery选择器访问,但也许我在这里缺少一些东西。

In my opinion this is not a very good solution, but it seems to work for my use case. I feel that there is a need here for another hook that allows one to access DOM when it is guaranteed all the elements from views are accessible through jQuery selectors, but perhaps I am missing something here.

推荐答案

我经历了Kris Selden的这个问题,他说:afterRender在渲染队列之后是完全刷新该运行循环的;我猜这是超过一个循环

I ran this question past Kris Selden, and he said "afterRender is after the render queue is totally flushed for that run loop; I'm guessing this is over more than one loop"

最有可能的是你有一个记录数组加载。也许它从一个项目开始,然后在后面加上9个负载。如果您排除数据加载,或许您有一个 Ember.run.next Ember.run.later 你的代码?

The most likely possibility is that you have a record array loading. Perhaps it starts with one item and then 9 more load in later. If you rule out data loading, perhaps you have an Ember.run.next or Ember.run.later somewhere in your code?

这篇关于使用带有嵌套视图的`afterRender`钩子的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆