Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JQuery UI Spinner is not updating ng-model in angular

Angular's ng-model is not updating when using jquery-ui spinner.

Here is the jsfiddle http://jsfiddle.net/gCzg7/1/

<div ng-app>

  <div ng-controller="SpinnerCtrl">
    <input type="text" id="spinner" ng-model="spinner"/><br/>
    Value: {{spinner}}
  </div>
</div>

<script>
    $('#spinner').spinner({});
</script>

If you update the text box by typing it works fine (you can see the text change). But if you use the up or down arrows the model does not change.

like image 896
coder Avatar asked Mar 19 '14 20:03

coder


2 Answers

Late answer, but... there's a very simple and clean "Angular way" to make sure that the spinner's spin events handle the update against ngModel without resorting to $apply (and especially without resorting to $parse or an emulation thereof).

All you need to do is define a very small directive with two traits:

  1. The directive is placed as an attribute on the input element you want to turn into a spinner; and

  2. The directive configures the spinner such that the spin event listener calls the ngModel controller's $setViewValue method with the spin event value.

Here's the directive in all its clear, tiny glory:

function jqSpinner() {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, element, attrs, c) {
            element.spinner({
                spin: function (event, ui) {
                    c.$setViewValue(ui.value);
                }
            });
        }
    };
};

Note that $setViewValue is intended for exactly this situation:

This method should be called when an input directive wants to change the view value; typically, this is done from within a DOM event handler.

Here's a link to a working demo.


If the demo link provided above dies for some reason, here's the full example script:

(function () {
    'use strict';

    angular.module('ExampleApp', [])
        .controller('ExampleController', ExampleController)
        .directive('jqSpinner', jqSpinner);

    function ExampleController() {
        var c = this;
        c.exampleValue = 123;
    };

    function jqSpinner() {
        return {
            restrict: 'A',
            require: 'ngModel',
            link: function (scope, element, attrs, c) {
                element.spinner({
                    spin: function (event, ui) {
                        c.$setViewValue(ui.value);
                    }
                });
            }
        };
    };
})();

And the minimal example template:

<div ng-app="ExampleApp" ng-controller="ExampleController as c">
    <input jq-spinner ng-model="c.exampleValue" />
    <p>{{c.exampleValue}}</p>
</div>
like image 158
William Avatar answered Sep 30 '22 14:09

William


Your fiddle is showing something else.

Besides this: Angular can not know about any changes that occur from outside its scope without being aknowledged. If you change a variable of the angular-scope from OUTSIDE angular, you need to call the apply()-Method to make Angular recognize those changes. Despite that implementing a spinner can be easily achieved with angular itself, in your case you must: 1. Move the spinner inside the SpinnerCtrl 2. Add the following to the SpinnerCtrl:

   $('#spinner').spinner({
      change: function( event, ui ) {
           $scope.apply();
       }
   }

If you really need or want the jQuery-Plugin, then its probably best to not even have it in the controller itself, but put it inside a directive, since all DOM-Manipulation is ment to happen within directives in angular. But this is something that the AngularJS-Tutorials will also tell you.

like image 39
David Losert Avatar answered Sep 30 '22 15:09

David Losert