0

I have an AngularJS model which should dynamically bind HTML elements. Now whenever I try to set the value of the model to a JQuery object I get an error message:

TypeError: Converting circular structure to JSON
at Object.stringify (native)

Here is a simplyfied jsfiddle example.

Is there a way to make the code work flawlessly? What exactly is circular?

Charles
  • 50,943
  • 13
  • 104
  • 142
Bastian
  • 4,638
  • 6
  • 36
  • 55
  • You should not try to access DOM elements inside controllers. AngularJS does not advocate it. You can write a directive for the same. – AlwaysALearner Aug 07 '13 at 10:52
  • Also, I dont understand what you're trying to do by assigning a DOM element to the model. – AlwaysALearner Aug 07 '13 at 11:02
  • In the not simplified version I am loading new HTML code on the fly (when the user clicks some button) which is then compiled and inserted into the designated places. – Bastian Aug 07 '13 at 11:15
  • That's where directive comes handy. – AlwaysALearner Aug 07 '13 at 11:16
  • Well, I did not understand directives, yet. The documentation is somehow incomprehensible for me. Anyways I would like to understand where the problem with my approach lies. – Bastian Aug 07 '13 at 11:23

1 Answers1

1

Short answer: your Fiddle can be fixed with the either one of the following lines (depending on what element you need):

$scope.myElement = $('#foo').prop("outerHTML");
$scope.myElement = $('#foo').html();

This change will prevent Chrome from looking too deep (or rather, high up) into the document tree.

I believe that the issue in your Fiddle is related to the way Chrome stringifies the object returned by jQuery. During this stringification it probably attempts to stringify the parent document, too - and there it interacts with Angular magic - in a bad way.

By the way, the code in provided Fiddle does not cause mentioned error. in Firefox, running the Fiddle does not result in an error.

It is not clear to me what you intend to do, but I believe you might be looking for functionality that $compile service provides. It compiles a piece of HTML string or DOM into a template and produces a template function, which can then be used to link scope and the template together.

As mentioned, you should not access DOM from a controller.

Your approach looks very jQuery-ish to me: you seem to be trying to manipulate the data based on DOM. Angular approach is to create a "data-driven document" - the data in your models should determine the contents of DOM.

Baradzed
  • 578
  • 3
  • 10
  • Ok so I would have to compile the code every time. Now what if I just want to move some existing structure to a specific place (the place is denoted by the model)? Would I then have to recompile the existing element every time I want to change the page? This is why I just wanted to simply extract some part of the page and move it to the model - in one line of code. – Bastian Aug 07 '13 at 11:28
  • "Now what if I just want to move some existing structure": If you just want to place a piece of HTML into a place designated by Angular binding, you can use [unsafe HTML binding directive from ngSanitize module](http://docs.angularjs.org/api/ng.directive:ngBindHtmlUnsafe) - though it has its risks for the end user. If the piece will contain Angular bindings, you'll have to compile the template first. – Baradzed Aug 07 '13 at 12:05
  • By the way, the code in provided Fiddle does not cause mentioned error. – Baradzed Aug 07 '13 at 12:22
  • That module sounds promising. With risks you mean that any HTML could be inserted? If so then this is no problem as I have to allow abitrary code on the web page anyway (I am only programing a prototype - safety seems to be not catchy enough for investors...). – Bastian Aug 07 '13 at 18:16
  • Regarding the error: Are you talking about my Fiddle example? In my browser the result pane shows `{{myElement}}` which it should not. And the error I can see in Chrome's Console tab. – Bastian Aug 07 '13 at 18:21
  • I've checked the Fiddle in Firefox. Weird, but FF shows `{"length":1,"0":{},"context":"$DOCUMENT","selector":"#foo"}` in results pane. Chrome indeed gets an error. Weird! – Baradzed Aug 07 '13 at 21:09
  • Now as I see the error Chrome produces, I know how to fix your Fiddle. I updated my answer accordingly. – Baradzed Aug 07 '13 at 21:57
  • Will this `html()` approach keep my Angular specific code alive? If not, I would prefer the `ngBindHtmlUnsafe` solution (http://jsfiddle.net/CxNc2/36/) as the final code will also contain Angular bindings that need to be compiled by Angular.js. – Bastian Aug 08 '13 at 06:53