我正在尝试处理ngModel
在不同浏览器中的不同行为。
我的指令包装jqueryUI自动完成,并在其select
事件中调用ngModel.$setViewValue(selectedItem.id)
。自动填充功能允许用户通过鼠标单击或按键盘上的enter
选择项目。
如果建议的项目是:
{
"name": "Apple",
"id": "1000"
}
我希望在选择它之后,ngModel值将被选为项目id
- 1000
。
在Chrome中,它运行正常 - 它正确设置$viewValue
和$modelValue
($modelValue=1000
)。
在Firefox中,它将模型设置为Chrome($modelValue=1000
),但是当我点击其他地方时 - 使模糊(然后浏览器可能会触发change
事件),模型更改并且它变得相同作为可见输入值($modelValue='Apple'
)。
在IE 11中,只有在用鼠标点击选择项目时,才会设置模型正确。如果我按enter
选择它,模型将变为可见输入值($modelValue='Apple'
)
这是plunkr:http://plnkr.co/edit/o2Jkgprf8EakGqnpu22Y?p=preview
我想在每个浏览器中达到相同的行为。如何处理这些问题?
答案 0 :(得分:2)
这似乎与http://bugs.jqueryui.com/ticket/8878
有关正如上面的链接所指出的,更改事件仅在Firefox中触发,而不是在Chrome中触发。因此,在您的情况下,在外部单击时会再次触发$ setViewValue,并且模型值设置为" Apple"。
自动完成jquery ui小部件有更改回调。要处理大小写/浏览器,您可能需要在此回调中再次显式设置视图值(并且它可以正常工作)。
http://plnkr.co/edit/GFxhzwieBJTSL8zjSPSZ?p=preview
link: function(scope, elem, attrs, ngModel) {
elem.on('change', function(){
// This will not be printed in Chrome and only on firefox
console.log('change');
});
select: function(event, ui) {
ngModel.$setViewValue(ui.item.data.id);
scope.$apply();
},
// To handle firefox browser were change event is triggered
// when clicked outside/blur
change: function(event, ui) {
ngModel.$setViewValue(ui.item.data.id);
scope.$apply();
}
答案 1 :(得分:1)
好的,我想我已经做到了。该解决方案基于Yoshi's comment,它使用本地模型来保留所选数据。
当用户选择某些内容时,本地模型设置为选中Object
,$viewValue
设置为所选项目的文本值。然后,解析器将本地模型的id
属性设置为$modelValue
。
select: function(event, ui) {
if(ui.item && ui.item.data){
model = ui.item.data
ngModel.$setViewValue(model.name);
scope.$apply();
}
}
ngModel.$parsers.push(function(value) {
if(_.isObject(model) && value!==model.name){
model = value;
return model;
}
return model.id;
});
解析器功能也是一件重要的事情。因为它是在用户输入内容或change
事件(这是firefox中的问题!)时运行的,它会检查该值是否与当前本地模型的文本值相同,如果不是,则将本地模型更改为此值。这意味着如果解析器函数由change
运行,则事件值将与文本值相同,因此$modelValue
不会更改,但如果用户键入某个模型,则更新为类型值(它变为{ {1}})。
Validator函数检查本地模型是否为String
。如果不是,则表示该字段无效,因此默认情况下其Object
消失。
以下是plunkr: http://plnkr.co/edit/2ZkXFvgLIwDljfJoyeJ1?p=preview
(在格式化程序函数中,我返回了所发生的内容,因此$modelValue
暂时为$viewValue
,但在Object
方法中我调用$render
来设置$setViewValue
并且$viewValue
正确,因此它变为$modelValue
。我听说String
不应该在$setViewValue
方法中运行,但我没有看到其他方法来设置正确{{1}当某些东西来自外部时。)
答案 2 :(得分:0)
我与ngModelController
和$setViewValue
进行了类似的战斗。
最终我寻找替代解决方案。 我发现一种非常好用的方法是创建一个新元素作为组件指令,其中包含输入标记作为转换元素。
app.directive('fruitAutocomplete', function($http) {
return {
restrict: 'E',
require: 'ngModel',
transclude: true,
template: '<ng-transclude></ng-transclude>',
link: function(scope, elem, attrs, ngModelController) {
var $input = elem.find('input');
$input.autocomplete({
...
});
}
}
})
在HTML中:
<fruit-autocomplete name="fruit" ng-model="model.fruit">
<input ng-disabled="inputDisabled" placeholder="input fruit"/>
</fruit-autocomplete>
这是一个有效的Plunker
使用此提议的解决方案,您可以将ngModelController
和jQueryUI模式相互作用隔离到其自己的自定义元素,并且它不会干扰&#34;正常&#34; <input>
标记,您不关心jQueryUI错误。
通过使用<input>
标记作为转化元素,您仍然可以从大多数Angular输入内容中受益,例如ng-disabled
,placeholder
等等。