【问题标题】:Angular http returns $$state objectAngular http 返回 $$state 对象
【发布时间】:2015-03-24 15:38:32
【问题描述】:

我定义了以下工厂:

angular.module("account").factory("users",["$http",
    function(a){
      return {
         getUser: function(){
            return a.get("/user/me").then(function(r){
                return r.data;
            });
        }
    };
  }
]);

还有我的控制器:

angular.module("test.controllers",["account"])
.controller("TestCtrl",["$scope","users",
    function(a,u){
        a.user = u.getUser();
        console.log(a.user);
}]);

这是控制台日志:

 d {$$state: Object, then: function, catch: function, finally: function} $$state: Object status: 1 value: Object user: Object__v: 0 _id: "54c1fg29f36e117332000005" temp: "1ce3793175e0b2548fb9918385c2de09"  __proto__: Object __proto__: Object __proto__: Object __proto__: Object

上面的代码返回一个状态对象而不是用户对象。 但是从日志来看,状态对象的值是用户对象。我如何获取用户对象?还是我这样做完全错了?

我知道另一种方法是返回 $http.get 并在控制器中调用 then() 方法。但是我会经常使用用户对象,如果我在控制器中调用 then() 方法,它几乎与在控制​​器中使用 $http.get 而不是工厂相同。

【问题讨论】:

  • 您在console.log 中看到的对象是您在调用.getUser 时调用.get 返回的promise。对 .then 的调用会创建一个新的 Promise,当您从那里返回某些内容时,它会修改为任何后续 then 解析的数据。
  • 从另一个帖子中查看我的答案:stackoverflow.com/a/38007172/1739949

标签: javascript angularjs angular-services


【解决方案1】:

JavaScript I/O 通常是异步的,包括在这种情况下。你的getUser 调用返回一个$q promise。为了打开它,你必须链接到它,然后像这样打开它:

angular.module("test.controllers",["account"])
.controller("TestCtrl",["$scope","users",
    function(a,u){
        u.getUser().then(function(user){
            a.user = user;
            console.log(a.user);
        });
}]);

如果您使用路由,您可能还想查看路由中的resolve 选项。另见this related question

【讨论】:

  • 但是如果我在控制器中使用 then(),我可以摆脱工厂,只需调用 $http.get('/user/me').then(..)。
  • @wdphd 你可以,这些调用是在工厂而不是在控制器中的原因是因为它使代码更整洁 - 不是因为它很神奇:) 你可以在工厂中编写的任何东西你也可以在控制器内部编写它只是不利于很好的关注点分离。
【解决方案2】:
angular.module("account").factory("users",["$http",
    function(a){
      var factObj = {
         user: null,
         getUser: function(){
            return a.get("/user/me").then(function(r){
                factObj.user = r.data;
            });
        }
      factObj.getUser();

      return factObj;
    };
  }
]);

angular.module("test.controllers",["account"])
.controller("TestCtrl",["$scope","users",
    function(a,u){
        a.userService = u;
}]);

在你看来

<div ng-controller="TestCtrl as test">{{test.userService.user}}</div>

基于 cmets 的编辑,确实这不适用于控制器或视图,因为您可能拥有它们,但这种模式运行良好,并且无需在每个可能重用数据的控制器中使用 .then。

通常将模型存储在处理获取数据的工厂或服务中,这样可以更轻松地将数据获取到您需要的每个视图中。不利的一面是,当引用此工厂时,您将获取用户,而不是从控制器显式触发 getUser 函数。如果你想解决这个问题,你可以在 getUser 函数中存储第一次请求时的承诺,如果它已经设置,则只为所有后续调用返回该承诺,这样你可以多次调用 getUser 而无需重复 API 请求。

【讨论】:

  • 这仍然会失败 - OP 的问题在于 get 的异步性,而不是数据的存储位置。
  • Benjamin 我在很多工作应用程序中使用这种模式,只要您通过控制器中的工厂引用数据,它就可以正常工作。更详尽的例子在这里plnkr.co/edit/cqyeXB5WgKZynQZdvEYP?p=preview
  • 要知道这行不通,您只需阅读代码即可。 a.get 返回一个符合 Promises/A+ 的承诺 - 它必须才能成为 A+ 承诺推迟执行到下一个周期。您将调用getUser,它将返回一个承诺,然后调用.user,它将返回null。如果您遇到任何其他行为,请提交错误against the issue tracker。我所描述的行为非常明确。
  • @shaunhusain:您在 var factObj 中返回 factObj 并抛出错误。正如上面 Benjamin 所说,它返回 null 将其移出工厂 obj
  • 应该工作plnkr.co/edit/pVDWKb5HEtsTnnYo7ANH?p=preview 您对 $http 的调用仍然是异步的,因此如果您尝试立即从工厂控制台.log 值,在响应返回之前它仍然是未定义的,但由于大多数当 $apply 从 $http 调用运行时,您绑定到视图中的数据的时间无论如何观察者都会负责更新它。我还删除了注释,因为我只是在构建过程中使用 ngAnnotate 执行此操作。
【解决方案3】:

我这里有一个类似的场景..我希望它可以帮助某人......

我的工厂..

 angular.module('programList.services',[])
    .factory('PROGRAMS', function($http) {
     return {
       getprogramList: function() {
       return $http.get('/api/programs/list').then(function(result) {
       return result.data[0];
       });
      }
     };
    });

这是我的控制器..

 angular.module('programList.services'])
 .controller('tviProgramsController',
    function($scope,$state,$stateParams,PROGRAMS){
        //this is the call to access the list as answered by Benjamin Above using then on success 
        PROGRAMS.getprogramList().then(function(list){
                  $scope.programlist = list;
              });
  });

;

这是在服务器端的路由器上...

  var express     = require('express'),
     programscontroller = require(path + 'programservercontroller'),
     router         = new express.Router();
     router.get('/api/programs/list', programscontroller.programlist);

这是mysql调用的模块

var con   = require('../../database/dbcon'),
mysql = require('mysql');

module.exports.programlist = function(req, res){
 var data = req.params.data;
 var sql = "CALL `sp_programlist`";
  con.query(sql, function(err, result) {
      if(err){
          throw err;
      } else {
          res.send(JSON.stringify(result));
      }
     });
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-22
    • 2018-08-12
    • 2020-12-24
    • 1970-01-01
    • 2021-10-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多