Related promises and `this` prototype

I find it difficult to find promises for working with the right area of this inside prototypes.

Here is my code:

 'use strict'; angular.module('testApp').factory('UrlSearchApi', function($resource, URL_SEARCH_API, PAGE_SIZE, $q){ var resource = $resource(URL_SEARCH_API); resource.Scroll = function () { return this.reset(); }; resource.Scroll.prototype.reset = function () { this.visibleItems = []; this.allItems = []; this.busy = null; return this; }; resource.Scroll.prototype.fetch = function(query){ var params = {}; if(query) { params.q = query; } return resource.query(params).$promise; }; resource.Scroll.prototype.loadAllItems = function (results) { var d = $q.defer(); angular.forEach(results, function (result, i) { this.allItems.push(result); if(i === results.length - 1 ) { d.resolve(); } }, this); return d.promise; }; resource.Scroll.prototype.loadVisibleItems = function () { var length = this.visibleItems.length, offset = parseInt(length / PAGE_SIZE), start = PAGE_SIZE * offset, end = start + PAGE_SIZE, subset = this.allItems.slice(start, end), d = $q.defer(); angular.forEach(subset, function (item, i) { this.visibleItems.push(item); if(i === subset.length - 1 ) { d.resolve(); } }, this); return d.promise; }; resource.Scroll.prototype.nextPage = function (query) { if(this.busy) { return; } console.log('nextPage ', query); var tasks = [], that = this; if(!this.allItems.length) { this.reset(); this.busy = true; return this.fetch(query) .then(this.loadAllItems) .then(this.loadVisibleItems) .finally(function () { this.busy = false; }); } else { this.busy = true; return this.loadVisibleItems().finally(function () { this.busy = false; }); } }; return resource; }); 

Whenever I run tests, I get

 describe('#nextPage', function () { var scroll; describe('when there is NO search term (show all)', function () { beforeEach(function (done) { scroll = new UrlSearchApi.Scroll(); $httpBackend.expectGET('/policy/search') .respond(200, arrayGenerator(123)); scroll.nextPage().then(done); $httpBackend.flush(); $rootScope.$apply(); }); it('should load all the items in all items variable', function () { expect(scroll.allItems.length).toBe(123); }); }); 

});

I get the following error:

 TypeError: 'undefined' is not an object (evaluating 'this.allItems') 

Now that $q in strict mode sets this inside then to undefined . I tried using bind(this) in several places, but no luck ... Any ideas?

+5
source share
1 answer

I already answered this question here . Just let me know in the comments if you have any questions.

Update. Try updating your resource.Scroll.prototype.nextPage method as follows:

 if(!this.allItems.length) { this.reset(); this.busy = true; return this.fetch(query) .then(this.loadAllItems.bind(this)) //bind here .then(this.loadVisibleItems.bind(this)) // here .finally(function () { this.busy = false; }.bind(this)); //and here 

But keep in mind - when you pass a function as a callback to then or to forEach etc , it will lose this context . So, use bind exactly when you pass a function using the this syntax as a callback.

+3
source

Source: https://habr.com/ru/post/1239150/


All Articles