0

我正在使用修改 DOM 的指令,因此必须在调用所有 postLink fns 后完成。(参见 angular-ui 模块/指令/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 函数之前运行。

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

谢谢!

更新

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

4

1 回答 1

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()
  }

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

于 2012-11-06T18:16:55.957 回答