我的指令需要使用ngModel
。
我需要在另一个指令中动态执行此操作,因为我想用范围做一些时髦的东西,并从编写HTML的人那里抽象出来。
我的第一个想法是使用$set
函数中attrs
参数提供的link
函数,该函数用于修改HTML,但指令本身不会被编译。然后,我们可以将其与$compile
提供程序结合使用,并且可以正常运行。
attrs.$set('ngModel', someVar);
$compile(element)(scope);
问题在于,如果我不能(并且我不能)替换元素标记,则会创建无限递归,因为指令会被无限期地重新应用和重新编译。
然而,我可以摆弄优先事项并让它发挥作用:
module.directive('input', [
'$compile',
function($compile) {
return {
restrict: 'E',
scope: {},
priority: 100, // Set this high enough to perform other directives
terminal: true, // Make sure this is the last directive parsed
link: function(scope, element, attrs) {
var key = 'example';
attrs.$set('ngModel', key);
$compile(element, null, 100)(scope);
}
};
}
]);
这很好用,但感觉不对:
我现在必须确保元素上的所有其他指令都是 能够被重新编译,因为它们都会被编译两次。
我必须确保没有人使用更高的优先级。
所以这让我想到为什么我不能只注入ngModelDirective并强制对我的元素进行编译?
module.directive('input', [
'ngModelDirective',
function(ngModel) {
return {
restrict: 'E',
scope: {},
priority: 100, // Set this high enough to perform other directives
terminal: true, // Make sure this is the last directive parsed
require: '?^form',
link: function(scope, element, attrs, formCtrl) {
var key = 'example';
attrs.$set('ngModel', key);
var ngModelFactory = ngModel[0];
var ngModelLink = ngModelFactory.compile(element);
ngModelLink.call(this, scope, element, attrs, [ngModelFactory.controller, formCtrl]);
}
};
}
]);
请参阅:https://github.com/angular/angular.js/blob/v1.2.x/src/ng/directive/input.js#L1356
没有错误,但没有任何反应。这似乎还不足以将其连接起来,所以我的问题是,任何人都可以详细说明我需要做什么将ngModelDirective
链接到我的自定义指令而不强制重新编译?
答案 0 :(得分:1)
如果没有重新编译,我认为这是不可能的。
ngModel
被设计为同一元素中的其他指令之间的一种协作者,也是父形式指示符。例如,在complilation期间:
$parser
或$formatter
添加到ngModel。因此,如果在复杂化过程结束后以某种方式添加ngModel
,则上述两个操作将会丢失。
编辑:如果要分配给ng-model属性的值在编译时已知,则可能会出现如下情况:
app.directive('myNgModel', function($compile) {
return {
restrict: 'A',
replace: false,
priority: 1000,
terminal: true, // these terminal and priority will stop all other directive from being compiled.
link: function (scope, element, attrs) {
var key = 'example';
attrs.$set('ngModel', key);
attrs.$set('myNgModel', null); // remove itself to avoid a recusion
$compile(element)(scope); // start compiling other directives
}
};
});
以下是带有示例的plunker:http://plnkr.co/edit/S2ZkiVIyq2bOK04vAnFO?p=preview
答案 1 :(得分:1)
ngModel
似乎不适合你要做的事情。但无论如何你根本不需要它。您可以双向绑定某个变量并将名称传递给模型指令范围:
app.directive("myDirective", function() {
// ...
scope: {
myModel = "=",
modelName = "myModel"
// ...
}
// ...
});
app.directive("ngModelDirective", function() {
// ...
// ...
transclude: true,
link: function(scope, element, attrs) {
var modelName = scope.modelName;
console.assert(modelName, '`modelName` must be set when using `ngModelDirective`.');
// TODO: Check if `scope[modelName]` is actually bound
doSomethingFancyWith(scope, modelName);
}
});
模板示例:
<myDirective ngModelDirective my-model="..." />
请注意doSomethingFancyWith
可以读取和写入模型变量,并绑定到外部世界。
答案 2 :(得分:0)
我设法做到了。它不是最漂亮的东西,但它可以工作,我可以使用本地input
连接我的inputDirective
指令,以便它可以使用require
之类的东西或验证特定的输入类型。
要针对另一个实现特定ngModel
功能的标准指令(例如ngChange
)进行构建,只需将注入的inputDirective
替换为正确的指令,例如ngChangeDirective
。
module.directive('input', function() {
return {
restrict: 'E',
scope: {},
require: '?ngModel',
priority: -1,
link: function(scope, element, attrs, ngModel) {
var key = 'example.property';
if (ngModel === undefined) {
attrs.$set('ngModel', key);
angular.injector(['ng']).invoke([
'inputDirective',
'ngModelDirective',
'$controller',
'$exceptionHandler',
'$parse',
'$animate',
function(inputDirective, ngModelDirective, $controller, $exceptionHandler, $parse, $animate) {
var ngModelFactory = ngModelDirective[0];
var ngModelLink = ngModelFactory.compile(scope); // Get the ngModel linkage function against this scope
ngModel = $controller(ngModelFactory.controller, {
$scope: scope,
$exceptionHandler: $exceptionHandler,
$attrs: attrs,
$element: element,
$parse: $parse,
$animate: $animate
}); // Call the ngModel controller and bootstrap it's arguments
// Call the inputDirective linkage function to set up the ngModel against this input
inputDirective[0].link(scope, element, attrs, ngModel);
element.data('$ngModelController', ngModel); // Allow additional directives to require ngModel on this element.
}
]);
}
}
};
});
注意:这不适用于ngOptions
,因为它指定了terminal: true
。