在AngularJS中使用来自JSON的深层嵌套对象 - 奇怪的行为

时间:2013-05-04 18:23:06

标签: javascript json angularjs promise angularjs-scope

我试图了解AngularJS如何从深层嵌套的JSON中看到一个对象。 Here's an example plunker。数据来自服务并分配给$scope.data。 javascript代码似乎希望我在使用之前首先声明对象的每个级别,但是从视图HTML中引用对象内的深层始终有效,并且在函数中使用深层有用。这是相当不一致的。

我不确定我对$scope的理解是否缺乏,或者这是否与promise对象有关。建议好吗?

HTML

<body ng-controller="MainCtrl">
  Referencing nested obj in view works:
  {{data.level1.level2}}
  <br>
  Using nested obj within declared scope var doesn't work:
  {{nestedObj}}
  <br>
  Using nested obj in a function works but throws TypeError:
  {{getLen()}}
</body>

的Javascript

var app = angular.module('app', []);

app.factory('JsonSvc', function ($http) {
  return {read: function(jsonURL, scope) {
        $http.get(jsonURL).success(function (data, status) {
            scope.data = data;
        });
    }};
});

app.controller('MainCtrl', function($scope, JsonSvc) {
    JsonSvc.read('data.json', $scope);

    // Using nested obj within declared scope var doesn't work
    // Uncomment below to break whole app
    // $scope.nestedObj = $scope.data.level1.level2;

    // Using nested obj in a function works but throws TypeError
    // Declaring $scope.data.level1.level2 = [] first helps here
    $scope.getLen = function () {return $scope.data.level1.level2.length};
});

JSON

{
    "level1": {
        "level2": [
            "a",
            "b",
            "c"
        ]
    }
}

2 个答案:

答案 0 :(得分:3)

您的$http请求是异步的。

app.controller('MainCtrl', function($scope, JsonSvc) {
    JsonSvc.read('data.json', $scope);

    //$scope.data.level1.level2 doesn't exist yet at this point in time 
    //and throws an exception
    $scope.nestedObj = $scope.data.level1.level2;

    //$scope.data.level1.level2 doesn't exist yet at this point in time 
    //and throws an exception
    //once Angular does dirty checking this one will work since the 
    //$http request finished.
    $scope.getLen = function () {
        return $scope.data.level1.level2.length
    };
});

由于您有三个依赖于该数据的范围对象,因此最好在回调中分配这些对象。

app.factory('JsonSvc', function ($http) {
  return {read: function(jsonURL, scope) {
        $http.get(jsonURL).success(function (data, status) {
            scope.data = data;
      scope.nestedObj = scope.data.level1.level2;
      scope.getLen = function () {
        return scope.data.level1.level2.length;
      };
        });
    }};
});

如果您不希望在回叫中全部设置,还可以使用$broadcast()$on()

app.factory('JsonSvc', function ($http, $rootScope) {
    return {
        read: function (jsonURL, scope) {
            $http.get(jsonURL).success(function (data, status) {
                scope.data = data;
                $rootScope.$broadcast("jsonDone");
            });
        }
    };
});

app.controller('MainCtrl', function ($scope, JsonSvc) {
    JsonSvc.read('data.json', $scope);
    $scope.name = "world";
    $scope.$on("jsonDone", function () {
        $scope.nestedObj = $scope.data.level1.level2;
        $scope.getLen = function () {
            return $scope.data.level1.level2.length;
        };
    });
});

答案 1 :(得分:3)

Ray,另一种选择是返回$ http.get调用,因为它是一个promise,并使用.then()函数声明$ scope.nestedObj或者一旦返回就要对数据做任何其他事情。

以下是我的示例:http://plnkr.co/edit/GbTfJ9

您可以在此处详细了解Angular中的承诺:http://docs.angularjs.org/api/ng.$q