角度控制器异步获取模型

时间:2015-01-18 21:51:08

标签: angularjs

我有一个像这样开始的控制器(这个问题简化了):

angular.module('myApp.controllers')
    .controller('MyController', ['$scope', '$routeParams', 'MyService',
                                function ($scope, $routeParams, MyService) {

MyService.fetchWithId($routeParams.id).then(function(model) {
    $scope.model = model;
});

哪个好,但是在整个控制器的许多地方,我都有在视图中引用的参考模型的函数......

$scope.someFunctionMyViewNeeds = function() {
    return $scope.model.someModelAttribute;
};

由于这些通常在获取完成之前运行,因此我最终会出现类似&#34的错误;无法读取未定义的属性"当视图试图看到someModelAttribute时。

到目前为止,我已尝试过三件事:

// before the fetch
$scope.model = new Model();

...但我真的不想要一个新模型,在某些情况下,如果没有其他依赖性,就无法完成初始化。

另一个想法是通过防御未使用的模型来丢弃代码,例如:

return ($scope.model)? $scope.model.someModelAttribute : undefined;

...但是,对于仅在获取完成时存在的条件,代码中有很多防御。

我的第三个想法是"解决"路由提供者中的模型,但我不知道如何做到这一点,并获得$ routeParams,其中保留了获取模型的参数。

我错过了一个更好的主意吗?

1 个答案:

答案 0 :(得分:2)

如果您想使用resolve,请尝试此操作。



var app = angular.module('app', ['ngRoute']);
app.config(function ($routeProvider) {
  $routeProvider.when('/things/:id', {
    controller: 'ThingsShowController',
    resolve: {
      model: function ($routeParams, MyService) {
        return MyService.fetchWithId(+$routeParams.id);
      }
    },
    template: '<a ng-href="#/things/{{model.id}}/edit">Edit</a>'
  });
  $routeProvider.when('/things/:id/edit', {
    controller: 'ThingsEditController',
    resolve: {
      model: function ($routeParams, MyService) {
        return MyService.fetchWithId(+$routeParams.id);
      }
    },
    template: '<a ng-href="#/things/{{model.id}}">Cancel</a>'
  });
});

// Just inject the resolved model into your controllers
app.controller('ThingsShowController', function ($scope, model) {
  $scope.model = model;
});

app.controller('ThingsEditController', function ($scope, model) {
  $scope.model = model;
});

// The rest is probably irrelevant
app.factory('Model', function () {
  function Model(attributes) {
    angular.extend(this, attributes);
  }
  return Model;
});
app.service('MyService', function ($q, Model) {
  this.fetchWithId = function (id) {
    var deferred = $q.defer();
    deferred.resolve(new Model({ id: id }));
    return deferred.promise;
  };
});
// Just to default where we are
app.run(function ($location) {
  $location.path('/things/123');
});
app.run(function ($rootScope, $location) {
  $rootScope.$location = $location;
});
// Because $routeParams does not work inside the SO iframe
app.service('$routeParams', function () {this.id = 123;});
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.9/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.9/angular-route.min.js"></script>

<div ng-app="app">
  <div>Route: {{$location.path()}}</div>
  <div ng-view=""></div>
</div>
&#13;
&#13;
&#13;