我有一个select
元素用于创建时区列表。这种简单的角度方式是:
<select ng-model="item.timezone" ng-options="timezone for timezone in timezones"></select>
然后确保控制器已将$scope.timezones
设置为时区字符串数组。
此选择出现在很多地方,我不希望每个控制器都必须加载它。所以我转向指令:
<select ng-model="item.timezone" timezones="true"></select>
然后使用指令渲染各种选项:
.directive('timezones',function () {
return {
restrict: 'A',
require: '?^ngModel',
link: function ($scope,element,attrs,ngModel) {
element.empty();
_.each(moment.tz.names(),function (name) {
element.append('<option value="'+name+'">'+name+'</option>');
});
// this formatter does nothing, is just there so I can be sure it is being called with the correct value
ngModel.$formatters.push(function(modelValue){
return(modelValue);
});
}
};
})
问题是angular现在使用我的“timezones”指令和处理角度“select”指令来处理它。这导致我对ng-model的设置被完全忽略,并且select的值设置为“”。
如果我在指令中执行此操作,如何识别模型值并选择正确的元素,或者有更好的方法来执行此操作?
更新:
我尝试在范围内设置timezones
并使用该指令在元素上设置ng-options
,但它仍为空白:
.directive('timezones',function () {
return {
restrict: 'A',
require: '?^ngModel',
link: function ($scope,element,attrs,ngModel) {
$scope.timezones = moment.tz.names();
element.attr("ng-options","timezone for timezone in timezones");
}
};
})
在这种情况下,我得到一个空的选择,只有一个空白选择。
答案 0 :(得分:1)
在我自己的指令上,我一直在努力解决这个问题,我终于解决了这个问题。
我知道解决方案是使用“子属性指令”的编译功能,因为它在编译“父元素指令”之前被触发,但我专注于将ngOptions
属性添加到tElement
,没有意识到所有指令编译函数之间共享tAttrs
。
所以我认为你可以解决它如下:
.directive('timezones', function() {
return {
controller: function($scope) {
$scope.timezones = moment.tz.names();
},
compile: function (tElement, tAttrs) {
var ngOptions = 'timezone for timezone in timezones';
tAttrs.ngOptions = ngOptions;
},
restrict: 'A'
};
答案 1 :(得分:0)
@deitch:尝试将指令中的选择部分作为&#34;模板&#34;,并使用&#39;隔离范围&#39;配置指令。将时区传递到指令的范围。
然后你的指令看起来像这样:
<timezone zone="item.timezone"></timezone>
&#13;
我写了一个例子作为一个掠夺者:http://plnkr.co/edit/7Ysn8K0Wwvo8CbtkMhVv?p=preview
.directive('timezone', function() {
return {
restrict: 'A',
require: 'ngModel',
scope: {
myTimezone: '=',
allTimezones: '@allTimezones'
},
template: '<p>Directive timezone: {{myTimezone}}</p>' +
'<p>{{ allTimezones }}</p>' +
'<select ng-model="myTimezone" ng-options="timezone for timezone in {{allTimezones}}"></select>'
};
});
&#13;
<div data-timezone data-my-timezone="data.myTimezone" data-all-timezones="{{timezones}}"></div>
&#13;
答案 2 :(得分:0)
我最终无法解决它,所以我完全传递了select
指令,并使用编译阶段生成我自己的选项:
.directive('timezones',function () {
return {
restrict: 'A',
require: '?^ngModel',
compile: function (element,attrs) {
_.each(moment.tz.names(),function (name) {
element.append('<option value="'+name+'">'+name+'</option>');
});
}
};
})
它只是有效。
答案 3 :(得分:0)
您需要做的是使用隔离范围创建指令并将模型作为binding传递。您可以在指令模板中创建select,并在指令范围内使用时区。
.directive('timezonesdir', function (timeZonesFactory) {
return {
restrict: 'AE',
template: '<select ng-model="timezone" ng-options="timezone for timezone in timezones"></select>',
scope: {
timezone: '='
},
link: function (scope) {
scope.timezones = // timezones
}
};
如您所说,如果您将此指令用作select元素的属性,则此方法无效,您必须在span或div或其他内容中使用它。
<span timezone="item.timezone" timezonesdir></span>
我已经为你创建了一个jsfiddle示例。
http://jsfiddle.net/limowankenobi/xo4r9q3j/
我为时区添加了一个工厂,将它们从指令中解耦。