最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Using deeply nested object from JSON in AngularJS - strange behavior - Stack Overflow

programmeradmin1浏览0评论

I'm trying to understand how AngularJS sees an object from a deeply nested JSON. Here's an example plunker. The data es from service and is assigned to $scope.data. The javascript code seems to want me to declare every level of the object first before usage, but referencing a deep level within object from the view HTML always works, and using the deep level in a function kinda works. It's rather inconsistent.

I'm not sure if my understanding of $scope is lacking, or if this has something to do with promise objects. Advise please?

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
    // Unment 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"
        ]
    }
}

I'm trying to understand how AngularJS sees an object from a deeply nested JSON. Here's an example plunker. The data es from service and is assigned to $scope.data. The javascript code seems to want me to declare every level of the object first before usage, but referencing a deep level within object from the view HTML always works, and using the deep level in a function kinda works. It's rather inconsistent.

I'm not sure if my understanding of $scope is lacking, or if this has something to do with promise objects. Advise please?

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
    // Unment 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"
        ]
    }
}
Share Improve this question asked May 4, 2013 at 18:23 Ray ShanRay Shan 1,6753 gold badges17 silver badges25 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 3

Your $http request is asynchronous.

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

Since you have three scope objects that rely on that data it would be best to assign those in the call back.

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

If you do not want to set it all up on the call back, you could also use $broadcast() and $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;
        };
    });
});

Ray, another option is to return the $http.get call since its a promise and use the .then() function to declare $scope.nestedObj or anything else you want to do with data once it returns.

Here's my example: http://plnkr.co/edit/GbTfJ9

You can read more about promises in Angular here: http://docs.angularjs/api/ng.$q

发布评论

评论列表(0)

  1. 暂无评论
ok 不同模板 switch ($forum['model']) { /*case '0': include _include(APP_PATH . 'view/htm/read.htm'); break;*/ default: include _include(theme_load('read', $fid)); break; } } break; case '10': // 主题外链 / thread external link http_location(htmlspecialchars_decode(trim($thread['description']))); break; case '11': // 单页 / single page $attachlist = array(); $imagelist = array(); $thread['filelist'] = array(); $threadlist = NULL; $thread['files'] > 0 and list($attachlist, $imagelist, $thread['filelist']) = well_attach_find_by_tid($tid); $data = data_read_cache($tid); empty($data) and message(-1, lang('data_malformation')); $tidlist = $forum['threads'] ? page_find_by_fid($fid, $page, $pagesize) : NULL; if ($tidlist) { $tidarr = arrlist_values($tidlist, 'tid'); $threadlist = well_thread_find($tidarr, $pagesize); // 按之前tidlist排序 $threadlist = array2_sort_key($threadlist, $tidlist, 'tid'); } $allowpost = forum_access_user($fid, $gid, 'allowpost'); $allowupdate = forum_access_mod($fid, $gid, 'allowupdate'); $allowdelete = forum_access_mod($fid, $gid, 'allowdelete'); $access = array('allowpost' => $allowpost, 'allowupdate' => $allowupdate, 'allowdelete' => $allowdelete); $header['title'] = $thread['subject']; $header['mobile_link'] = $thread['url']; $header['keywords'] = $thread['keyword'] ? $thread['keyword'] : $thread['subject']; $header['description'] = $thread['description'] ? $thread['description'] : $thread['brief']; $_SESSION['fid'] = $fid; if ($ajax) { empty($conf['api_on']) and message(0, lang('closed')); $apilist['header'] = $header; $apilist['extra'] = $extra; $apilist['access'] = $access; $apilist['thread'] = well_thread_safe_info($thread); $apilist['thread_data'] = $data; $apilist['forum'] = $forum; $apilist['imagelist'] = $imagelist; $apilist['filelist'] = $thread['filelist']; $apilist['threadlist'] = $threadlist; message(0, $apilist); } else { include _include(theme_load('single_page', $fid)); } break; default: message(-1, lang('data_malformation')); break; } ?>