AngularJS - 创建使用ng-model的指令
本文翻译自:AngularJS - Create a directive that uses ng-model
I am trying to create a directive that would create an input field with the same ng-model as the element that creates the directive. 我正在尝试创建一个指令,该指令将使用与创建指令的元素相同的ng-model创建输入字段。
Here's what I came up with so far: 这是我到目前为止所提出的:
HTML HTML
AngularJS Plunker
This scope value
JavaScript 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);}};
});
However, I am not confident this is the right way to handle this scenario, and there is a bug that my control is not getting initialized with the value of the ng-model target field. 但是,我不相信这是处理这种情况的正确方法,并且存在一个错误,即我的控件没有使用ng-model目标字段的值进行初始化。
Here's a Plunker of the code above: http://plnkr.co/edit/IvrDbJ 这是上面代码的一个Plunker: http ://plnkr.co/edit/IvrDbJ
What's the correct way of handling this? 处理这个问题的正确方法是什么?
EDIT : After removing the ng-model="value" from the template, this seems to be working fine. 编辑 :从模板中删除ng-model="value"后,这似乎工作正常。 However, I will keep this question open because I want to double check this is the right way of doing this. 但是,我会保持这个问题的开放性,因为我想仔细检查这是否是正确的方法。
#1楼
参考:https://stackoom.com/question/Xe8B/AngularJS-创建使用ng-model的指令
#2楼
I wouldn't set the ngmodel via an attribute, you can specify it right in the template: 我不会通过属性设置ngmodel,您可以在模板中指定它:
template: '',
plunker : http://plnkr.co/edit/9vtmnw?p=preview plunker : http : //plnkr.co/edit/9vtmnw?p = preview
#3楼
EDIT : This answer is old and likely out of date. 编辑 :这个答案很旧,可能已经过时了。 Just a heads up so it doesn't lead folks astray. 只是抬头,所以它不会让人误入歧途。 I no longer use Angular so I'm not in a good position to make improvements. 我不再使用Angular,所以我不能很好地进行改进。
It's actually pretty good logic but you can simplify things a bit. 它实际上是非常好的逻辑,但你可以简化一些事情。
Directive 指示
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 elementscope: {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 with directive 带指令的Html
This scope value
CSS CSS
.some {border: 1px solid #cacaca;padding: 10px;
}
You can see it in action with this Plunker . 你可以通过这个Plunker看到它的实际效果 。
Here's what I see: 这是我看到的:
- I understand why you want to use 'ng-model' but in your case it's not necessary. 我理解你为什么要使用'ng-model',但在你的情况下它没有必要。 ng-model is to link existing html elements with a value in the scope. ng-model用于链接现有 html元素和范围中的值。 Since you're creating a directive yourself you're creating a 'new' html element, so you don't need ng-model. 由于您自己创建了一个指令,因此您正在创建一个“新的”html元素,因此您不需要ng-model。
EDIT As mentioned by Mark in his comment, there's no reason that you can't use ng-model, just to keep with convention. 编辑正如Mark在他的评论中所提到的那样,没有理由不能使用ng-model,只是为了遵守惯例。
- By explicitly creating a scope in your directive (an 'isolated' scope), the directive's scope cannot access the 'name' variable on the parent scope (which is why, I think, you wanted to use ng-model). 通过在指令中显式创建作用域(“隔离”作用域),指令的作用域无法访问父作用域上的“name”变量(这就是为什么我想要使用ng-model)。
- I removed ngModel from your directive and replaced it with a custom name that you can change to whatever. 我从您的指令中删除了ngModel,并将其替换为您可以更改为任何内容的自定义名称。
- The thing that makes it all still work is that '=' sign in the scope. 使一切仍然有用的事情是'='在范围内签名。 Checkout the docs docs under the 'scope' header. 查看“范围”标题下的文档文档 。
In general, your directives should use the isolated scope (which you did correctly) and use the '=' type scope if you want a value in your directive to always map to a value in the parent scope. 通常,如果希望指令中的值始终映射到父作用域中的值,则指令应使用隔离作用域(您已正确执行)并使用'='类型作用域。
#4楼
You only need ng-model when you need to access the model's $viewValue or $modelValue. 当您需要访问模型的$ viewValue或$ modelValue时,您只需要ng-model。 See NgModelController . 请参阅NgModelController 。 And in that case, you would use require: '^ngModel' . 在这种情况下,您将使用require: '^ngModel' 。
For the rest, see Roys answer . 其余的,请参阅Roys的回答 。
#5楼
I took a combo of all answers, and now have two ways of doing this with the ng-model attribute: 我对所有答案进行了组合,现在有两种方法可以使用ng-model属性:
- With a new scope which copies ngModel 使用复制ngModel的新范围
- With the same scope which does a compile on link 使用相同的范围进行链接编译
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
I'm not sure I like the compiling at link time. 我不确定我喜欢链接时的编译。 However, if you're just replacing the element with another you don't need to do that. 但是,如果您只是将元素替换为另一个元素,则不需要这样做。
All in all I prefer the first one. 总而言之,我更喜欢第一个。 Simply set scope to {ngModel:"="} and set ng-model="ngModel" where you want it in your template. 只需将范围设置为{ngModel:"="}并将ng-model="ngModel"设置在模板中的所需位置。
Update : I inlined the code snippet and updated it for Angular v1.2. 更新 :我内联了代码段并为Angular v1.2更新了它。 Turns out that isolate scope is still best, especially when not using jQuery. 事实证明,隔离范围仍然是最好的,特别是在不使用jQuery时。 So it boils down to: 所以归结为:
Are you replacing a single element: Just replace it, leave the scope alone, but note that replace is deprecated for v2.0: 您是否正在替换单个元素:只需替换它,保留范围,但请注意,对于v2.0,不推荐使用replace:
app.directive('myReplacedDirective', function($compile) { return { restrict: 'E', template: '', replace: true }; });Otherwise use this: 否则使用这个:
app.directive('myDirectiveWithScope', function() { return { restrict: 'E', scope: { ngModel: '=', }, template: '' }; });
#6楼
it' s not so complicated: in your dirctive, use an alias: scope:{alias:'=ngModel'} 它不是那么复杂:在你的dirctive中,使用别名: scope:{alias:'=ngModel'}
.directive('dateselect', function () {
return {restrict: 'E',transclude: true,scope:{bindModel:'=ngModel'},template:''
}
in your html, use as normal 在您的HTML中,正常使用
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
