Pregunta

I've been using the jQuery / AngularJS Directive for debouncing inputs in a Firebase-backed app. It came from Lars Gersmann's post, and was working great:

http://orangevolt.blogspot.com.au/2013/08/debounced-throttled-model-updates-for.html

Updating from Angular 1.0.8 to 1.2 seems to break things. Each time the directive fires, instead of pulling the events from the element, the $._data function brings back an undefined, resulting in this error:

TypeError: Object.keys called on non-object at Function.keys (native)

It's defined here:

 var map = $._data( element[0], 'events'),
 events = $.each( Object.keys( map), function( index, eventName) {
    // map is undefined :(
    ...
 }

Did something change in AngularJS, or even jQuery, that wouldn't pull the events of this element like it used to?

(Side note, I'm using jQuery version 1.8.3, which hasn't changed in the Angular upgrade).

Thanks to anyone who can shed some light on this!

¿Fue útil?

Solución

You can access those events instead by using unbinds, binds and the Angular $timeout method to create a simpler debounce script. This is based off this post about blocking ngChange events.

This is a rewritten debounce directive that seems to work in Angular 1.2. It unbinds the input then applies changes with $setViewValue after a 1000ms delay. I've also added an instant change on blur. The key to making this work over the original post was setting priority.

angular.module('app', []).directive('ngDebounce', function($timeout) {
return {
    restrict: 'A',
    require: 'ngModel',
    priority: 99,
    link: function(scope, elm, attr, ngModelCtrl) {
        if (attr.type === 'radio' || attr.type === 'checkbox') return;

        elm.unbind('input');

        var debounce;
        elm.bind('input', function() {
            $timeout.cancel(debounce);
            debounce = $timeout( function() {
                scope.$apply(function() {
                    ngModelCtrl.$setViewValue(elm.val());
                });
            }, 1000);
        });
        elm.bind('blur', function() {
            scope.$apply(function() {
                ngModelCtrl.$setViewValue(elm.val());
            });
        });
    }

}
});

Plus JSFiddle Demo

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top