【问题标题】:angularjs two directives on one elementangularjs 一个元素上的两个指令
【发布时间】:2013-12-09 12:26:11
【问题描述】:

我有两个指令:

// Generated by CoffeeScript 1.6.3
app.directive("focusMe", function() {
  return {
    scope: {
      focus: "=focusMe"
    },
    link: function(scope, element) {
      return scope.$watch("focus", function(value) {
        if (value === true) {
          element[0].focus();
          return scope.focus = false;
        }
      });
    }
  };
});

和:

// Generated by CoffeeScript 1.6.3
app.directive("cleanMe", function() {
  return {
    scope: {
      clean: "=cleanMe"
    },
    link: function(scope, element) {
      return scope.$watch("clean", function(value) {
        if (value === true) {
          element[0].value = "";
          return scope.clean = false;
        }
      });
    }
  };
});

这个输入(angularUI):

<input type="text" ng-model="addUserSelected" typeahead="emp.value for emp in allUsers | filter:$viewValue | limitTo:5" typeahead-editable="false" typeahead-on-select="addLine($item.id)" focus-me="usersFocusInput" clean-me="usersCleanInput">

我收到此错误:

Error: [$compile:multidir] http://errors.angularjs.org/1.2.3/$compile/multidir?p0=cleanMe&p1=focusMe&p…2%20focus-me%3D%22usersFocusInput%22%20clean-me%3D%22usersCleanInput%22%3E

我做错了什么?

如果我从 html 中删除 clean-me 属性,它会起作用。

谢谢

【问题讨论】:

  • 为什么不重置ng-model 绑定的模型?我怀疑你不需要cleanMe 指令
  • cleanMe 没有意义,它可以是任何 2 个(或更多)指令。 clean-me 和 focus-me 仅用于示例。

标签: javascript angularjs angularjs-directive


【解决方案1】:

这里没有真正需要孤立的作用域。使用“正常”指令范围,该指令将仅从父级继承,如下所示:

// Generated by CoffeeScript 1.6.3
app.directive("focusMe", function() {
  return {
    link: function(scope, element, attrs) {
      return scope.$watch(attrs.focusMe, function(focusMe) {
        if (focusMe.value === true) {
          element[0].focus();
          return scope[attrs.focusMe].value = false;
        }
      });
    }
  };
});

// Generated by CoffeeScript 1.6.3
app.directive("cleanMe", function() {
  return {
    link: function(scope, element, attrs) {
      return scope.$watch(attrs.cleanMe, function(cleanMe) {
        if (cleanMe.value === true) {
          element[0].value = "";
          return scope[attrs.cleanMe].value = false;
        }
      });
    }
  };
});

如果您已经知道继承是如何工作的,请忽略这部分,只是为了完整性而添加:

请注意,我使用的是 [attrs.focusMe].value,而不仅仅是 [attrs.focusMe]。原因是继承在 javascript 中是如何工作的。这些指令是子作用域,因此如果您尝试执行 scope[attrs.focusMe] = false,您将在指令作用域中设置一个局部变量,即您不会影响父作用域(控制器在哪里使用)。但是,如果您将 focusMe 模型(无论它是什么)设为父范围内的对象,然后更改该对象上的值,那么它不会设置局部变量,而是会更新父范围.所以:

scope[attrs.focusMe] = false; // Sets a local variable, does not affect the parent
scope[attrs.focusMe].value = false; // Updates focusMe on the parent

如果您想要深入的指南,这里有一个关于继承的好答案:What are the nuances of scope prototypal / prototypical inheritance in AngularJS?

【讨论】:

  • 修复了范围错误,当然应该是 scope[attrs.focusMe].value 而不是 scope.focusMe.value。您希望 focusMe 属性指出的范围变量。此外,如果您提供的值不在“根”上,例如 something.usersFocusInput,那么更改它需要更多的努力。
【解决方案2】:

您有两个指令需要在同一元素上隔离范围,这是不允许的。

不允许这样做的原因是,如果指令中有一些模板 {{...}} 代码,则不清楚它应该从哪个范围获取其值。

考虑使用attribute.$observe 来观察cleanMefocusMe 属性并对其进行操作,而不是隔离作用域。

app.directive("focusMe", function() {
  return {
    link: function(scope, element, attributes) {
      attributes.$observe("focusMe", function(value) {
        if (value === true) {
          element[0].focus();
          scope.focus = false;
        }
      });
    }
  };
});

和:

app.directive("cleanMe", function() {
  return {
    link: function(scope, element, attributes) {
      attributes.$observe("cleanMe", function(value) {
        if (value === true) {
          element[0].value = "";
          return scope.clean = false;
        }
      });
    }
  };
});

【讨论】:

  • 首先感谢您的帮助!这个解决方案对我来说有两个问题:第一个“值”等于“usersFocusInput”,而不是范围 $scope.usersFocusInput 中的参数值,它应该是真/假。第二个 scope.clean 未定义,我想将 $scope.usersFocusInput 替换回 false。
  • @Noampz 然后你想使用scope.$parent.watch(attributes['focusMe'], ...) 并设置scope.$parent[attributes['focusMe']] = falsecleanMe 也是如此。这对你有用吗?
  • 为什么不只是 scope.$watch(attributes.focusMe)?
  • 除非指令继承从 1.1 分支更改为应该可以正常工作的 1.2 分支,因为指令将从使用它的范围继承。
  • @ErikHonn 除非在当前范围内不小心定义了“focusMe”。使用$scope.$parent 将避免该错误。此外,在覆盖属性时,需要使用$scope.$parent,以免在本地范围内正确写入。
【解决方案3】:

我终于找到了解决办法:)

// Generated by CoffeeScript 1.6.3
app.directive("focusMe", function() {
  return {
    link: function(scope, element, attributes) {
      return scope.$watch(attributes.focusMe, function(value) {
        if (scope[value] === true) {
          element[0].focus();
          return scope[attributes.focusMe] = false;
        }
      });
    }
  };
});

// Generated by CoffeeScript 1.6.3
app.directive("cleanMe", function() {
  return {
    link: function(scope, element, attributes) {
      return scope.$watch(attributes.cleanMe, function(value) {
        if (value === true) {
          element[0].value = "";
          return scope[attributes.cleanMe] = false;
        }
      });
    }
  };
});

在 html 中 usersFocusInput 和 usersCleanInput 是范围内的参数,我使用 scope[attributes.focusMe] 获取此参数并将其更改为 false。

<input type="text" ng-model="addUserSelected" typeahead="emp.value for emp in allUsers | filter:$viewValue | limitTo:5" typeahead-editable="false" typeahead-on-select="addLine($item.id)" focus-me="usersFocusInput" clean-me="usersCleanInput">

【讨论】:

  • 关闭,但不完全。 :) 请注意, scope[attributes.focusMe] = false 将在指令中设置一个局部变量,它不会更新父控制器。为此,您需要将其设为对象(或使用 $parent)。在上面/下面/任何地方查看我的答案。
猜你喜欢
  • 2014-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-07
  • 2014-04-02
  • 2016-09-14
  • 1970-01-01
相关资源
最近更新 更多