我正在重写这个问题,因为我认为原文不太清楚。
基本上,我有一个'wrapper'指令,我试图动态地将属性添加到其中一个包装(转换)元素。我可以让它工作,但Angular似乎并没有意识到添加后的新属性。
如果我使用$compile
,那么Angular会识别它们 - 但代价是对已转换内容进行双重编译,在这种情况下,它会使options
中select
的数量增加一倍} tag。
Here is a plunker显示(带注释)我正在尝试的内容,下面是相同的代码,以便那些可以查看代码并通过查看建议答案的人:
(注意 - 我的最终目的是检查valid-form-group
属性的自定义指令required
,如果找到将其应用于包含的select
标记
HTML
<body ng-controller="MainCtrl">
<form name="validationForm" novalidate>
<valid-form-group class="form-group" ng-class="{'has-error': validationForm.validInfo.$error.required}" required>
<select ng-model="data.option" ng-options="option.id as option.message for option in selectOptions" name="validInfo" id="validInfo">
<option value="">-- Select a Question --</option>
</select>
</valid-form-group>
</form>
</body>
JS
var app = angular.module('plunker', [])
.controller('MainCtrl', function($scope) {
$scope.selectOptions = [
{id: 1, message: 'First option'},
{id: 2, message: 'Second option'},
{id: 3, message: 'Third option'}
];
})
.directive('validFormGroup', function($compile) {
return {
restrict: 'E',
template: '<div><span ng-transclude></span></div>',
replace: true,
transclude: true,
require: '^form',
link: function(scope, element, attrs, ctrl) {
if (attrs.required !== undefined) {
var selectElement = angular.element(element.find('select'));
// either of the below produce the same results
selectElement.attr('ng-required', true);
//selectElement.attr('required', true);
// if the below is commented out it wont validate
// BUT if it is left in it will recompile and add another 3 options
$compile(selectElement)(scope);
}
}
};
});
CSS
.has-error{
border: solid 1px red;
}
请注意,此处的示例使用“required
”(或ng-required
)作为添加的属性,以突出显示Angular无法识别它的事实,除非已编译。
欢迎任何帮助或评论 - 有点失望,我无法让它工作,所以也许有一些我缺少的基本...
plunker应该可以帮助我查看问题。
编辑 - 对回复答案和评论的延迟道歉。如下面的评论或两条评论所述,个人问题使我无法找到时间进行调查。
答案 0 :(得分:2)
尝试这个简单的指令:
.directive('validFormGroup', function($compile) {
return {
restrict: 'A',
replace: false,
require: '^form',
compile: function (element, attr) {
if (attr.required !== undefined) {
var selectElement = element.find('select');
// either of the below produce the same results
selectElement.attr('ng-required', true);
//selectElement.attr('required', true);
}
}
};
});
并将其用作html属性:
<div valid-form-group class="form-group" ng-class="{'has-error': validationForm.validInfo.$error.required}" required>
<select ng-model="data.option"
ng-options="option.id as option.message for option in selectOptions"
name="validInfo" id="validInfo" >
<option value="">-- Select a Question --</option>
</select>
<br/>
<br/>Required invalid? {{validationForm.validInfo.$error.required||false}}
<br/>
<br/>
</div>
<强>解释强>:
我在这个解决方案中根本没有使用transclude
,因为这个指令的目的只是在用范围编译之前修改html ,没有必要对于过于复杂的被抄写的内容。
我在这里处理compile
函数而不是link
函数。 compile
函数是您在链接到范围之前修改html 的好地方。
答案 1 :(得分:1)
我只能猜测你所看到的是指令初始化过程中双重编译的结果,这就是你看到双重选项的原因。
您可以通过将编译包装在$ timeout内来解决此问题,这将确保编译在指令初始化之外发生。这是一个工作demo,低于指令代码:
.directive('validFormGroup', function($compile, $timeout) {
return {
restrict: 'E',
template: '<div><span ng-transclude></span></div>',
replace: true,
transclude: true,
require: '^form',
link: function(scope, element, attrs, ctrl) {
if (attrs.required !== undefined) {
var selectElement = angular.element(element.find('select'));
$timeout(function(){
selectElement.attr('ng-required', true);
$compile(selectElement)(scope);
});
}
}
};
});
PS您可以通过在指令上使用隔离范围,然后检查您的transcluded输入/选择元素是否具有所需的属性集来实现类似的引导程序包装器功能。在隔离范围上定义一个函数以检查错误,并将此函数绑定到form-group ng-class has-error。这样你就不必使用$ timeout了。
答案 2 :(得分:1)
我想在这里建议一种不同的方法,我适应了动态验证。将动态验证动态添加到字段中,减少每个字段的样板html代码,我已经编写了一个类似用途的指令。请参阅示例指令... PLUNKER
的plunker链接我已经为所有类型的字段编写了这样的指令:数字,文本,选择,textarea,bool,datepicker等...附带的plunker为您提供了一个文本&amp;数字字段。
使用下面的衬垫发生角度的魔力: var newElem = angular.element(template);
element.replaceWith(newElem);
$compile(newElem)(scope);
所有其他代码只是一些逻辑的if else部分..
答案 3 :(得分:0)
在这种情况下你不需要使用$ compile。我刚刚更改了代码来解决您的问题。我尽量保持与原始版本尽可能接近,以帮助您理解。
Javascript(基于attrs.required添加了isRequired范围变量)
.directive('validFormGroup', function($compile) {
return {
restrict: 'E',
template: '<div><span ng-transclude></span></div>',
replace: true,
transclude: true,
require: '^form',
link: function(scope, element, attrs, ctrl) {
if (attrs.required !== undefined) {
//added isRequired
scope.isRequired = true;
var selectElement = angular.element(element.find('select'));
// either of the below produce the same results
//selectElement.attr('ng-required', true);
//selectElement.attr('required', true);
// if the below is commented out it wont validate
// BUT if it is left in it will recompile and add another 3 options
//remove $compile
//$compile(selectElement)(scope);
}
}
};
});
HTML(添加了ng-required = isRequired)
<select ng-model="data.option" ng-options="option.id as option.message for option in selectOptions" name="validInfo" id="validInfo" ng-required="isRequired">
您可以在http://plnkr.co/edit/BGQo05mTNr1H1HjFXSpf?p=preview
参考plunkr版本我认为这回答了你的问题。如果你有更复杂的情况,请分享。
更新:(通读别人评论并再次回答) 如果您需要动态HTML内容,可以使用此解决方案 - Compiling dynamic HTML strings from database
另一种方法是删除ng- *属性以防止重新编译。 http://plnkr.co/edit/JpfdvISCZ39heuUfdHt3?p=preview
的plunkr版本 selectElement.removeAttr('ng-options');
selectElement.removeAttr('ng-model');
答案 4 :(得分:0)
我没有一个完整的答案,但是如果你给你的指令一个孤立的范围范围:{},那么在双重编译时它无法获得选项因此无声地失败 - 我在你的plunkr和我试过这个下拉列表中只有一组选项。
我说我没有竞争的答案 - 我不相信它 - 它似乎是一个黑客,我认为你需要与你可能能够分享的指令分享范围内的东西通过继承的范围单独继承这些,以便您可以维护功能,但正如我所说,它感觉很hacky并且感觉不对,因为它没有解决如何最好地处理双重编译的基本问题。