AngularJS对象在控制器方法内丢失值

AngularJS object losing value inside controller method

本文关键字:方法 对象 控制器 AngularJS      更新时间:2023-09-26

我是一名初级开发人员,所以我可能错过了一些明显的东西,但我感觉有点疯狂。我有一个简单的Angular网络应用程序。我正在尝试加载一个与主机数组相对应的环境名称的哈希字典。{development: ["dev.8090", "host.dev.9009"]},然后使用该字典来查找我当前所在的主机。我应该能够将location.host变量传递给getEnv方法,并找到将告诉我所处环境的关联键。

字典加载,但当我尝试在getEnv方法内部访问它时,它会恢复为一个空对象。请注意,不是没有定义,而是空的。这是我的代码:

var app = angular.module('app', ['ngResource', 'ui.bootstrap', 'ui.router']);
app.config(['$httpProvider', function ($httpProvider) {
    $httpProvider.defaults.useXDomain = true;
    delete $httpProvider.defaults.headers.common['X-Requested-With'];
}]);
function AppController($scope, $http) {
    window.MY_SCOPE = $scope;
    $scope.env = "Local";
    $scope.dict = {};
    $scope.loadDict = function() {
      $http.get('api/call/').
        success(function(data){
          for (env in data.environment) {
          // data.environment = array of objects
          // [
          // {hosts: ["host1", "host2"], name: "string1"},
          // {hosts: ["host1", "host2"], name: "string2"}
          // ]
            var key = data.environment[env].name;
            $scope.dict[key] = data.environment[env].hosts;
          }
          console.log($scope.envDict)
          // in the console:
          // Object {string1: Array[2], string2: Array[2]}
        }).error(function(data){
            console.error(data);
        })
    };
    $scope.getEnv = function(host) {
      for (key in $scope.dict) {
        // never gets this far because $scope.dict is now = {}
        for (value in $scope.dict[key]) {
          if ($scope.dict[key][value] === host) {
            $scope.env = key;
          }
        }
      }
    };
    $scope.loadDict();
    $scope.getEnv("host1");
}

我可以手动调用这些方法中的每一个,并使用MY_SCOPE变量从控制台获得我想要的结果。如果我把字典硬编码,它就行了。如果我从代码中除$scope.getEnv函数内部之外的任何位置console.log$scope.dict,我就会得到预期的结果。一旦涉及$scope.getEnv,$scope.dict={}。

我已尽力把这些键编入字典。我试着在代码中移动定义。我已经尝试过将loadDict方法导出到工厂中。一切都无济于事。想法?

$scope.loadDict中的$http.get调用是异步的。getEnv在加载字典之前被调用。一旦数据返回,就需要调用getEnv。

让loadDict返回$http.get调用,该调用将为您提供承诺。然后,您可以链接到一个成功回调的承诺。

你还应该把$http调用放在某种服务中,以"角度"的方式进行:)

试试这个:

$scope.loadDict = function() {
      return $http.get('api/call/').
        success(function(data){
          for (env in data.environment) {
         var key = data.environment[env].name;
            $scope.dict[key] = data.environment[env].hosts;
          }
          console.log($scope.envDict)
          // in the console:
          // Object {string1: Array[2], string2: Array[2]}
        }).error(function(data){
            console.error(data);
        })
    };
$scope.loadDict().then(function(result){
     $scope.getEnv("host1");
}

您的问题是没有处理loadDict在内部是异步的这一事实。

解决这个问题的一种方法是等待它完成,方法是返回它的承诺并等待该承诺得到解决。

还有其他方法可以做到这一点,但这可能是最接近你现有的方法之一:

// inject $q so you can make a promise
function AppController($scope, $http, $q) {
    window.MY_SCOPE = $scope;
    $scope.env = "Local";
    $scope.dict = {};
    $scope.loadDict = function() {
      // set up the deferred response
      var deferred = $q.defer();
      $http.get('api/call/').
        success(function(data){
          for (env in data.environment) {
          // data.environment = array of objects
          // [
          // {hosts: ["host1", "host2"], name: "string1"},
          // {hosts: ["host1", "host2"], name: "string2"}
          // ]
            var key = data.environment[env].name;
            $scope.dict[key] = data.environment[env].hosts;
          }
          console.log($scope.envDict)
          // in the console:
          // Object {string1: Array[2], string2: Array[2]}
          // all is well so resolve the promise
          deferred.resolve();
        }).error(function(data){
            console.error(data);
            // reject the promise
            deferred.reject(data);
        })
      return deferred.promise;
    };
    $scope.getEnv = function(host) {
      for (key in $scope.dict) {
        // never gets this far because $scope.dict is now = {}
        for (value in $scope.dict[key]) {
          if ($scope.dict[key][value] === host) {
            $scope.env = key;
          }
        }
      }
    };
    $scope.loadDict().then(
      function () {
        $scope.getEnv("host1");
      },
      function (err) {
        // whatever you want to do if the loadDict function failed to do its job
      }
    );
}
在$http.get()返回数据之前,正在调用$scope.getEnv()。您需要在$http.get().success()块中调用$scope.getEnv(),如下所示:
$scope.loadDict = function() {
    $http.get('api/call/').success(function (data) {
        for (env in data.environment) {
            var key = data.environment[env].name;
            $scope.dict[key] = data.environment[env].hosts;
        }
        $scope.getEnv("host1");
    }).error(function(data){
        console.error(data);
    });
};

您需要异步处理事情。success是异步回调,而getEnv是同步的。这种情况下的解决方案是在loadDict中定义一个promise,并在成功调用时解决它。然后,在控制器getEnv方法中,您将在promise被解析后编写代码:大致代码会是这样的,我还没有测试过,只是写信给你的想法:

$scope.loadDict = function() {
        var deferred = $q.defer(); // to define a promise
      $http.get('api/call/').
        success(function(data){
                   deferred.resolve(data);//resolve the promise on success
          }
         }).error(function(data){
            console.error(data);
        })
     return deferred.promise;//return promise
    };
    $scope.getEnv = function(host) {
       $scope.loadDict().then(
        function(data) {
          for (env in data.environment) {
          // data.environment = array of objects
          // [
          // {hosts: ["host1", "host2"], name: "string1"},
          // {hosts: ["host1", "host2"], name: "string2"}
          // ]
            var key = data.environment[env].name;
            $scope.dict[key] = data.environment[env].hosts;
            for (key in $scope.dict) {
        // never gets this far because $scope.dict is now = {}
        for (value in $scope.dict[key]) {
          if ($scope.dict[key][value] === host) {
            $scope.env = key;
          }
        }
      }
     });
    };