如何在范围内的所有指令准备好后运行事件?

时间:2012-11-06 17:21:32

标签: javascript angularjs

我正在使用修改DOM的指令,因此必须在调用所有postLink fns之后完成。 (see angular-ui modules/directives/select2/select2.js:103

鉴于某些先决条件(未在URL中编码),我想将焦点设置为页面上的第一个select2元素。这是有问题的,因为在设置焦点之前,必须初始化select2,并且没有一些俗气的任意延迟> 0,我无法安排广播的事件来设置焦点。

我创建了以下指令,该指令将侦听焦点primaryInput / focus事件并设置焦点。

# TODO - should we create a directive for tab order instead?
app.directive "primaryInput", () ->
  {
    name: "primaryInput"
    link: (scope, element, attrs) ->
      scope.$on "primaryInput/focus", ->
        element.focus()
  }

更改primaryInput指令优先级不起作用,因为任何优先级将在调度setTimeout函数之前运行。

理想情况下,我希望能够拥有一个promises集合,每个promise将每个延迟指令推送到一个堆栈,然后一个promise将在所有这些promise完成后得到解决。我会把我的问题集中在如何最好地实现这个目标上,但我已经想到了一种不太好的方法,想要探索更好的方法,并且想要避免使用XY problem

谢谢!

更新

在完成这里描述问题的努力后退了一步,我想到了一个可接受的方法解决我的问题,并会回答我自己的问题,但如果有人有更好的方法,请保持开放。

1 个答案:

答案 0 :(得分:1)

由于延迟执行复杂性在处理Select2的指令中,我现在决定将那种复杂性隔离开来。

我覆盖了Select2指令中元素的焦点函数,因此焦点调用一旦可用就转发到select2实例。这样,可以告诉元素在select2之前聚焦。

我的焦点指示:

app.directive "input", ($injector) ->
  primaryMatcher = (e,attrs) ->
    attrs.primary?
  {
    name: "inputFocus"
    restrict: 'E'
    link: (scope, element, attrs) ->
      scope.$on "focus", (e, matcher)->
        if ((matcher || primaryMatcher)(element, attrs))
          console.log("focus", element, attrs)
          element.focus()
  }

在我的Select2指令中:

app.directive "s2Factor", () ->
  # ...
  {
    name: "s2Factor"
    require: "?ngModel"
    priority: 1
    restrict: "A"
    link: (scope, el, attr, controller) ->
      select2_p = $.Deferred()
      # ...
      setTimeout ->
        el.select2 opts
        select2_p.resolve(el.data("select2"))

      el.focus = () ->
        select2_p.then (select2) ->
          select2.focus()
  }

它涉及实例猴子修补,但我发现在这种情况下它是可以接受的。