当页面刷新或深度链接时,angular-ui-router不满足状态解析承诺

时间:2014-08-07 21:32:04

标签: javascript angularjs single-page-application angular-ui-router restangular

使用AngularJS 1.2.16,ui-router和Restangular(对于API服务),我有一个具有子状态的抽象状态,它使用多个视图。子视图接受URL参数(通过$ stateParams)以及根据通过URL传递的给定ID从API获取记录的决心。

当您在整个站点中导航时,一切正常,但是如果您在给定页面上并刷新它(Command / Ctrl + r或单击刷新按钮)或通过点击带有ID的深层链接直接加载页面(这是更关键的问题)API服务被请求命中,但承诺永远不会完成解析,因此数据不可用于状态,控制器,模板等。

根据ui-router的文档,在所有承诺都解决之前,不应实例化控制器。我在Google和SO中搜索过高低,阅读了AngularJS,Restangular和ui-router文档,以及大量的博客,并尝试了我知道的每一次迭代来解决这个问题,找不到任何指向解决方案的东西

以下是相关代码:

company.js (控制器代码)

angular.module('my.company', ['ui.router', 'CompanySvc'])

.config(['$stateProvider', function config ($stateProvider) {
  $stateProvider
    .state('company', {
      abstract: true,
      url: '/company',
      data: {
        pageTitle: 'Company'
      },
      views: {
        'main': {
          templateUrl: 'company/companyMain.tpl.html'
        }
      }
    })
    .state('company.landing', {
      url: '/{id}',
      views: {
        'summary': {
          controller: 'CompanyCtrl',
          templateUrl: 'company/companyDetails.tpl.html'
        },
        'locations': {
          controller: 'CompanyCtrl',
          templateUrl: 'company/companyLocations.tpl.html'
        }
      },
      resolve: {
        companySvc: 'CompanySvc',
        // Retrieve a company's report, if the id is present
        company: ['$log', '$stateParams', 'companySvc', function ($log, $stateParams, companySvc) {
          $log.info('In company.landing:resolve and $stateParams is: ', $stateParams);

          var id = $stateParams.id;

          $log.info('In company.landing:resolve and id is: ', id);

          return companySvc.getCompany(id).$promise;

          // NOTE SO: this was another stab at getting the promise resolved,
          // left commented out for reference
          /*return companySvc.getCompany(id).then(function (response) {
            return response;
          });*/
        }]
      }
    });
  }
])

.controller('CompanyCtrl', ['$log', '$scope', '$state', 'company',
  function CompanyCtrl ($log, $scope, $state, company) {
    $log.info('In CompanyCtrl & $state is: ', $state);
    $log.info('In CompanyCtrl and company data is: ', company);
    $scope.reportData = company ? company : {};
    $log.info('In CompanyCtrl and $scope.reportData is: ', $scope.reportData);
  }
]);

companyService.js (使用Restangular的API服务代码)

angular.module('my.companyService', ['restangular']);

.factory('CompanySvc', ['$log', 'Restangular', function ($log, Restangular) {
  var restAngular = Restangular.withConfig(function (Configurer) {
    Configurer.setBaseUrl('/int');
  });

  // Object for working with individual Companies
  var _companySvc = restAngular.all('companies');

  // Expose our CRUD methods
  return {
    // GET a single record /int/companies/{id}/report
    getCompany: function (id) {
      $log.info('In CompanySvc.getCompany & id is: ', id);

      return restAngular.one('companies', id).customGET('report').then(function success (response) {
        $log.info('Retrieved company: ', response);

        return response;
      }, function error (reason) {
        $log.error('ERROR: retrieving company: ', reason);

        return false;
      });
    }
  };
}]);

可能添加的其他一些要点: * html5mode使用hashPrefix时为true * app正在由Apache提供重写规则集 * base href已设置 *这是整个应用程序中特有的问题,在这种情况下,数据正在一个状态下被解析;我只是选择了这个例子

最后,这是控制台的一些输出:

In company.landing:resolve and $stateParams is: Object { id="d2c936fb78724880656008a5545b01ea445d4dc4"}
In company.landing:resolve and id is: d2c936fb78724880656008a5545b01ea445d4dc4
In CompanySvc.getCompany & id is: d2c936fb78724880656008a5545b01ea445d4dc4\
In CompanyCtrl & $state is: Object { params={...}, current={...}, $current={...}, more...}
In CompanyCtrl and company data is: undefined
In CompanyCtrl and $scope.reportData is: Object {}
In CompanyCtrl & $state is: Object { params={...}, current={...}, $current={...}, more...}
In CompanyCtrl and company data is: undefined
In CompanyCtrl and $scope.reportData is: Object {}
In CompanyCtrl & $state is: Object { params={...}, current={...}, $current={...}, more...}
Retrieved company: Object { $promise={...}, $resolved=false, route="companies", more...}

1 个答案:

答案 0 :(得分:9)

首先只是一个注释。如果你有路由问题(比如那些使用ui-router),而不是使用小提琴,你可以使用像pastebin这样的东西来提供一个可以在本地运行的完整的演示文件,这样就可以测试路由问题。 / p>

我创建了其中一个来自你的小提琴:here

有趣的是,你的模拟演示似乎在路由方面完美无缺。这让我觉得问题出在你的制作服务中。曾经用ui-router惹恼我的一件事是难以解决resolve错误,因为似乎几乎没有错误报告。

如果您将此添加到您的应用运行功能(正如我在上面的链接中所做的那样),您应该更好地解决错误输出:

// handle any route related errors (specifically used to check for hidden resolve errors)
$rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error){ 
    console.log(error);
});