我有一个自定义下拉指令,它具有常见属性,例如类和 ng-model 。
我已决定扩展此控件以支持验证,现在需要包含可选属性,如果它们由程序员设置,则只应包含在输出模板中。
示例
我有一个部分工作的系统,我将代码从模板URL中移出并转换为字符串连接,我在后期调用:指令编译的函数。
我本来希望将我的指令HTML保留在模板中,但是无法正常工作,所以我有了这个解决方案。
问题:
指令代码
'use strict';
angular.module(APP)
.directive('wkKeyLabelSelect', ["$compile",
function($compile) {
return {
restrict: 'EA',
replace: true,
scope: {
'class': '@', // Permanent - One Way Attribute
ngModel: '=', // Permanent - Two Way Attribute (Angular)
items: '=', // Permanent - Two Way Attribute (Custom)
id: '@', // Dynamic - One Way Attribute
name: '@', // Dynamic - One Way Attribute
ngRequired: '=', // Dynamic - Two Way Attribute (Angular)
},
//templateUrl: COMPONENTS_PATH + '/keyLabelSelect/keyLabelSelect.html',
controller: 'KeyLabelSelectController',
link: function (scope, element, attrs) {
//$compile(element)(scope);
},
compile: function (element, attrs) {
// name & ngRequired are not available in the compile scope
//element.replaceWith($compile(html)(scope));
return {
pre: function preLink(scope, iElement, iAttrs, controller) {
},
post: function postLink(scope, iElement, iAttrs, controller) {
// Template goes here
var html =
'<select ' +
' class="{{class}}"' +
(scope.id ? ' id="{{id}}"' : "") +
(scope.name ? ' name="{{name}}"' : "") +
(scope.ngRequired ? ' ng-required="true"' : "") +
' ng-model="ngModel"' +
' ng-options="item.key as item.label for item in items"' +
'>' +
'</select>';
iElement.replaceWith($compile(html)(scope));
}
}
}
};
}
]);
指令控制器代码
angular.module(APP)
.controller('KeyLabelSelectController', ['$scope', function ($scope) {
$scope.klass = typeof $scope.klass === 'undefined' ? 'form-control' : $scope.klass;
console.log($scope.ngModel);
console.log($scope.items);
}]);
用于运行指令的HTML
<div class="form-group" ng-class="{ 'has-error': editForm.state.$touched && editForm.name.$invalid }">
<label class="col-md-3 control-label">State</label>
<div class="col-md-9">
<wk-key-label-select id="state" name="state"
ng-required="true"
ng-model="model.entity.state"
class="form-control input-sm"
items="model.lookups.job_state">
</wk-key-label-select>
<div class="help-block" ng-messages="editForm.state.$error">
<p ng-message="required">Job State is required.</p>
</div>
</div>
</div>
我的原始模板网址内容,目前尚未使用
<!-- This is now deprecated in place of inline string -->
<!-- How could I use a in place of string concatenation -->
<select class="{{klass}}"
name="{{name}}"
ng-model="ngModel"
ng-options="item.key as item.label for item in items"></select>
答案 0 :(得分:2)
引入自定义输入控制器的“正确”方法是支持ngModelController
。这使您的自定义控件能够与支持ngModel
的其他指令集成,例如自定义验证器,解析器,<form>
。这有点棘手,但是使您的控件与框架的内置控件无法区分:
.directive("customSelect", function() {
return {
require: "?ngModel",
scope: {
itemsExp: "&items" // avoids the extra $watcher of "="
},
template: '<select ng-model="inner" \
ng-options="item.key as item.label for item in itemsExp()"\
ng-change="onChange()"></select>',
link: function(scope, element, attrs, ngModel) {
if (!ngModel) return;
// invoked when model changes
ngModel.$render = function() {
scope.inner = ngModel.$modelValue;
};
scope.onChange = function() {
ngModel.$setViewValue(scope.inner);
};
}
};
});
然后,它可以与其他控件巧妙地集成,并且本地利用ng-required
这样的验证器:
<custom-select name="c1" ng-model="c1" items="items" ng-required="true">
</custom-select>
这似乎不是你提出的问题的答案,但这只是因为你的问题是一个XY问题。通过实现自定义输入控件,您可以实现您要执行的操作 - 将name
属性分配给指令(如果提供了表单指令,则将其自身注册)并且ng-required
本机工作。但是,如果您必须将name
/ id
分配给基础<select>
(出于CSS原因或诸如此类),您可以有条件地使用ng-attr-
应用属性。模板将更改为:
<select ng-attr-name="attrs.name || undefined"
ng-attr-id ="attrs.id || undefined"
ng-model="inner" ...
当然,您需要在链接功能的范围内公开attrs
:
link: function(scope, element, attrs, ngModel){
scope.attrs = attrs;
// etc...
}