angularJs TypeError: Converting circular structure to JSON

angularjs, angularjs-scope, json

Solution

Somewhere you are trying to convert an object to JSON, and that has a circular reference in it, meaning something like this:

var myObj = new Object();
myObject.reference = myObj;

Now trying to convert this to JSON will fail, and produce your error.

Looking at the your edited post, your data structure is something like this:

task.parent -> {project}

project.tasks -> [{task1},{task2},...]

This is supposed to model the relation "project has multiple tasks" and "task belongs to a project".

Now this can obviously not be converted to json format, due to circular referencing.

For the data structure, why not go with:

project = { "id": 42,
            "tasks": [123, 124, 127, ... ],
          }

task = { "id": 123,
         "idproject": 42,
            ...
       }

Whenever you have to show the relationships in your angularjs app, you could go with filters. If you want to show what belongs to a project, filter all tasks by projectid.

Or retrieve only the required data from your backend on the fly, by requesting what tasks the backend has for a specific project id.

That is one way to do it. Of course, having the backend accept appropriate update requests would be working just as well, e.g. updating a project would require the project id, and an array of task ids.

Problem

I have a small AngularJs app like so: ``` // html <div ng-repeat="project in projects"> <h3>{{ project.id }}</h3> <h3>{{ project.title }}</h3> <div ng-repeat="task in project.tasks"> <h4>{{ task.id }}. {{ task.title }}</h4> <button class="btn btn-default" ng-click="showEditTask=true">Edit Task</button> <div class="box row animate-show-hide" ng-show="showEditTask"> <h2>Create a New Task</h2> <form name="newTaskForm" class="form-horizontal"> Title: <br /> <input ng-model="new_task.title" type="text" id="title" name="title" class="form-control" placeholder="Title" required /><br /> Project: <br /> <select ng-model="new_task.project" ng-options="project.title for project in projects" class="form-control"></select><br> </form> <button class="btn btn-success" ng-click="createTask(new_task)" ng-disabled="!newTaskForm.title.$valid">create</button> </div> </div> </div> // app.js concernsApp.factory('ConcernService', function ($http, $q) { ... update: function (obj_url, obj) { var defer = $q.defer(); console.log(obj) $http({method: 'POST', url: api_url + obj_url + obj.id + '/', data: obj}). success(function (data, status, headers, config) { defer.resolve(data); }).error(function (data, status, headers, config) { defer.reject(status); }); return defer.promise; }, }); concernsApp.controller('ProjectsCtrl', function ($scope, $http, ConcernService) { $scope.updateTask = function(obj) { ConcernService.update('tasks/', obj).then(function(){ ... } }); ``` The problem is with updating a task and leaving the parent project as is. If I change the parent project, it all works fine. If I use the same parent project then I get: ``` TypeError: Converting circular structure to JSON ``` I'm not entirely sure what is happening here. Edit So, I can solve the problem like this: ``` $scope.updateTask = function(obj) { parentProject = {'id': obj.project.id}; obj.project = parentProject; ConcernService.update('tasks/', obj).then(function(){ ... }); }; ``` This works as I only actually need the `task.project.id` to update the object. I think the problem is due to that fact that the task references a parent project, which in turn references the child tasks etc. I'm not entirely sure about this tough. However, this solution seems a little hacky to me and I would love to see a better solution.

Original source