2015-12-24 11 views
5

Ich habe eine harte Zeit, Versprechen zu bekommen, mit dem richtigen this Bereich in Prototypen zu arbeiten.Verkettete Versprechen und Prototyp `this`

Hier ist mein 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; 
}); 

Jedes Mal, wenn ich die Tests ausführen ich

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); 
    }); 
}); 

}) erhalten;

bekomme ich folgende Fehlermeldung:

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

ich jetzt, dass $q im Strict-Modus die this innerhalb then-undefined setzt. Ich versuchte mit bind(this) an mehreren Orten, aber nicht Glück ... Irgendwelche Ideen?

Antwort

3

Ich habe bereits eine Frage wie diese here beantwortet. Lassen Sie mich in Kommentaren wissen, wenn Sie noch Fragen haben.

Upd. Versuchen Sie, Ihre resource.Scroll.prototype.nextPage Methode wie folgt zu aktualisieren:

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 

Aber denken Sie daran - wenn Sie eine Funktion als Callback übergeben an einen then oder zu forEach etc es werde verlieren this Kontext. Verwenden Sie also bind genau, wenn Sie die Funktion übergeben, die this Syntax als Rückruf verwendet.

+0

Wenn Sie der Meinung sind, dass Sie eine doppelte Frage gefunden haben, markieren Sie diese bitte, anstatt eine Antwort zu posten, die eine Kopie/einen Link zu einer anderen Antwort darstellt. – ChrisF