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

时间:2014-09-10 23:32:50

标签: javascript angularjs angularjs-scope javascript-objects

我是一名初级开发者,所以我可能会遗漏一些明显的东西,但我感觉有点疯狂。我有一个简单的Angular webapp。我试图加载与主机阵列对应的环境名称的哈希字典。 {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变量从控制台获取我想要的结果。如果我对字典进行硬编码,它就可以了。如果我从代码中的任何地方调用console.log $ scope.dict,除了$ scope.getEnv函数内部,我得到了我期望的结果。一旦涉及$ scope.getEnv,$ scope.dict = {}。

我已经尝试将密钥硬编码到字典中。我试过在代码中移动定义。我已经尝试将loadDict方法导出到工厂中。一切都无济于事。想法?

4 个答案:

答案 0 :(得分:1)

$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");
}

答案 1 :(得分:0)

您的问题是您没有处理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
      }
    );
}

答案 2 :(得分:0)

在$ 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);
    });
};

答案 3 :(得分:0)

你需要异步对待事物。成功是异步回调,而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;
          }
        }
      }
     });

    };