将模型传递给自定义指令 - 清除文本输入

时间:2015-06-14 11:28:44

标签: angularjs angularjs-directive

我想要实现的目标相对简单,但我已经用这个问题进行了很长时间,现在是时候寻求帮助了。

基本上,我创建了一个由文本输入和清除它的链接组成的指令。

我通过一个工作正常的属性传入id,但是我似乎无法弄清楚如何在点击重置链接时传递模型以清除它。

这是我到目前为止所做的:

在我看来:

<text-input-with-reset input-id="the-relevant-id" input-model="the.relevant.model"/>

我的指示:

app.directive('textInputWithReset', function() {

  return {
      restrict: 'AE',
      replace: 'true',
      template: '<div class="text-input-with-reset">' +
                  '<input ng-model="inputModel" id="input-id" type="text" class="form-control">' +
                  '<a href class="btn-reset"><span aria-hidden="true">&times;</span></a>' +
                '</div>',
      link: function(scope, elem, attrs) {
        // set ID of input for clickable labels (works)
        elem.find('input').attr('id', attrs.inputId);

        // Reset model and clear text field (not working)
        elem.find('a').bind('click', function() {
          scope[attrs.inputModel] = '';
        });
      }
  };

});

我显然缺少一些基本的东西 - 任何帮助都会受到高度赞赏。

3 个答案:

答案 0 :(得分:0)

在您重置值的函数中重置scope.$apply()后,您应该致电inputModel

elem.find('a').bind('click', function() {
      scope.inputModel = '';
      scope.$apply();
    });

请阅读AngularJS here中的范围。

  

$ apply()用于从角度框架外部以角度执行表达式。 (例如,来自浏览器DOM事件,setTimeout,XHR或第三方库)。因为我们正在调用角度框架,所以我们需要执行异常处理的适当范围生命周期,执行监视。

我还在你的指令范围内添加了inputModel属性的声明。

scope: {
    inputModel: "="
  }

See demo on plunker.

但是如果您可以在模板中使用ng-click - 使用它,那就更好了。

答案 1 :(得分:0)

好的,我似乎已经通过使用指令范围并在模板中使用ng-click来修复它:

我的观点:

<text-input-with-reset input-id="the-relevant-id" input-model="the.relevant.model"/>

我的指示:

app.directive('textInputWithReset', function() {

  return {
    restrict: 'AE',
    replace: 'true',
    scope: {
      inputModel: '='
    },        
    template: '<div class="text-input-with-reset">' +
                '<input ng-model="inputModel" id="input-id" type="text" class="form-control">' +
                '<a href ng-click="inputModel = \'\'" class="btn-reset"><span aria-hidden="true">&times;</span></a>' +
              '</div>',
    link: function(scope, elem, attrs) {
      elem.find('input').attr('id', attrs.inputId);
  };

});

答案 2 :(得分:0)

看起来你已经回答了你的问题,但我会在这里留下我的答案,以便进一步解释,以防其他人遇到同样的问题。

在当前状态下,您的指令有两个问题:

  1. 点击处理程序将在Angular的摘要周期之外触发。基本上,即使您设法清除模型的值,Angular也不会知道它。你可以在scope.$apply()调用中包装你的逻辑来解决这个问题,但在这种情况下它不是正确的解决方案 - 继续阅读。

  2. 通过scope[attrs.inputModel]访问范围会评估为scope['the.relevant.model']。显然,模型的名称不是字面the.relevant.model,因为点通常意味着嵌套而不是名称的字面部分。您需要一种不同的方式来引用模型。

  3. 您应该使用隔离范围(请参阅herehere)来获取此类指令。基本上,你修改你的指令看起来像这样:

    app.directive('textInputWithReset', function() {
    
      return {
          restrict: 'AE',
          replace: 'true',
          template: [...],
    
          // define an isolate scope for the directive, passing in these scope variables
          scope: {
              // scope.inputId = input-id attribute on directive
              inputId: '=inputId',
              // scope.inputModel = input-model attribute on directive
              inputModel: '=inputModel'
          },
    
          link: function(scope, elem, attrs) {
            // set ID of input for clickable labels (works)
            elem.find('input').attr('id', scope.inputId);
    
            // Reset model and clear text field (not working)
            elem.find('a').bind('click', function() {
              scope.inputModel = '';
            });
          }
      };
    
    });
    

    请注意,在定义隔离范围时,该指令会使用请求的变量获取自己的范围。这意味着您只需在指令中使用scope.inputIdscope.inputModel,而不是尝试以迂回方式引用它们。

    这是未经测试的,但它应该非常有效(您需要使用我之前提到的scope.$apply()修复)。您可能希望测试inputId绑定,因为您现在可能需要传递一个文字字符串(例如,在属性中放置'input-id'以指定它是文字字符串,而不是{{1}这意味着范围中有一个input-id变量。

    在你的指令工作之后,让我们尝试以“Angular方式”使其更加有效。既然您的指令中有隔离范围,则无需在链接函数中实现自定义逻辑。每当您的链接函数有input-id.click()时,可能有更好的方法来编写它。

    在这种情况下,您可以使用更多内置的Angular逻辑来简化指令,而不是在.attr()函数中手动修改DOM:

    link()

    现在,您所有的<div class="text-input-with-reset"> <input ng-model="inputModel" id="{{ inputId }}" type="text" class="form-control"> <a href="#" class="btn-reset" ng-click="reset()"><span aria-hidden="true">&times;</span></a> </div> 函数(或者,更好的是,您的指令的控制器)需要做的是在作用域上定义link()函数。其他一切都将自动生效!