从另一个指令

时间:2015-10-29 20:11:50

标签: angularjs angular-directive

我目前正在将ng-model-options指令添加到我的多个输入框中以进行去抖动。我的元素看起来像这样:

<input type="text" ng-model="search" ng-model-options="{ debounce: { 'default': 200 } }" />

我想把它放在一个指令中:

  1. 我的标记不那么繁琐。
  2. 我可以在一个地方控制去抖值,以防我想要改变它。
  3. 我最终希望标记看起来像这样使用debounce指令:

    <input type="text" ng-model="search" debounce />
    

    我试图像这样实现这个指令:

    app.directive('debounce', ['$compile', function ($compile) {
        return {
            restrict: 'A',
            replace: false,
            link: function (scope, element, attrs) {
                element.attr('ng-model-options', "{ debounce: { 'default': 200 } }");
                $compile(element.contents())(scope);
            }
        }
    }]);
    

    它似乎会产生正确的HTML,但是去抖动没有做任何事情。我的指令有什么问题?

3 个答案:

答案 0 :(得分:1)

为了做同样的事情,你需要添加更高priority的指令,以避免编译其他指令&amp;将terminal选项设置为true。这表明当该指令运行时没有其他指令,然后从该指令运行remove指令属性&amp;添加ng-model-options以应用去抖动更改。

  

删除debounce属性是必要的,以避免无限编译

<强>指令

app.directive('debounce', ['$compile', function ($compile) {
  return {
    restrict: 'A',
    priority: 1,
    terminal: true, 
    compile: function(element, attrs) {
      //compile when scope is not linked to the DOM.
      element.attr('ng-model-options', "{ debounce: { 'default': 200 } }");
      element.removeAttr('debounce'); //this removal is necessary to avoid infinite compile
      var compile = $compile(element);
      return function (scope, element, attrs) {
        var link = compile(scope);
      };
    } 
  }
}]);

答案 1 :(得分:1)

实际上你甚至不需要访问该元素。您可以在ngModel控制器的$options属性中设置选项,并设置如下所需的值:

ctrl.$options = {debounce:{default:300}, updateOnDefault: true};

代码:

.directive('debounce', ['$timeout',
  function($timeout) {
    return {
      restrict: 'A',
      require: 'ngModel',
      link: function(scope, element, attrs, ctrl) {
        var options = ctrl.$options || {};

        ctrl.$options = angular.extend(options, {
          debounce: {
            default: 300
          },
          updateOnDefault: true
        });

      }
    }
  }
]);

&#13;
&#13;
angular.module('app', []).directive('debounce', ['$timeout',
  function($timeout) {
    return {
      restrict: 'A',

      require: 'ngModel',
      replace: false,

      link: function(scope, element, attrs, ctrl) {
        var options = ctrl.$options || {};
        
        ctrl.$options = angular.extend(options || {}, {
          debounce: {
            default: 300
          },
          updateOnDefault: true
        });
        
       
      }
    }
  }
]).controller('test', function() {
  this.callMe = function() {
    console.log(this.search);
  }
});
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<div ng-app="app" ng-controller="test as vm">

  <input type="text" ng-model="vm.search" debounce ng-change="vm.callMe()" />
  <input type="text" ng-model="vm.search" ng-change="vm.callMe()" ng-model-options="{ debounce: { 'default': 200 } }" />{{vm.search}}
</div>
&#13;
&#13;
&#13;

如果您想通过接受去抖动值作为属性来使其更具可配置性,那么:

.directive('debounce', ['$timeout',
  function($timeout) {
    return {
      restrict: 'A',
      require: 'ngModel',
      link: function(scope, element, attrs, ctrl) {
        var options = ctrl.$options || {updateOnDefault: true};

        ctrl.$options = angular.extend(options, {
          debounce: {
            default:  +attrs.debounce || 300
          }
        });

      }
    }
  }
])

答案 2 :(得分:0)

在Angular中,动态添加指令给自己并不是很好。您通过编译处于正确的轨道上,但是ng-model指令已经在您执行此操作时进行了编译。

由于ngModel被记录为以优先级1运行,因此您需要同时为terminal并以优先级2运行,以便ng-model-options在适当的时间进行关联。

app.directive('debounce', ['$compile', function ($compile) {
  return {
    restrict: 'A',
    priority: 2,
    terminal: true,
    compile: function(tElement) {
      tElement.attr('ng-model-options', "{ debounce: { 'default': 200 } }");

      return function (scope, element, attrs, controllers, transclude) {
        $compile(element, null, 2)(scope, {
          parentBoundTranscludeFn: transclude
        });
      };
    } 
  }
}]);