Фабрика за обещания в Angular

Нов в Angular, може да използва обещания погрешно. Имам фабрика, която връща обещание:

.factory('myData', ['$http', '$q', function($http, $q) {
    var deferred = $q.defer();

    $http.get('/path/to/endpoint')
        .success(function(data) {
            deferred.resolve(data);
        })
        .error(function(err) {
            deferred.reject(err.what())
        });

    return deferred.promise;
}])

Сега, ако инжектирам фабриката си някъде, мога да използвам обещанието:

.controller('myController', ['$scope', 'myData', function($scope, myData) {
    myData.then(function(result) {
        $scope.data = result;
    });
}]);

Това е добре, но започвам да използвам myData на няколко места и не искам да пиша нов .then във всяка директива и контролер, в който използвам данните. След като обещанието бъде разрешено, не ме интересува вече, има ли някакъв начин да накараш myData да върне обещание, ако не е разрешено, но да върне само резултата, след като приключи с разрешаването?

Казано по друг начин, може ли myData просто да бъде .then result след разрешаването, или трябва да пиша ново .then всеки път?


person diplosaurus    schedule 20.01.2015    source източник
comment
Имате ли стойност по подразбиране, която можете да върнете вместо стойността на разрешеното обещание?   -  person Steve Mitcham    schedule 20.01.2015
comment
@SteveMitcham Разбира се, празен обект ще се справи добре в този случай.   -  person diplosaurus    schedule 20.01.2015


Отговори (2)


За работа с обещания

Първо, вашата myData услуга може просто да върне обаждането:

.factory('myData', ['$http', function($http) {
    return $http.get('/path/to/endpoint').then(function(req){
       return req.data;
    });
}]);

Разопаковане на стойности

Така че знаете как да работите с обещания в Angular... Но вие искате нещо по-добро, искате обещанието да се разгръща автоматично с дайджестите на Angular. Това е трудно, но може да се направи. Обърнете внимание, че може да бъде объркващо в кода и аз наистина не го препоръчвам, но ето общата идея:

Автоматично разопаковане

.factory('myData', ['$http', function($http) {
    var result = []; // initial result to return
    var p = $http.get('/path/to/endpoint').then(function(res){
       result.push.apply(result, res.data); // add all the items
    });
    result.then = p.then; // allow hooking on it
    return result; // return the array, initially empty
}]);

Това ще ви позволи да направите нещо като:

.controller('myController', ['$scope', 'myData', function($scope, myData) {
    $scope.data = myData;
}]);

Което ще постави там празен масив и ще го замени (също причинявайки обобщение), когато пристигнат истинските данни, все още можете да направите myData.then, за да проверите дали е готово да се заредите, така че можете да използвате стария синтаксис, ако трябва да сте сигурни .

Добра идея ли е?

Имайте предвид, че Angular правеше това до версия 1.2 (премахнато напълно във 1.3), но спря да го прави, защото автоматичното разопаковане се смяташе за твърде магическо. Можете да формулирате свои собствени решения, но имайте предвид, че основният екип на Angular реши, че това не е добра идея. Имайте предвид, че неща като ngResource все още правят това.

person Benjamin Gruenbaum    schedule 20.01.2015

Да, разрешете обещанието във вашата услуга/фабрика и препратете разрешената стойност на обещанието във вашите контролери, вместо да препращате и обработвате обещанието във вашите контролери. Надявам се, че има смисъл.

person Patrick Motard    schedule 20.01.2015
comment
Нещо като. Как да се позова само на стойността на обещанието, а не на самото обещание? - person diplosaurus; 20.01.2015