带有 <select ng-options> 的指令和间接 [英] Directive with <select ng-options> and indirection
问题描述
我在一个页面上有多个多选,每个都有一些逻辑来填充来自服务器的多选,我想将每个多选包装成一个指令.
在尝试将它们包装到指令中之前,我按如下方式构建了每个:
index.html
controllers.js
在第一遍中,我从这里调用 $http.是的,我知道,这不是最佳实践,但我想首先证明这对我自己有效.
$scope.loadSelect = function(_url) {$http({网址:_url,方法:'POST',数据:$scope.inputs,模型:全部"+ _url}). 成功(功能(数据,状态,标题,配置){$scope[config.model] = 数据;});};//填充组$scope.loadSelect('groups');//当组改变时,重新加载依赖组的其他选择字段$scope.groupsChanged = function() {$scope.loadSelect('categories');$scope.loadSelect('actions');}
现在我想将此迁移到指令.我看到两个主要挑战:1.) 如何将整个选项集(例如现在的allgroups"模型)封装到指令中?2.) 基于最初的实验,我尝试将 物理构建到模板中,但意识到我必须操纵 DOM 来物理替换 name、ng-model 和ng-选项.这让我想到了 compile 属性,但是 a.) 感觉不对 b.) 设置
<select ng-options="x for x in allgroups"/>
实际上并没有重复它已被插入到 DOM 中.使用 compile 感觉不对;解决这个问题的正确方法是什么?
这是我对指令的第一次尝试,看起来像这样.它并没有真正起作用,而且我认为我的做法是错误的:
index.html
<dimension ng-model="inputs.users" alloptions-model="allusers">Users</dimension>
directives.js
directive('dimension', function() {返回 {限制:'E',范围: {ngModel: '=',alloptionsModel: '='},模板:''+'<标签 ng-transclude></label>'+'<字段集>'+'<div class="form-group">'+'<select ng-model="{{ngModel}}" ng-options="x for x in {{alloptionsModel}}" multiple class="form-control"></select>'+'</div>'+'</字段集>'+'</div>',替换:真的,转置:真实};});很明显,我什至还没有进入服务器负载部分,但我计划将它滚动到指令中的控制器中,并在服务中实际调用 $http.
我觉得我走错了路.如果您对如何重新调整有任何建议,请帮忙!
解决方案 你的指令的主要问题是你不能在 ngModel
和 ngOptions
中使用 mustache 绑定指令,因为它们是直接评估的.您可以直接绑定到作用域属性(ngModel 和 alloptionsModel):
directive('dimension', function() {返回 {限制:'E',范围: {ngModel: '=',alloptionsModel: '='},模板:''+'<标签 ng-transclude></label>'+'<字段集>'+'<div class="form-group">'+'<select ng-model="ngModel" ng-options="x for x in alloptionsModel" multiple class="form-control"></select>'+'</div>'+'</字段集>'+'</div>',替换:真的,转置:真实};});请参阅 此 plunkr 以获取工作示例.
编辑至于编译路线,没有错.当您需要动态创建一个模板时它很有用,当您进入 select
的项目模板时,这显然是您的情况.
compile: function(tElement, tAttrs) {var select = tElement.find('select'),值 = tAttrs.value ?'X.'+ tAttrs.value : 'x',标签 = tAttrs.label ?'X.'+ tAttrs.label : 'x',ngOptions = value + ' as ' + label + ' for x in alloptionsModel';select.attr('ng-options', ngOptions);}//在 HTML 文件中<维度 ng-model="inputs.users"alloptions-model="allusers"标签=名称">用户</维度>
我已经使用编译功能更新了 plunkr.
I have several multi-selects on a page, each with a bit of logic that fills that multi-select from the server, and I want to wrap each one up into a Directive.
Before trying to wrap these into Directives, I built each as such:
index.html
<select name="groups" ng-model="inputs.groups" ng-change="groupsChanged()" ng-options="g for g in allgroups" multiple></select>
controllers.js
In the first pass, I do my $http calls from here. Yes, I know, not best practices, but I wanted to prove that this works to myself first.
$scope.loadSelect = function(_url) {
$http({
url: _url,
method: 'POST',
data: $scope.inputs,
model: 'all' + _url
}).success(function(data, status, headers, config) {
$scope[config.model] = data;
});
};
// Fill groups
$scope.loadSelect('groups');
// When groups change, reload other select fields that depend on groups
$scope.groupsChanged = function() {
$scope.loadSelect('categories');
$scope.loadSelect('actions');
}
Now I want to migrate this to a Directive. I see two major challenges:
1.) How do I encapsulate the entire set of options (e.g. what is now the "allgroups" model) into the Directive?
2.) Based on initial experiments, I tried to physically build the <select/>
into the template, but realized that I have to manipulate the DOM to physically replace name, ng-model, and ng-options. That lead me to the compile attribute, but a.) that feels wrong and b.) setting <select ng-options="x for x in allgroups" />
doesn't actually repeat after it's been inserted into the DOM. Using compile doesn't feel right; what's the right way to approach this?
Here is my first attempt at the Directive looks like this. It doesn't really work, and I think I'm going about it incorrectly:
index.html
<dimension ng-model="inputs.users" alloptions-model="allusers">Users</dimension>
directives.js
directive('dimension', function() {
return {
restrict: 'E',
scope: {
ngModel: '=',
alloptionsModel: '='
},
template:
'<div>' +
'<label ng-transclude></label>' +
'<fieldset>' +
'<div class="form-group">' +
'<select ng-model="{{ngModel}}" ng-options="x for x in {{alloptionsModel}}" multiple class="form-control"></select>' +
'</div>' +
'</fieldset>' +
'</div>',
replace: true,
transclude: true
};
});
Clearly I haven't even gotten to the server load part yet, but I plan to roll that into a controller in the Directive, with the actual $http call in a service.
I feel like I'm moving down the wrong track. If you have suggestions on how to realign, please help!
解决方案 The main problem with your directive is that you can't use mustache binding in ngModel
and ngOptions
directive because they are evaluated directly. You can directly bind to the scoped property (ngModel and alloptionsModel):
directive('dimension', function() {
return {
restrict: 'E',
scope: {
ngModel: '=',
alloptionsModel: '='
},
template:
'<div>' +
'<label ng-transclude></label>' +
'<fieldset>' +
'<div class="form-group">' +
'<select ng-model="ngModel" ng-options="x for x in alloptionsModel" multiple class="form-control"></select>' +
'</div>' +
'</fieldset>' +
'</div>',
replace: true,
transclude: true
};
});
See this plunkr for a working example.
Edit
As for the compile route, there is nothing wrong with it. It is useful when you need to dynamically create a template which will clearly be your case when you will get to the select
's item template.
compile: function(tElement, tAttrs) {
var select = tElement.find('select'),
value = tAttrs.value ? 'x.' + tAttrs.value : 'x',
label = tAttrs.label ? 'x.' + tAttrs.label : 'x',
ngOptions = value + ' as ' + label + ' for x in alloptionsModel';
select.attr('ng-options', ngOptions);
}
// In the HTML file
<dimension ng-model="inputs.users"
alloptions-model="allusers"
label="name">
Users
</dimension>
I've updated the plunkr with the compile function.
这篇关于带有 <select ng-options> 的指令和间接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文