Humanity

Edit the world by your favorite way

Angular UI Router の resolve プロパティが失敗(reject)した場合に値を受け取りたい

angularjs - Reloading current state - refresh data - Stack Overflow

Update for newer versions:

$state.reload();

Which is an alias for:

$state.transitionTo($state.current, $stateParams, { 
  reload: true, inherit: false, notify: true
});

まず上記エントリで $state.reload()$state.transitionTo() を呼び出すらしいことが分かった。 $state.go() も同様に $state.transitionTo() を呼び出す。

Home · angular-ui/ui-router Wiki · GitHub

$rootScope.$on('$stateChangeStart', 
function(event, toState, toParams, fromState, fromParams, options){ 
    event.preventDefault(); 
    // transitionTo() promise will be rejected with 
    // a 'transition prevented' error
})

そしてどうやら $state.transitionTo() は promise を返すらしい。 つまり resolve プロパティで reject したら $state.reload()$state.go() が返す promise で受け取れる。

  angular.module('sample')
    .config(['$stateProvider', function($stateProvider) {
      $stateProvider
        .state('top', {
          url: '/',
          templateUrl: '/page/top.html',
          controller: 'topCtrl as $ctrl',
          resolve: {
            fetchResult: ['Book', '$q', function (Book, $q) {
              var deferred = $q.defer()
              Book.get().$promise.then(function onSuccess(res) {
                deferred.resolve({
                  books: res.books,
                  alerts: []
                })
              }, function onError(res) {
                if (angular.isObject(res) &&
                    angular.isString(res.statusText) &&
                    angular.isObject(res.data) &&
                    angular.isObject(res.data.error) &&
                    angular.isString(res.data.error.msg)) {
                  deferred.resolve({
                    books: [],
                    alerts: [{
                      type: 'danger',
                      msg: res.statusText + ' (' + res.data.error.msg.trim() + ')'
                    }]
                  })
                } else {
                  // Offline?
                  deferred.reject({
                    books: [],
                    alerts: [{
                      type: 'danger',
                      msg: 'Couldn\'t connect to server.'
                    }]
                  })
                }
              })
              return deferred.promise
            }]
          }
        })
    }])

    .controller('topCtrl', ['fetchResult', '$state', function topCtrl(fetchResult, $state) {
      var $ctrl = this
      $ctrl.books = fetchResult.books
      $ctrl.alerts = fetchResult.alerts

      $ctrl.closeAlert = function closeAlert(index) {
        $ctrl.alerts.splice(index, 1)
      }

      $ctrl.refresh = function refresh() {
        $state.reload().catch(function onError(fetchResult) {
          $ctrl.alerts = $ctrl.alerts.concat(fetchResult.alerts)
        })
      }
    }])

ほぼ実際のコードからの引用なので長くなってしまった (日記ブログからの転載まんまなので雑)。 画面上の更新ボタンを押した時($ctrl.refresh())、fetchResult を取得するために投げている GET リクエストが失敗し、オフラインっぽかったらその旨を画面上に表示する。