【问题标题】:Angular JS $scope.$apply giving interpolation error "TypeError: Converting circular structure to JSON"Angular JS $scope.$apply 给出插值错误“TypeError:将循环结构转换为 JSON”
【发布时间】:2017-12-12 00:20:34
【问题描述】:

我已经编写了一个自定义的角度指令,如下所示:

dirs.directive('sectionInfo', function(){
    return {
        restrict: 'E',
        templateUrl: 'partials/section-home.html',
        transclude: true,
        controller: function($scope, $routeParams){
            var section = this;
            section.sectionItem = [];

            client.entries({"some params"}, 
                function(err, entries){
                    if (err) { console.log(err); return; }
                    $scope.$apply(function(){
                        section.sectionItem = entries;
                });
                }
            );
        },
        controllerAs: 'sectionCtrl'
    }
});

然后显示在一个单独的部分页面中,如下所示:

<section-info></section-info>
<ul class="list-group">
  <li class="list-group-item" ng-repeat="entry in entriesCtrl.index_items">
    <a href="#/entries/{{entry.sys.id}}">
        <h4>{{entry.fields.title}} <small>{{entry.fields.author}}</small></h4>
    </a>
  </li>
</ul>

部分模板代码很简单:

{{sectionCtrl.sectionItem}}

当我加载此页面并保留 $scope$apply 调用时,我收到一个错误:

错误:错误:interr 插值误差 无法插值:{{sectionCtrl.sectionItem}} TypeError:将循环结构转换为 JSON

当我删除 $scope.$apply 调用时,它消失了。知道是什么导致了 $scope.$apply 调用中的循环引用吗?

编辑:条目内容和错误消息的控制台日志。

【问题讨论】:

  • 你能显示entries的值吗?这很可能是导致您的问题的原因,在这种情况下,$apply 所做的只是告诉模板它必须显示新值(entries
  • 完成 - 在 $scope.$apply 之前调用 console.log(entries) :-)
  • 我的意思是,显示它的实际内容 - 问题是条目不能表示为 JSON,因为它的某些部分引用自身,使其循环。

标签: javascript json angularjs


【解决方案1】:

发生的情况是你有一个循环引用,这意味着一个对象通过它的属性或元素之一引用它自己。 (在您的图片中,看起来 sys 字段正在引用其父对象)。为了说明这里有一个通过字段引用自身的对象的示例,您不能将其转换为常规 JSON。这会提醒错误。

angular.module("so", []);

console.error = function(msg){
  console.log("Well, an error occurred, here's what it said:" + msg);
}

angular.module("so").controller("AnswerCtrl", function($scope){

  // make a thing, and put the thing in itself
  $scope.thing = { somefield: 'lalalala' };
  $scope.thing.circle= $scope.thing;

});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="so" ng-controller="AnswerCtrl">
  {{ thing }}
</div>

所以问题与 Angular 并没有太大关系,但更多的是 Angular 使用 JSON.stringify 或类似的东西将对象转换为 JSON 字符串,以便它可以在视图中显示它。

您可以做的是,首先 - 不要尝试使用循环引用显示实际对象。您可以很好地显示其中的一部分,但不要尝试将循环对象序列化为 JSON。

如果你想显示所有属性,你可以使用something like this answer,在这里演示:

angular.module("so", []);

console.error = function(msg){
  console.log("Well, an error occurred, here's what it said:" + msg);
}

angular.module("so").controller("AnswerCtrl", function($scope){

  // make a thing, and put the thing in itself
  $scope.thing = { somefield: 'lalalala' };
  $scope.thing.circle= $scope.thing;

  var cache = [];
  $scope.viewThing = JSON.stringify($scope.thing, function(key, value) {
    if (typeof value === 'object' && value !== null) {
      if (cache.indexOf(value) !== -1) {
        return;
      }
      cache.push(value);
    }
    return value;
  });

});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="so" ng-controller="AnswerCtrl">
  {{ viewThing }}
</div>

如果必须显示,请使用this libary

【讨论】:

  • 感谢修复 - 具有讽刺意味的是,我只是输出整个对象进行调试,要求它查看特定字段使这项工作完美。
【解决方案2】:

试试这样的:

var safeApply = function (scope, callback) {
    if (scope.$$phase != '$apply' && scope.$$phase != '$digest' &&
        (!scope.$root || (scope.$root.$$phase != '$apply' && scope.$root.$$phase != '$digest')))    {
        scope.$apply();
    }
    if (angular.isFunction(callback)) {
        callback();
    }
};

你可以这样称呼它

safeApply($scope, function(){
   section.sectionItem = entries;
 });

【讨论】:

  • 防止 $apply 嵌套足以将函数包装在 $timeout();手动检查范围。$$phase 被认为是不好的做法。
  • 这消除了错误,但屏幕没有更新为正确的值,而是只显示 []
猜你喜欢
  • 2019-01-05
  • 2020-08-18
  • 1970-01-01
  • 2020-09-14
  • 2018-06-08
  • 2021-10-23
  • 1970-01-01
相关资源
最近更新 更多