AngularJS - 创建一个使用ng-model的指令

17 浏览
0 Comments

AngularJS - 创建一个使用ng-model的指令

我想创建一个指令,该指令将创建具有与创建指令的元素相同的ng-model的输入字段。

到目前为止,我想到了以下内容:

HTML

<!doctype html>
  
  
  

  This scope value 
  


JavaScript

var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
  $scope.name = "Felipe";
});
app.directive('myDirective', function($compile) {
  return {
    restrict: 'E',
    scope: {
      ngModel: '='
    },
    template: '' +
      '',
    replace: true,
    require: 'ngModel',
    link: function($scope, elem, attr, ctrl) {
      $scope.label = attr.ngModel;
      $scope.id = attr.ngModel;
      console.debug(attr.ngModel);
      console.debug($scope.$parent.$eval(attr.ngModel));
      var textField = $('input', elem).
        attr('ng-model', attr.ngModel).
        val($scope.$parent.$eval(attr.ngModel));
      $compile(textField)($scope.$parent);
    }
  };
});

然而,我不确定这是处理此情况的正确方法,而且我的控件没有使用ng-model目标字段的值进行初始化的错误。

这是上面代码的Plunker:http://plnkr.co/edit/IvrDbJ

如何正确处理此问题?

编辑:从模板中删除ng-model =“value”后,似乎运作良好。但是,我将保持此问题处于打开状态,因为我想再次检查这是否是正确的做法。

admin 更改状态以发布 2023年5月22日
0
0 Comments

我汇总了所有答案,现在有两种使用ng-model属性的方法:

  • 使用新的作用域复制ngModel
  • 在链接中进行编译,使用相同的作用域
var app = angular.module('model', []);
app.controller('MainCtrl', function($scope) {
  $scope.name = "Felipe";
  $scope.label = "The Label";
});
app.directive('myDirectiveWithScope', function() {
  return {
    restrict: 'E',
    scope: {
      ngModel: '=',
    },
    // Notice how label isn't copied
    template: '',
    replace: true
  };
});
app.directive('myDirectiveWithChildScope', function($compile) {
  return {
    restrict: 'E',
    scope: true,
    // Notice how label is visible in the scope
    template: '',
    replace: true,
    link: function ($scope, element) {
      // element will be the div which gets the ng-model on the original directive
      var model = element.attr('ng-model');
      $('input',element).attr('ng-model', model);
      return $compile(element)($scope);
    }
  };
});
app.directive('myDirectiveWithoutScope', function($compile) {
  return {
    restrict: 'E',
    template: '',
    replace: true,
    link: function ($scope, element) {
      // element will be the div which gets the ng-model on the original directive
      var model = element.attr('ng-model');
      return $compile($('input',element).attr('ng-model', model))($scope);
    }
  };
});
app.directive('myReplacedDirectiveIsolate', function($compile) {
  return {
    restrict: 'E',
    scope: {},
    template: '',
    replace: true
  };
});
app.directive('myReplacedDirectiveChild', function($compile) {
  return {
    restrict: 'E',
    scope: true,
    template: '',
    replace: true
  };
});
app.directive('myReplacedDirective', function($compile) {
  return {
    restrict: 'E',
    template: '',
    replace: true
  };
});


.some {
  border: 1px solid #cacaca;
  padding: 10px;
}




  This scope value , label: "{{label}}"
  
  • With new isolate scope (label from parent):
  • With new child scope:
  • Same scope:
  • Replaced element, isolate scope:
  • Replaced element, child scope:
  • Replaced element, same scope:

Try typing in the child scope ones, they copy the value into the child scope which breaks the link with the parent scope.

Also notice how removing jQuery makes it so only the new-isolate-scope version works.

Finally, note that the replace+isolate scope only works in AngularJS >=1.2.0

我不确定我喜欢在链接时编译。然而,如果你只是用另一个元素替换它,那么就不需要这样做。

总的来说,我更喜欢第一种方法。只需将作用域设置为{ngModel:"="},并在模板中设置ng-model =“ngModel”

更新:我嵌入了代码片段并针对Angular v1.2进行了更新。事实证明,隔离作用域仍然是最好的选择,尤其是不使用jQuery时。因此它归结为:

  • 您是否要替换单个元素:只需替换它,保留作用域,但请注意,对于v2.0,替换已被弃用:

    app.directive('myReplacedDirective', function($compile) {
      return {
        restrict: 'E',
        template: '',
        replace: true
      };
    });
    

  • 否则使用此方法:

    app.directive('myDirectiveWithScope', function() {
      return {
        restrict: 'E',
        scope: {
          ngModel: '=',
        },
        template: ''
      };
    });
    

0
0 Comments

EDIT:这个答案已经老旧,可能已经过时了。只是提醒一下,不要误导其他人。我不再使用Angular,所以无法改进。


实际上,这是相当不错的逻辑,但你可以简化一些东西。

指令

var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
  $scope.model = { name: 'World' };
  $scope.name = "Felipe";
});
app.directive('myDirective', function($compile) {
  return {
    restrict: 'AE', //attribute or element
    scope: {
      myDirectiveVar: '=',
     //bindAttr: '='
    },
    template: '' +
      '',
    replace: true,
    //require: 'ngModel',
    link: function($scope, elem, attr, ctrl) {
      console.debug($scope);
      //var textField = $('input', elem).attr('ng-model', 'myDirectiveVar');
      // $compile(textField)($scope.$parent);
    }
  };
});

具有指令的HTML


  This scope value 
  

CSS

.some {
  border: 1px solid #cacaca;
  padding: 10px;
}

您可以使用Plunker查看它的效果。

这是我看到的:

  • 我了解为什么您想使用'ng-model',但在您的情况下,它不是必要的。ng-model用于将现有的html元素与范围内的值链接起来。由于您自己创建了一个指令,因此您创建了一个“新”的html元素,因此不需要ng-model。

编辑:如马克在他的评论中提到的那样,没有理由不能使用ng-model,只是为了遵循惯例。

  • 通过在指令中显式创建一个范围(一个“隔离”范围),指令的范围无法访问父范围上的“name”变量,这就是您想要使用ng-model的原因(我认为)。
  • 我从指令中删除了ngModel,并用您可以更改的自定义名称替换了它。
  • 使所有东西仍然有效的是范围中的“=”符号。在“scope”标题下查看文档

一般来说,您的指令应该使用隔离范围(您已经正确执行)并使用“=”类型范围,如果您希望指令中的值始终映射到父范围中的值。

0