-1

Why would doing this to the angular todo app stop all functionality?

document.body.onload = function addElement() {
    document.body.innerHTML +=
        '<div  >'+
        '</div> ';
};

All the buttons with ng-click don't call their respective scope functions and pressing enter on the input causes a page reload instead of adding a new todo item.

demo commit:https://github.com/QuantumInformation/todomvc/commit/95ca6233a3e5b3a9775675c3f92d731ecc6032af

isherwood
  • 58,414
  • 16
  • 114
  • 157
Nikos
  • 7,295
  • 7
  • 52
  • 88
  • why would you even need to do this in the first place? There are too many angular ways to do it for this code to ever be needed. – charlietfl Jul 27 '15 at 16:53
  • @Nikos, this piece of code doesn't seem to be the best approach of using Angular. As *charlietfl highlighted above you don't even need to do this as AngularJS provides a better and more elegant way. It seems what you need to do is specify your controller in the page and define the functions you need in the controller scope. Please create a Plunker and share your code. – Denison Luz Jul 27 '15 at 16:58
  • In other words...what are you needing to accomplish? – charlietfl Jul 27 '15 at 17:09
  • @charlietfl my code is a third party script that is seperate from the angular app, it sits on top and records integration tests: see https://github.com/QuantumInformation/test-recorder – Nikos Jul 27 '15 at 17:33
  • can't you just use a directive to insert it? Or ng-include or any standard angular approaches? Also...if you were to append instead of using innerHTMl it should work – charlietfl Jul 27 '15 at 17:34
  • @charlietfl it has to be framework agnoistic as it works with different frameworks. – Nikos Jul 27 '15 at 17:39
  • Adding elements via innerHTML is like erasing the whiteboard and redrawing everything from scratch. Means you just undid all the event handlers that were attached. – epascarello Jul 27 '15 at 17:40

1 Answers1

2

Keep in mind that the question is referring to a utility that is supposed to work across any website, not just an Angular website. If you found this question and are building an Angular app this does NOT apply to you. It's a very specific use case outside the world of building AngularJS apps.

I think @epascarello explained it pretty well in a comment, but to reiterate:

What you’re doing is taking the HTML code currently on the page (which does NOT include event listeners, $scope bindings, etc) and re-rendering a wiped version of it, with a <div> at the end.

If you have a directive with the following template:

<div>
    <p>{{person.name}}</p>
</div>

when Angular displays that on the page it compiles it by binding it to a $scope. So the HTML on the actual page would be:

<div>
    <p>Nikos</p>
</div>

and AngularJS will update that element when person.name changes. How that happens is Angular is storing a reference to the DOM element. Not the string value, the actual object. However, when you do document.body.innerHTML = document.body.innerHTML += '<div></div>', you're taking the HTML and creating a duplicate copy of that. Now, the DOM element AngularJS has the reference to doesn't exist. There is a new version being shown on the page, but AngularJS doesn't know about it.

The proper way to do this would be:

document.body.appendChild(document.createElement('div'));
jkjustjoshing
  • 3,370
  • 4
  • 21
  • 22