diff --git a/src/bloodhound/bloodhound.js b/src/bloodhound/bloodhound.js index 37ecc849..e680e29a 100644 --- a/src/bloodhound/bloodhound.js +++ b/src/bloodhound/bloodhound.js @@ -153,7 +153,7 @@ var Bloodhound = window.Bloodhound = (function() { }, get: function get(query, cb) { - var that = this, matches, cacheHit = false; + var that = this, matches = [], cacheHit = false; matches = this.index.get(query); matches = this.sorter(matches).slice(0, this.limit); @@ -164,8 +164,10 @@ var Bloodhound = window.Bloodhound = (function() { // if a cache hit occurred, skip rendering local matches // because the rendering of local/remote matches is already - // in the event loop - !cacheHit && cb && cb(matches); + // in the event loop. + // if we don't have any local matches and we're going to the + // network, don't render unnecessarily. + !cacheHit && (matches.length > 0 || !this.transport) && cb && cb(matches); function returnRemoteMatches(remoteMatches) { var matchesWithBackfill = matches.slice(0); @@ -184,7 +186,6 @@ var Bloodhound = window.Bloodhound = (function() { // the remote results and can break out of the each loop return matchesWithBackfill.length < that.limit; }); - cb && cb(that.sorter(matchesWithBackfill)); } }, diff --git a/src/typeahead/typeahead.js b/src/typeahead/typeahead.js index 6d69bab7..eb787750 100644 --- a/src/typeahead/typeahead.js +++ b/src/typeahead/typeahead.js @@ -186,7 +186,9 @@ var Typeahead = (function() { _onQueryChanged: function onQueryChanged(e, query) { this.input.clearHint(); - this.dropdown.empty(); + if(query.length === 0) { + this.dropdown.empty(); + } query.length >= this.minLength && this.dropdown.update(query); this.dropdown.open(); this._setLanguageDirection(); diff --git a/test/bloodhound_spec.js b/test/bloodhound_spec.js index c7171a17..46d92513 100644 --- a/test/bloodhound_spec.js +++ b/test/bloodhound_spec.js @@ -283,25 +283,87 @@ describe('Bloodhound', function() { } }); - it('should call #get callback once if cache hit', function() { - var spy = jasmine.createSpy(); + describe('when there is not matching data in the search index', function() { + beforeEach(function() { + this.bloodhound = new Bloodhound({ + datumTokenizer: datumTokenizer, + queryTokenizer: queryTokenizer, + remote: '/test?q=%QUERY', + local: { value: 'not an animal' } + }); - this.bloodhound = new Bloodhound({ - datumTokenizer: datumTokenizer, - queryTokenizer: queryTokenizer, - remote: '/test?q=%QUERY' + this.bloodhound.initialize(); }); - this.bloodhound.initialize(); - this.bloodhound.transport.get.andCallFake(fakeGet); - this.bloodhound.get('dog', spy); + it('should call #get callback once if there is a cache hit', function() { + var spy = jasmine.createSpy(); - expect(spy.callCount).toBe(1); + this.bloodhound.transport.get.andCallFake(fakeGetWithCacheHit); + this.bloodhound.get('dog', spy); - function fakeGet(url, o, cb) { - cb(fixtures.data.animals); - return true; - } + expect(spy.callCount).toBe(1); + + function fakeGetWithCacheHit(url, o, cb) { + cb(fixtures.data.animals); + return true; + } + }); + + it('should call #get callback once if there is a cache miss', function() { + var spy = jasmine.createSpy(); + + this.bloodhound.transport.get.andCallFake(fakeGetWithCacheMiss); + this.bloodhound.get('dog', spy); + + expect(spy.callCount).toBe(1); + + function fakeGetWithCacheMiss(url, o, cb) { + cb(fixtures.data.animals); + return false; + } + }); + + }); + + describe('when there is matching data in the search index', function() { + beforeEach(function() { + this.bloodhound = new Bloodhound({ + datumTokenizer: datumTokenizer, + queryTokenizer: queryTokenizer, + remote: '/test?q=%QUERY', + local: { value: 'dog' } + }); + + this.bloodhound.initialize(); + }); + + it('should call the #get callback twice if there is a cache miss', function() { + var spy = jasmine.createSpy(); + + this.bloodhound.transport.get.andCallFake(fakeGetWithCacheMiss); + this.bloodhound.get('dog', spy); + + expect(spy.callCount).toBe(2); + + function fakeGetWithCacheMiss(url, o, cb) { + cb(fixtures.data.animals); + return false; + } + }); + + it('should call the #get callback once if there is a cache hit', function() { + var spy = jasmine.createSpy(); + + this.bloodhound.transport.get.andCallFake(fakeGetWithCacheHit); + this.bloodhound.get('dog', spy); + + expect(spy.callCount).toBe(1); + + function fakeGetWithCacheHit(url, o, cb) { + cb(fixtures.data.animals); + return true; + } + }); }); }); diff --git a/test/typeahead_view_spec.js b/test/typeahead_view_spec.js index e86e099b..9e775c96 100644 --- a/test/typeahead_view_spec.js +++ b/test/typeahead_view_spec.js @@ -376,12 +376,18 @@ describe('Typeahead', function() { expect(this.input.clearHint).toHaveBeenCalled(); }); - it('should empty dropdown', function() { - this.input.trigger('queryChanged', testDatum.value); + it('should empty dropdown if the query is empty', function() { + this.input.trigger('queryChanged', ''); expect(this.dropdown.empty).toHaveBeenCalled(); }); + it('should not empty dropdown if the query is non-empty', function() { + this.input.trigger('queryChanged', testDatum.value); + + expect(this.dropdown.empty).not.toHaveBeenCalled(); + }); + it('should update dropdown', function() { this.input.trigger('queryChanged', testDatum.value);