2016-08-16 19 views
5

Istotne skrzypce: https://jsfiddle.net/tqf4zea7/1/

Używam $ q w kątowym kontrolera. Aby przetestować kilka scenariuszy, stworzyłem tablicę zakresu naciskać wiadomości:

$scope.messages = []; 

mam skonfigurować funkcję, która zwraca $ q funkcję jako tak:

function returnAPromise(valToReturn){ 
    return $q(function(resolve, reject){ 
     $timeout(function(){ 
      resolve(valToReturn); 
     }, 500); 
    }); 
} 

Mam następnie .then() wezwanie na wynik, który wygląda tak:

returnAPromise('third').then($scope.messages.push); 

od kiedy tylko chcą pchnąć wartość, że obietnica została rozwiązana z do tablicy, pomyślałem, może po prostu przejść się po naciśnięciu spotkał hod tablicy komunikatów, ale kiedy to zrobić, pojawia się następujący błąd:

VM289 angular.js:12520 TypeError: Array.prototype.push called on null or undefined 
    at processQueue (VM289 angular.js:14792) 
    at VM289 angular.js:14808 
    at Scope.$eval (VM289 angular.js:16052) 
    at Scope.$digest (VM289 angular.js:15870) 
    at Scope.$apply (VM289 angular.js:16160) 
    at VM289 angular.js:17927 
    at completeOutstandingRequest (VM289 angular.js:5552) 
    at VM289 angular.js:5829 

Jeśli Załączam pchnięcie w funkcji, to działa dobrze:

returnAPromise('third').then(function(message){ 
    $scope.messages.push(message) 
}); 

Czy to zamknięcie Wydanie I nie rozumiesz?

Odpowiedz

6

Trzeba związać impuls ponieważ używa this

returnAPromise('third').then($scope.messages.push.bind($scope.messages)); 
+1

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind sekcja Przykłady opisuje problem i dlaczego .bind() rozwiązuje go.Niestety zawiera ona wiersz "Częsty błąd dla nowych programistów JavaScript". = [Zostałem zdegradowany. – sonicblis

1

wiem, że jest akceptowane odpowiedź, ale będzie to wyjaśnić jaśniej tutaj

Przykład

zacznijmy od przykładu

var scope = { 
    scopeFn: function() { 
    console.log('this', this) 
    } 
} 

function callFn(fn) { 
    fn(); 
} 

callFn(obj.scopeFn) // will log window object 
callFn(function() { 
    obj.scopeFn(); 
});// will log scope object 

jak widać, zawijanie funkcji jon nadadzą nazwanego obiektu wartość tego, ale wywołanie go bezpośrednio bez zawijania spowoduje wywołanie obiektu okna.

dlaczego?

this spowoduje powiązanie z obiektem, z którego pochodzi.

W pierwszym przykładzie callFn(obj.scopeFn) podajesz funkcję jako parametr, dlatego gdy funkcja jest wywoływana, jej wywołanie nie następuje bezpośrednio z obiektu scope. (scope obiekt zostaje utracony, wysyłane jest tylko odniesienie do funkcji).

w drugim przykładzie wywołuje się funkcję scopeFn z obiektu, dlatego this będzie wiązał się z jej obiektem. (scope obiekt nie jest stracone, jak cała sprawa jest tam, kiedy jego nazwie)

Rozwiązanie

Aby rozwiązać ten problem, trzeba powiązać funkcję są przechodzącą jako parametr dla determinacji, więc to będzie zawsze być wywołany tak, jakby był wywoływany z jego obiektu nadrzędnego.

var scopeMessage = $scope.messages; 
returnAPromise('third').then(scopeMessage.push.bind(scopeMessage));