Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ng-model is not updating when using jquery element.val()

PLUNKR example here

I'm using some version of jquery autocomplete as an angularjs direcitve. When the jquery updates the input's value using element.val() angular does no notice the change until after the next digest ( i suppose ).

My first thought was to perform the action on the ng-model post digest using $timeout but as you can see it didn't help.

My second approach was to override the element's val function to trigger an input event but I haven`t managed to make it work.

Try to select a value from the autocomplete list and you'll see that the ng-model above is not updating.

UPDATE

Thanks for the response. I didn't know about the onSelect option.

This is the code based on your recommendations

// clone user provided options 
scope.options = _.extend({}, scope.AutoCompleteOptions());

// Wrap onSelect - Force update before manipulation on ng-model
var fn = _.has(scope.AutoCompleteOptions(), 'onSelect')  ? scope.AutoCompleteOptions().onSelect : _.noop;
scope.options.onSelect = function () { 
  ngModelCtrl.$setViewValue(element.val()); 
  scope.$apply(fn);
};

scope.autocomplete = $(element).autocomplete(scope.options);

This way i maintain the interface of the directive while guarantying that ng-model will be up to date.

Thanks.

like image 862
haki Avatar asked Mar 20 '23 02:03

haki


2 Answers

As you already knew, the problem is angular doesn't aware of the update made by jquery plugin. Luckily, you can use the plugin's onSelect callback to update ngModel, like this:

.directive("autoComplete", function() {
    return {
        restrict: "A" , 
        require: 'ngModel', // require ngModel controller
        scope: {
            AutoCompleteOptions : "=autoCompleteOptions", // use '=' instead of '&'
        },
        link: function (scope, element, attrs, ngModelCtrl) {

            // prevent html5/browser auto completion
            attrs.$set('autocomplete','off');

            // add onSelect callback to update ngModel
            scope.AutoCompleteOptions.onSelect = function() {
                scope.$apply(function() {
                    ngModelCtrl.$setViewValue(element.val());
                });
            };

            scope.autocomplete = $(element).autocomplete(scope.AutoCompleteOptions);
        }
    }
});
like image 189
Ye Liu Avatar answered Mar 22 '23 16:03

Ye Liu


The plugin you're using has an onSelect callback, so you can simply modify your autocomplete parameters to include a callback which updates the scope

{
    lookup      : $scope.current,
    width       : 448,
    delimiter   : /,/,
    tabDisabled : true,
    minChars    : 1,
    onSelect: function(v, data) {
        $scope.selected_tags = v.value;
        $scope.$apply();
}

EDIT

To further improve this you can remove the need to use the model name in the callback:

function(v, data) {
    var model = $(this).attr("ng-model");
    $scope[model] = v.value;
    $scope.$apply();
}
like image 35
Ciaran Phillips Avatar answered Mar 22 '23 16:03

Ciaran Phillips