Javascript Angularjs自定义select2指令
我为这个很棒的jquery插件创建了简单的自定义AngularJs指令,如下所示: 指令Javascript Angularjs自定义select2指令,javascript,jquery,angularjs,angularjs-directive,jquery-select2,Javascript,Jquery,Angularjs,Angularjs Directive,Jquery Select2,我为这个很棒的jquery插件创建了简单的自定义AngularJs指令,如下所示: 指令 app.directive("select2",function($timeout,$parse){ return { restrict: 'AC', link: function(scope, element, attrs) { $timeout(function() { $(element).select2(
app.directive("select2",function($timeout,$parse){
return {
restrict: 'AC',
link: function(scope, element, attrs) {
$timeout(function() {
$(element).select2();
},200);
}
};
});
在HTML模板中的用法:
<select class="form-control" select2 name="country"
data-ng-model="client.primary_address.country"
ng-options="c.name as c.name for c in client.countries">
<option value="">Select Country</option>
</select>
PS:我知道现在有类似的模块,但它需要一些不同的标记形式的
,我的应用程序已经完全开发好了,我只想用select2替换普通的选择框
因此,您能否指导我如何解决此问题,并确保指令与最新行为保持同步?我对select2不太熟悉(因此获取和设置控件中显示值的实际API可能不正确),但我建议将此作为备选方案:
app.directive("select2",function($timeout){
return {
restrict: 'AC',
require: 'ngModel',
link: function(scope, element, attrs, model) {
$timeout(function() {
element.select2();
});
model.$render = function() {
element.select2("val",model.$viewValue);
}
element.on('change', function() {
scope.$apply(function() {
model.$setViewValue(element.select2("val"));
});
})
}
};
});
第一个$timeout是必需的,因为您使用的是ng选项,所以这些选项在下一个摘要周期之前不会出现在DOM中。问题在于,如果应用程序稍后更改了国家/地区模型,则不会向控件中添加新选项 它不能直接回答您的问题,但请接受它,因为有一些人希望采用另一种方法,而不是坚持使用jQuery select2 我已经建立了自己的这个目的,因为我不满足于现有的不完全遵循角度原则,HTML第一 这仍处于早期阶段,但我认为所有的功能都可以在所有现代浏览器中使用 这些都是例子
app.directive("select2",function($timeout,$parse){
return {
restrict: 'AC',
link: function(scope, element, attrs) {
var options = [],
el = $(element),
angularTriggeredChange = false,
selectOptions = attrs["selectOptions"].split(" in "),
property = selectOptions[0],
optionsObject = selectOptions[1];
// watch for changes to the defining data model
scope.$watch(optionsObject, function(n, o){
var data = [];
// format the options for select2 data interface
for(var i in n) {
var obj = {id: i, text: n[i][property]};
data.push(obj);
}
el.select2({data: data});
// keep local copy of given options
options = n;
}, true);
// watch for changes to the selection data model
scope.$watch(attrs["selectSelection"], function(n, o) {
// select2 is indexed by the array position,
// so we iterate to find the right index
for(var i in options) {
if(options[i][property] === n) {
angularTriggeredChange = true;
el.val(i).trigger("change");
}
}
}, true);
// Watch for changes to the select UI
el.select2().on("change", function(e){
// if the user triggered the change, let angular know
if(!angularTriggeredChange) {
scope.$eval(attrs["selectSelection"]+"='"+options[e.target.value][property]+"'");
scope.$digest();
}
// if angular triggered the change, then nothing to update
angularTriggeredChange = false;
});
}
};
});
根据您使用的Angular和/或Select2的版本,您可能会有不同的行为,您可以指定吗
另外,如果要防止闪烁,请确保隐藏默认的
标记,以便在select2元素弹出之前不显示任何内容
这也是在我的JSFIDLE和CSS中完成的
.form-control { width: 200px; opacity: 0 }
这可能比你想象的要简单 请看看这个 基本上,所有插件Angularjs$watch都需要基于某些东西。我不能100%肯定jQuery-select2;但我认为这只是控件的正常DOM事件。(对于Angular$手表,它是一个“脏检查循环”) 我的想法是让我们相信jquery-Select2和AngularJS能够处理这些更改事件 我们只需要观察Angular方式的变化,并以Select2的方式更新select
var refreshSelect=function(){
如果(!element.select2Initialized)返回;
$timeout(函数(){
元素。触发器(“更改”);
});
};
//...
范围$watch(attrs.ngModel,刷新选择);
注意:我添加了2块新手表,我想您会喜欢的 Angular不喜欢由第三方插件修改模型数据。我的猜测基于这样一个事实,即您使用$timeout时,在更新选项或模型与select2插件之间存在竞争条件。我提出的解决方案是,让Angular不必亲自更新,而是根据指令手动进行更新,这样无论是谁在修改,都可以确保所有内容都匹配。这是我提出的指令:
app.directive("select2",function($timeout,$parse){
return {
restrict: 'AC',
link: function(scope, element, attrs) {
var options = [],
el = $(element),
angularTriggeredChange = false,
selectOptions = attrs["selectOptions"].split(" in "),
property = selectOptions[0],
optionsObject = selectOptions[1];
// watch for changes to the defining data model
scope.$watch(optionsObject, function(n, o){
var data = [];
// format the options for select2 data interface
for(var i in n) {
var obj = {id: i, text: n[i][property]};
data.push(obj);
}
el.select2({data: data});
// keep local copy of given options
options = n;
}, true);
// watch for changes to the selection data model
scope.$watch(attrs["selectSelection"], function(n, o) {
// select2 is indexed by the array position,
// so we iterate to find the right index
for(var i in options) {
if(options[i][property] === n) {
angularTriggeredChange = true;
el.val(i).trigger("change");
}
}
}, true);
// Watch for changes to the select UI
el.select2().on("change", function(e){
// if the user triggered the change, let angular know
if(!angularTriggeredChange) {
scope.$eval(attrs["selectSelection"]+"='"+options[e.target.value][property]+"'");
scope.$digest();
}
// if angular triggered the change, then nothing to update
angularTriggeredChange = false;
});
}
};
});
我已经添加了属性select options
和select model
。这些将用于使用select2的界面填充和更新数据。以下是一个示例html:
<select id="sel" class="form-control" select2 name="country"
select-selection="client.primary_address.country"
select-options="name in client.countries" >
<option value="">Select Country</option>
</select>
<div>Selected: {{client.primary_address.country}}</div>
选择国家
所选:{{client.primary_address.country}
请注意,仍然可以对该指令进行一些清理,并且输入中存在一些问题,例如选择选项属性中的“in”。它也不会强制执行属性,但如果属性不存在,则会失败
另外请注意,我使用了Select2版本4,这可以从el.val(I).trigger(“change”)
中看出。如果使用旧版本,您可能必须还原某些内容
这是指令的作用。这与
选择2
有关吗?如果您删除select2
指令,并使其成为一个普通的select元素,它是否按预期工作?是的,如果我删除它,它将按预期工作。我还在应用程序中使用select2
,但我使用的是Angular的包装器,现在已被弃用。Select2给我带来了很多痛苦,顺便说一句,我建议你尽量避免:)@OmriAharon使用ui-Select2
比创建自己已经编写的库要好。@pankajparkar是的,我建议使用推荐的ui-select
。用控制作为方法是行不通的,你能让它发挥作用并把它包括在你的答案中吗?请参见选择中的更改反映在范围变量中,但范围变量中的更改不反映在选择中您的PRUNKR中存在打字错误。您应该更改按钮的ng单击以包括cc。tooI强烈建议使用“change.select2”事件而不是“change”。我总是得到无限的变化事件循环,直到我使用这个解决方案,当模型是一个对象时,这个解决方案不起作用。