【问题标题】:Can't assign object returned by service to $scope无法将服务返回的对象分配给 $scope
【发布时间】:2016-11-24 08:35:44
【问题描述】:

我正在尝试将服务返回的数据分配给 $scope 属性。不知何故,它无法正常工作。服务方法通过 $http.get 正确获取数据,但未分配给控制器中的 $scope。

app.service('StoreService', ['$http', function ($http) {

    this.getStoreNamesService = function () {
        console.log('getStoreNames called');
        $http.get('http://localhost:8080/storys')
            .success(function (response, status) {
                console.log(response);
                return response;
            })
    };
}]);

app.controller('ItemFormController', ['$scope', '$http', '$mdDialog', 'itemService', 'StoreService', function ($scope, $http, $mdDialog, itemService, StoreService) {

    $scope.storeNames = StoreService.getStoreNamesService();
}]);

在服务中打印响应会提供正确的数据。但是当我打印 $scope.storeNames 时,它在视图上也给了我未定义的数据。

app.js:

var app = angular.module('BlankApp', ['ngMaterial', 'ngRoute'])
.config(function($mdThemingProvider) {
    $mdThemingProvider.theme('default')
        .primaryPalette('teal')
        .accentPalette('red')
        .warnPalette('red');
});

app.config(function ($routeProvider) {
    $routeProvider
        .when('/addItem', {
            templateUrl: 'templates/addItemForm.html',
            controller: 'ItemFormController'
        })
        .when('/', {
        templateUrl: 'templates/first.html'
        })
        .when('/store', {
            templateUrl: 'templates/itemsInStore.html',
            controller: 'StoreController'
        })
        .when('/item/:itemId', {
            templateUrl: 'templates/itemView.html',
            controller: 'ItemController'
        })
        .otherwise({
            template: '<h1>otherwise template</h1>'
        })
});

脚本标签的顺序:

    <!-- Angular Material requires Angular.js Libraries -->
<script src="js/angular-1.5.8/angular.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-animate.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-aria.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-messages.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular-route.min.js"></script>

<!-- Angular Material Library -->
<script src="js/AngularMaterial/angular-material.js"></script>

<!-- Your application bootstrap  -->


<script src="js/app.js"></script>
<script src="js/service/itemService.js"></script>
<script src="js/service/StoreService.js"></script>
<script src="js/controller/testController.js"></script>
<script src="js/controller/SideNavController.js"></script>
<script src="js/controller/ItemFormController.js"></script>

<script src="js/controller/sampleController.js"></script>
<script src="js/controller/ItemController.js"></script>

【问题讨论】:

  • 发生这种情况是因为 AJAX 调用未完成并且您的函数在此之前返回。要么使用 $scope 作为参数发送回调,要么更好地使用 Promise

标签: javascript angularjs angularjs-http


【解决方案1】:

这应该可行:

app.service('StoreService', ['$http', function ($http) {

this.getStoreNamesService = function () {
    console.log('getStoreNames called');
    return $http.get('http://localhost:8080/storys').then(
        function success(response, status) {
            console.log(response);
            return response;
        })
    };
}]);

app.controller('ItemFormController', ['$scope', '$http', '$mdDialog', 'itemService', 'StoreService', function ($scope, $http, $mdDialog, itemService, StoreService) {
    StoreService.getStoreNamesService().then(function(result){
        $scope.storeNames = result;
    });
}]);

你只能在 promise 解决后分配变量storeNames。按照你的方式,承诺被分配给变量。

还要注意 .success() 已弃用。请改用.then()。

【讨论】:

    【解决方案2】:

    你弄错了几件事

    1. 你应该从服务方法getStoreNames中通过$http方法返回promise对象。
    2. 您不应将$scope(context) 传递给服务来修改它。
    3. 您应该使用.then 函数从promise 对象中获取值。

      app.service('StoreService', ['$http', function ($http) {
        this.getStoreNamesService = function () {
          //return promise here
          return $http.get('http://localhost:8080/storys');
        };
      }]);
      

    控制器

    StoreService.getStoreNamesService($scope).then(function(response){
       $scope.storeNames = response.data;
    });
    

    【讨论】:

      【解决方案3】:

      使用 Angular 时,最好返回一个 Promise,$http 服务返回一个 Promise,您可以将成功回调移动到范围:

      app.service('StoreService', ['$http', function ($http) {
          this.getStoreNamesService = function () {
              return $http.get('http://localhost:8080/storys');
          };
      }]);
      
      app.controller('ItemFormController', ['$scope', '$http', '$mdDialog', 'itemService', 'StoreService', function ($scope, $http, $mdDialog, itemService, StoreService) {
          StoreService.getStoreNamesService().then(function (response, status) {
              $scope.storeNames = response.data;
          });
      }]);
      

      或者你可以创建一个延迟对象,它类似于返回一个承诺,除了它只返回数据而不是 $http 状态代码等:

      app.service('StoreService', ['$http', '$q', function ($http, $q) {
          this.getStoreNamesService = function () {
              var deferred = $q.defer();
              $http.get('http://localhost:8080/storys').then(function(response, status){
                  deferred.resolve(response.data);
              });
              return deferred;
          };
      }]);
      
      app.controller('ItemFormController', ['$scope', '$http', '$mdDialog', 'itemService', 'StoreService', function ($scope, $http, $mdDialog, itemService, StoreService) {
          StoreService.getStoreNamesService().then(function (data) {
              $scope.storeNames = data;
          });
      }]);
      

      见$q

      在这两种情况下,范围对象都应填充在控制器中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-06-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-25
        • 2015-03-04
        • 1970-01-01
        相关资源
        最近更新 更多