2013-06-07 16 views
13

Próbuję użyć resolve w $routeProvider, aby wyświetlić nową trasę tylko po zakończeniu żądania $http. Jeśli żądanie zakończy się pomyślnie, obietnica wynikająca z metody $ http.post() zostanie rozwiązana, a widok zostanie wyrenderowany. Ale jeśli żądanie nie powiedzie się (timeout lub błąd wewnętrzny np.), Obietnica nigdy nie zostanie rozwiązana, a widok nigdy nie zostanie wyrenderowany. Jak radzić sobie z niepowodzeniem żądania przy użyciu resolve?

najważniejszych części kodu jest poniżej:

app.js

$routeProvider.when('/warrantyResult', { 
    templateUrl : 'partials/warranty-result.html', 
    controller : 'WarrantyResultCtrl', 
    resolve : { 
     response : [ 'Warranty', function(Warranty) { 
      return Warranty.sendRequest(); 
     } ] 
    } 
}); 

controllers.js

angular.module('adocDemo.controllers', []).controller('HomeCtrl', [ '$scope', function($scope) { 

} ]).controller('WarrantyCtrl', [ '$scope', '$http', '$location', 'Warranty', function($scope, $http, $location, Warranty) { 
    $scope.submitWarranty = function() { 
     $scope.loading = true; 
     Warranty.setRequestData($scope.data); 
     $location.path('/warrantyResult'); 
    }; 
} ]).controller('WarrantyResultCtrl', [ '$scope', 'Warranty', function($scope, Warranty) { 

    $scope.request = Warranty.getRequestData(); 
    $scope.response = Warranty.getResponseData(); 
} ]); 

services.js

angular.module('adocDemo.services', []).factory('Warranty', [ '$http', '$timeout', function($http, $timeout) { 
    /** 
    * This service is used to query the Warranty Webmethod. The sendRequest 
    * method is automaticcaly called when the user is redirected to 
    * /warrantyResult route. 
    */ 
    var isDataSet = false; 
    var requestData = undefined; 
    var responseData = undefined; 
    return { 
     setRequestData : function(data) { 
      //Setting the data 
      isDataSet = true; 
     }, 
     getRequestData : function() { 
      return requestData; 
     }, 
     sendRequest : function(data) { 
      if(isDataSet) { 
       var request = $http.post('url/to/webservice', requestData); 
       request.success(function(data) { 
        responseData = data; 
       }); 
       return request; 
      } 
     }, 
     getResponseData : function() { 
      return responseData; 
     } 
    }; 
} ]); 

wiem mógłbym użyć obietnicy a zaokrąglij wywołanie $ http i rozwiąż je, nawet jeśli żądanie jest niepowodzeniem, ale zastanawiam się, czy istnieje prostsze rozwiązanie.

Dzięki za czytanie i, miejmy nadzieję, że pomaga :)

+0

Zależy od tego, jak zachowa się Twoja aplikacja, gdy rozwiązywanie się nie powiedzie? – Stewie

+0

Najlepszym zachowaniem byłoby przekierowanie użytkownika na inną trasę (/ requestError?), Gdy rozstrzygnięcie nie powiedzie się. Można również wyświetlić/gwarancjiResult i kontroler tej trasy będzie odpowiedzialny za sprawdzenie, czy żądanie zakończyło się sukcesem, czy nie. – pdegand59

Odpowiedz

0

Po głębokich poszukiwań, nie mogłem znaleźć rozwiązanie tego problemu.

Postanowiłem usunąć definicję rozwiązania w mojej definicji trasy i używam poniższego fragmentu kodu w pliku WarrantyCtrl.

$scope.submitWarranty = function() { 
    $scope.formatUserData(); 
    if ($scope.verifyUserData()) { 
     $scope.loading = true; 
     Warranty.setRequestData($scope.data); 
     Warranty.sendRequest().success(function() { 
      $location.path('/warrantyResult'); 
     }).error(function() { 
      $location.path('/webserviceError'); 
     }); 
    } 
}; 

Niezbyt mądra, ale pracuje jako odnie ... Jeśli ktoś jeszcze rozwiązanie dla oryginalnego problemu, byłbym bardzo zadowolony, aby ją przeczytać!

+0

Co zrobić, jeśli ma się tylko '$ location.path ('/ webserviceError')' i zrobić to w procedurze obsługi błędu wywołania '$ http'. Aby można było rozwiązać trasę i nie trzeba myśleć o odrzuconej obietnicy, ponieważ będzie ona obsługiwana w serwisie –

8

Myślę, że jedynym sposobem, aby to zrobić od resolve jest ręcznie rozwiązać obietnicę zwrócony przez Warranty.sendRequest i owinąć go w nowym obietnicy:

resolve : { 
    response : [ 'Warranty' '$q', function(Warranty, $q) { 
    var dfd = $q.defer(); 

    Warranty.sendRequest().then(function(result) { 
     dfd.resolve({ success: true, result : result }); 
    }, function(error) { 
     dfd.resolve({ success : false, reason : error }); 
    }); 

    return dfd.promise; 

    } ] 
} 

W WarrantyResultCtrl, można sprawdzić, czy wystąpił błąd i generować przekierowanie.

EDIT: znacznie czystsze rozwiązanie:

// WarrantyCtrl 
$scope.$on('$routeChangeError', function() { 
    // handle the error 
}); 
$scope.submitWarranty = function() { 
    $scope.loading = true; 
    Warranty.setRequestData($scope.data); 
    $location.path('/warrantyResult'); 
}; 

(plunker demo)

+0

Twój plunker nie działa. Ale tak czy inaczej za odpowiedź! Zamierzam dać ci szansę na twoje rozwiązanie. – pdegand59

+0

@ pdegand59 whoops, przepraszam! Wczoraj trochę posprzątałem za wcześnie :( – robertklep

3

Co znalazłem to, że sterownik nie jest zwolniony w ogóle jeśli Promise jest rejected, a twój widok nigdy nie jest renderowany - tak jak Ty.

Co odkryłem także, że jeśli obsłużyć Promise z .then() w swoim $routeProvider „s resolve The .then() powróci nowy Promise który jest resolved i kontroler został zwolniony po tym wszystkim, choć bez danych spodziewasz .

Na przykład:

$routeProvider.when('/warrantyResult', { 
    templateUrl : 'partials/warranty-result.html', 
    controller : 'WarrantyResultCtrl', 
    resolve : { 
     response : [ 'Warranty', function(Warranty) { 
      return Warranty.sendRequest() 
       .then(null, function(errorData) { 
        // Log an error here? 
        // Or do something with the error data? 
       }); 
     }] 
    } 
}); 

Teraz w kontrolerze będzie chciał sprawdzić, czy response jest undefined. Jeśli jest to undefined, to wiesz, że połączenie z Warranty.sendRequest() nie powiodło się i możesz podjąć odpowiednie działania.

Za to, co warto, nie podążałem tą drogą. Zamiast tego wstrzyknąłem usługę $location do obsługi resolve i przekierowałem na stronę błędu, jeśli wywołanie $http zostanie odrzucone.

UPDATE Wystarczy zauważyć, że w kontrolerze jesteś wstrzykiwanie usługę Warranty kiedy powinna być zamiast wstrzykiwania response że zdefiniowany w resolve. To uniemożliwi renderowanie widoku do momentu rozwiązania obietnicy zwrócony z Warranty.sendRequest().

Powiązane problemy