Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

angularJs TypeError: Converting circular structure to JSON

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.

like image 610
Darwin Tech Avatar asked Nov 28 '13 22:11

Darwin Tech


People also ask

How do I fix Typeerror converting circular structure to JSON?

The "Converting circular structure to JSON" error occurs when we pass an object that contains circular references to the JSON. stringify() method. To solve the error, make sure to remove any circular references before converting the object to JSON.

What is circular structure in JSON?

A circular structure is an object that references itself. To be able to stringify such objects, developers can utilize the replacer parameter in the stringify() method, making sure the function that is being passed in, filters out repeated or circular data.


Video Answer


1 Answers

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.

like image 67
bgse Avatar answered Oct 25 '22 09:10

bgse