Search code examples
javascriptjqueryangularjsjquery-uiangular-ngmodel

ngModel - How to deal with its different behavior in different browsers?


I'm trying to deal with different behavior of ngModel in different browsers.

My directive wraps jqueryUI autocomplete and on its select event it calls ngModel.$setViewValue(selectedItem.id). Autocomplete allows user to select item by mouse click or by pressing enter on the keyboard.

If suggested item is:

{
  "name": "Apple",
  "id": "1000"
}

I expect after selecting it, the ngModel value will be selected item's id - 1000.

  • In Chrome it works OK - it sets $viewValue and $modelValue correctly ($modelValue=1000).

  • In Firefox it sets model as in Chrome ($modelValue=1000), but when I click somewhere else - make blur (then browser probably fires change event), model changes and it becomes same as visible input value ($modelValue='Apple').

  • In IE 11 it sets model correct only when I select item with mouse click. If I select it by pressing enter, the model becomes visible input value ($modelValue='Apple')

Here is plunkr: http://plnkr.co/edit/o2Jkgprf8EakGqnpu22Y?p=preview

I'd like to reach the same behavior in every browser. How to deal with that problems?


Solution

  • Ok, I think I've made it. The solution is based on Yoshi's comment and it uses local model to keep selected data.

    When user selects something, local model is set to selected Object and $viewValue is set to the text value of selected item. Then parser sets id property of local model as $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;
    });
    

    Parser function do also one important thing. Because it's run when user type something or on the change event (that was the problem in firefox!), it checks if the value is same as current local model's text value, and if not it changes local model into this value. It means that if parser function is run by change event value would be the same as text value, so $modelValue is not changed, but if user type something model is updated to the typed value (it becomes String).

    Validator function checks if local model is an Object. If not it means that field is invalid so by default its $modelValue disappears.

    Here is the plunkr: http://plnkr.co/edit/2ZkXFvgLIwDljfJoyeJ1?p=preview

    (In formatter function I return that what comes, so $viewValue is temporarily an Object but then in $render method I call $setViewValue to set $viewValue and $modelValue correctly, so it becomes String. I heard $setViewValue should not be run in $render method, but I don't see other way to set correct $modelValue when something comes from outside).