diff --git a/build/ng-tags-input.js b/build/ng-tags-input.js index efb52c7a..b03e0da7 100644 --- a/build/ng-tags-input.js +++ b/build/ng-tags-input.js @@ -268,7 +268,7 @@ tagsInput.directive('tagsInput', ["$timeout","$document","tagsInputConfig", func */ tagsInput.directive('autoComplete', ["$document","$timeout","$sce","tagsInputConfig", function($document, $timeout, $sce, tagsInputConfig) { function SuggestionList(loadFn, options) { - var self = {}, debouncedLoadId, getDifference; + var self = {}, debouncedLoadId, getDifference, lastPromise; getDifference = function(array1, array2) { var result = []; @@ -283,6 +283,8 @@ tagsInput.directive('autoComplete', ["$document","$timeout","$sce","tagsInputCon }; self.reset = function() { + lastPromise = null; + self.items = []; self.visible = false; self.index = -1; @@ -307,7 +309,15 @@ tagsInput.directive('autoComplete', ["$document","$timeout","$sce","tagsInputCon $timeout.cancel(debouncedLoadId); debouncedLoadId = $timeout(function() { self.query = query; - loadFn({ $query: query }).then(function(items) { + + var promise = loadFn({ $query: query }); + lastPromise = promise; + + promise.then(function(items) { + if (promise !== lastPromise) { + return; + } + self.items = getDifference(items, tags); if (self.items.length > 0) { self.show(); diff --git a/build/ng-tags-input.min.zip b/build/ng-tags-input.min.zip index 70809573..027ea93c 100644 Binary files a/build/ng-tags-input.min.zip and b/build/ng-tags-input.min.zip differ diff --git a/build/ng-tags-input.zip b/build/ng-tags-input.zip index b0f12fdb..d75aadbc 100644 Binary files a/build/ng-tags-input.zip and b/build/ng-tags-input.zip differ diff --git a/src/auto-complete.js b/src/auto-complete.js index 5bdda480..26ff500e 100644 --- a/src/auto-complete.js +++ b/src/auto-complete.js @@ -20,7 +20,7 @@ */ tagsInput.directive('autoComplete', function($document, $timeout, $sce, tagsInputConfig) { function SuggestionList(loadFn, options) { - var self = {}, debouncedLoadId, getDifference; + var self = {}, debouncedLoadId, getDifference, lastPromise; getDifference = function(array1, array2) { var result = []; @@ -35,6 +35,8 @@ tagsInput.directive('autoComplete', function($document, $timeout, $sce, tagsInpu }; self.reset = function() { + lastPromise = null; + self.items = []; self.visible = false; self.index = -1; @@ -59,7 +61,15 @@ tagsInput.directive('autoComplete', function($document, $timeout, $sce, tagsInpu $timeout.cancel(debouncedLoadId); debouncedLoadId = $timeout(function() { self.query = query; - loadFn({ $query: query }).then(function(items) { + + var promise = loadFn({ $query: query }); + lastPromise = promise; + + promise.then(function(items) { + if (promise !== lastPromise) { + return; + } + self.items = getDifference(items, tags); if (self.items.length > 0) { self.show(); diff --git a/test/auto-complete.spec.js b/test/auto-complete.spec.js index 63fd03f4..71deeae4 100644 --- a/test/auto-complete.spec.js +++ b/test/auto-complete.spec.js @@ -265,6 +265,53 @@ describe('autocomplete-directive', function() { // Assert expect(suggestionList.selected).toBeNull(); }); + + it('discards all load calls but the last one', function() { + // Arrange + var deferred1 = $q.defer(), deferred2 = $q.defer(), deferred3 = $q.defer(); + var promises = [deferred1.promise, deferred2.promise, deferred3.promise]; + + $scope.loadItems = jasmine.createSpy().andCallFake(function() { + return promises.shift(); + }); + spyOn(suggestionList, 'show'); + + // Act + // First we need to register all promises + suggestionList.load('foobar', tagsInput.getTags()); + $timeout.flush(); + + suggestionList.load('foobar', tagsInput.getTags()); + $timeout.flush(); + + suggestionList.load('foobar', tagsInput.getTags()); + $timeout.flush(); + + // Now we resolve each promise which was previously created + deferred1.resolve(['Item1']); + deferred2.resolve(['Item2']); + deferred3.resolve(['Item3']); + + $scope.$digest(); + + // Assert + expect(suggestionList.show.calls.length).toBe(1); + }); + + it('discards all load calls after the suggestion list is reset', function() { + // Arrange + spyOn(suggestionList, 'show'); + suggestionList.load('foobar', tagsInput.getTags()); + $timeout.flush(); + + // Act + suggestionList.reset(); + + resolve(['Item3']); + + // Assert + expect(suggestionList.show).not.toHaveBeenCalled(); + }); }); describe('navigation through suggestions', function() { @@ -555,7 +602,6 @@ describe('autocomplete-directive', function() { // Assert expect($scope.loadItems).not.toHaveBeenCalled(); - }); }); diff --git a/test/test-page.html b/test/test-page.html index d14e79a5..e8e75d93 100644 --- a/test/test-page.html +++ b/test/test-page.html @@ -24,13 +24,23 @@