【问题标题】:Able to access object returned by service, but accessing its properties gives undefined能够访问服务返回的对象,但访问其属性给出未定义
【发布时间】:2016-12-18 23:00:06
【问题描述】:

我是一个角度初学者,我正在尝试建立一个从我的 php 后端获取数据并更新控制器的工厂。这是我的基本代码:

工厂

app.factory('sessionStatus', ['$http', function($http){
    return {
        status:function(){
            var status = {};
            $http.get('/game_on/api/api.php?session-status')
            .then(function(response){
                angular.copy(response.data, status);
            });
            return status;
        }
    };
}]);

控制器

app.controller('headerCtrl', ['$scope', 'sessionStatus', function($scope, sessionStatus){

    $scope.sessionStatus = sessionStatus.status();

    console.log($scope.sessionStatus);

}]);

这在控制台中为我提供了以下信息:

Object{}
  session:"false"

但是,当我调整控制器以记录会话属性的值时,如下所示:

console.log($scope.sessionStatus.session);

我只是在控制台中未定义。

我做错了什么?

编辑

对于其他患有我独特的迟钝品牌的人,这是我得出的结论:

这个问题的主要原因是我一直在尝试访问 $http 服务在它的承诺被解决之前返回的异步生成的信息(即在.then() 完成执行之前),这导致了未定义的存在因为在控制器中调用 console.log() 时,生成数据的请求仍在进行中,因此实际上尚未定义数据。

使用 $timeout 服务,我能够延迟调用 console.log(),从而将数据正确记录到控制台。

$timeout(function(){
    console.log($scope.sessionStatus.session);
}, 2000); // logs "false" to the console like originally expected

我之前的想法是,我应该在控制器内尽可能短地调用我的工厂方法,然后在调用之外对其结果进行操作。这显然是个坏主意,因为存在.then(),这样您就可以在请求完成的准确时刻对异步请求的结果采取行动。

事后看来,这一切似乎都很明显,但希望这种解释在未来对其他人有所帮助......

感谢我收到的所有答案,他们对我帮助很大!

【问题讨论】:

  • console.log 是一个异步操作,并不总是在您期望的确切时间记录值。在您的控制器中,如果您将console.log($scope.sessionStatus); 更改为console.log(JSON.stringify($scope.sessionStatus));,那么它会输出什么?编辑:我怀疑您的 console.log 在返回承诺之前完成,这就是您无法访问该属性的原因。
  • @IthinkIcancode - 是的,看来你是对的。 JSON.stringify() 输出一个空对象。
  • @IthinkIcancode - 我能够通过使用 $timeout 在 console.log 调用上设置 2 秒延迟来记录所需的值,所以它似乎肯定是由异步引起的。

标签: javascript angularjs angularjs-factory angularjs-http


【解决方案1】:

您可以在此处对代码进行一些更改。首先,我建议解决承诺并在控制器而不是服务中分配值。接下来,您不需要在结果对象上使用 Angular.Copy,您可以简单地进行变量赋值。尝试类似这样的简单方法,然后构建:

app.factory('sessionStatus', ['$http', function($http){

    return {status: $http.get('/game_on/api/api.php?session-status')}

}]);

app.controller('headerCtrl', ['$scope', 'sessionStatus', function($scope, sessionStatus){

    sessionStatus.status.then(function(result){
        $scope.sessionStatus = result.data; //or some property on result
    });

}]);

【讨论】:

  • 感谢您的回答。我之前尝试过将其作为解决方案,但无法在 promise 的 then 方法之外访问分配的 $s​​cope 变量的值。正如我在对 OP 的评论中指出的那样,这似乎是因为异步,这很好,但是你能告诉我是否实际上可以在 then 方法之外访问这些值,或者它只是一个要求所有代码依赖于这些值的它位于其中,以便它仅在返回承诺后运行?谢谢。
  • 你总是必须在返回方法中有代码。话虽如此,您可以找到一些创造性的方法来使其与您的应用程序一起工作。大多数时候归结为您决定如何构建应用程序,以便 Promise 正确地更新您的值,而不是妨碍您。我整理了一个小提琴来展示一些例子。 check it out here。干杯
【解决方案2】:

尝试从您的factory返回一个承诺:

app.factory('sessionStatus', ['$http', function($http) {
  var factory = {
    status: status
  };

  return factory;

  function status() {
    return $http.get('/game_on/api/api.php?session-status');
  }
}]);

然后在控制器中:

app.controller('headerCtrl', ['$scope', 'sessionStatus', function($scope, sessionStatus) {
  function getSuccess(response) {
    $scope.sessionStstus = response.data;
  }

  function getError(response) {
    console.log('error');
  }

  sessionStatus.status()
    .then(getSuccess)
    .catch(getError);

  console.log($scope.sessionStatus);
}]);

【讨论】:

    【解决方案3】:

    由于 javascript 是异步的,它不会等到 http 响应并返回状态。这就是为什么它返回null。试试这样的

       app.factory('sessionStatus', ['$http', function($http){
                return {
                    status:function(){
                     $http.get('/game_on/api/api.php?session-status')
                    }
                };
            }]);
    
            app.controller('headerCtrl', ['$scope', 'sessionStatus', function($scope, sessionStatus){
    
                $scope.sessionStatus = sessionStatus.status().then(function(response) { 
                   console.log(response);
            });
    
    
        }]);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-13
      • 2015-08-02
      • 1970-01-01
      • 2018-04-24
      • 2021-11-18
      相关资源
      最近更新 更多