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

Javascript AngularJS对象在控制器方法中丢失值,javascript,angularjs,angularjs-scope,javascript-objects,Javascript,Angularjs,Angularjs Scope,Javascript Objects,我是一名初级开发人员,所以我可能遗漏了一些明显的东西,但我感觉有点疯狂。我有一个简单的角度网络应用程序。我正在尝试加载与主机数组相对应的环境名称的哈希字典{development:[“dev.8090”,“host.dev.9009”]}然后使用该字典查找我当前所在的主机。我应该能够将location.host变量传递给getEnv方法,并找到相关键,该键将告诉我所处的环境 字典会加载,但当我尝试在getEnv方法内部访问它时,它会恢复为空对象。提醒你,不是没有定义,而是空的。这是我的密码: v

我是一名初级开发人员,所以我可能遗漏了一些明显的东西,但我感觉有点疯狂。我有一个简单的角度网络应用程序。我正在尝试加载与主机数组相对应的环境名称的哈希字典<代码>{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中定义一个承诺,并在成功调用时解决它。 然后,在控制器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;
          }
        }
      }
     });

    };

非常感谢你。我显然有很多东西要学——你能推荐一个可靠的资源来学习承诺吗?我已经浏览了文档,仍然很模糊。我下面链接的$q页面可能会有所帮助——这就是angular的承诺实现。我喜欢的一个更一般的介绍是$Q所基于的原始Q库:(但请注意,并不是所有的Q方法都在$Q中)。两者都可以@link64显然跳过了包装承诺的创建,所以您可能更喜欢它。您仍然应该学习$q,因为您对承诺感到好奇。@stu.salsbury您不确定他是否投票否决了您,他是一个新用户,所以让我们给他一个怀疑的好处=)