ngModel - 如何在不同的浏览器中处理它的不同行为?

时间:2015-07-10 08:34:33

标签: javascript jquery angularjs jquery-ui angular-ngmodel

我正在尝试处理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

我想在每个浏览器中达到相同的行为。如何处理这些问题?

3 个答案:

答案 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-disabledplaceholder等等。