3

I'm building myself a little js library and I've come across a problem with the append and prepend methods. This is my current setup

prepend: function(str) {
    this.node.innerHTML = str + this.node.innerHTML;
},
append: function(str) {
    this.node.innerHTML += str;
}

They both do work as expected, content is being added, but unfortunately all event listeners of elements that are inside the tag I'm modifying are being lost. It's funny how I didn't figure that may cause an issue. Anyway I tried looking at jQuery to see how they're doing it but their code is apparently not meant to be understood by me. I tried looking up other questions but didn't really find a solution for this.

How can I achieve this without losing my listeners?

php_nub_qq
  • 15,199
  • 21
  • 74
  • 144
  • 1
    jQuery builds actual DOM nodes with the internal DOMManip function, that way all elements are appended with the native appendChild, prepended with insertBefore etc. and innerHTML is never used. – adeneo Jan 02 '14 at 03:42
  • @adeneo so it turns out to be a harsh job I guess, but how would I split an html string into nodes :/ – php_nub_qq Jan 02 '14 at 03:47
  • You wouldn't, you would parse the string with the browsers parser, for instance by setting the string as the content of a documentFragment, then extract the nodes and insert them into the actual DOM. – adeneo Jan 02 '14 at 03:56
  • see the accepted ans of my Q http://stackoverflow.com/q/11515383/908879 – ajax333221 Jan 02 '14 at 03:58
  • @adeneo I'm sorry could you elaborate, set the string as the content of a documentFragment? – php_nub_qq Jan 02 '14 at 04:03
  • 1
    http://stackoverflow.com/questions/7474710/can-i-load-an-entire-html-document-into-a-document-fragment-in-internet-explorer/7539198#7539198 – adeneo Jan 02 '14 at 04:11

4 Answers4

2

If you move the elements around the DOM as objects rather than a primitive string representation, their attached events and other meta will be maintained.

You'll need to utilize the DOM's appendChild and insertBefore methods. Fiddle: http://jsfiddle.net/QMLpL/2/

Here is your updated snippet:

prepend: function(newNode) {
    this.node.insertBefore(newNode,this.node.firstChild);
},
append: function(newNode) {
    this.node.appendChild(newNode);
}

The updated snippet expects a DOM node rather than a string.


If you are expecting a string, consider utilizing the string as a CDATA node:

node = document.createTextNode(str);

Enhanced fiddle: http://jsfiddle.net/QMLpL/3/

Usage:

prepend: function(str) {
    newNode = document.createTextNode(str);
    this.node.insertBefore(newNode,this.node.firstChild);
},
append: function(str) {
    newNode = document.createTextNode(str);
    this.node.appendChild(newNode);
}

The contents of the linked fiddle are as follows.

HTML:

<div id="one">
    <p><a id="clicky" href="#">Hello World</a></p>
</div>
<div id="two">
    <p>Lorem Ipsum</p>
</div>

JavaScript:

var clicky = document.getElementById('clicky');
clicky.onclick = function() {
    console.log('clicked!');
    return false;
};

function append(target,node) {
    if ( typeof node === 'string' ) {
        node = document.createTextNode(node); // cast string as CDATA
    }
    target.appendChild(node);
}

function prepend(target,node) {
    if ( typeof node === 'string' ) {
        node = document.createTextNode(node);
    }
    target.insertBefore(node,target.firstChild);
}

var twoDiv = document.getElementById('two');
append(twoDiv,clicky);

var newElement = document.createElement('p');
newElement.onclick = function() {
    console.log('clicked the p');
    return false;
};
newElement.appendChild(document.createTextNode('Dolor sit amet.')); // add a CDATA node to the new P element
prepend(twoDiv,newElement);

append(twoDiv,'Waddup?');
zamnuts
  • 9,492
  • 3
  • 39
  • 46
  • I'm looking for a way to append html strings, but this would be my alternative. Thank you for your effort! – php_nub_qq Jan 02 '14 at 04:04
  • @php_nub_qq I'm a bit confused, if you have a string representation of HTML why would you be interested in maintaining the events of the children? If the children have events, that would mean you have the parent-most node object in your repertoire. Dealing with the raw DOM node would be faster than serializing it as a string, then having the DOM re-parse it. – zamnuts Jan 02 '14 at 04:08
1

Use insertAdjacentHTML:

prepend: function(str) {
    this.node.insertAdjacentHTML("beforebegin", str);
},
append: function(str) {
    this.node.insertAdjacentHTML("afterend", str);
}
Kernel James
  • 3,752
  • 25
  • 32
  • This appears to be exactly what I'm looking for, I can't believe firefox doesn't support it `:<` – php_nub_qq Jan 02 '14 at 04:00
  • 1
    According to MDN Firefox version 8.0 and above supports `insertAdjacentHTML`. – zamnuts Jan 02 '14 at 04:09
  • Actually I was looking at old information, MDN states that all major browsers currently support this, even though it is not in the ECMA. Thank you! – php_nub_qq Jan 02 '14 at 04:10
0

Okay here's what might work, I'm not sure. How about making a deep clone of the object in question. And then parsing the new html you want to to add in another variable. Next looping recursivly over these 2 objects and adding all their children to a new one. Finally replacing the object in question with your new object. This way the listeners are preserved I think. It won't be easy to write but it might give you an idea. Cheers.

user3152069
  • 408
  • 3
  • 9
  • Why parse it yourself when you have an entire DOM engine at your disposal? – zamnuts Jan 02 '14 at 04:00
  • insertAdjacentHTML IS NOT SUPPORTED BY FIREFOX. Keep this in mind. I ment to use the appendChild for the recursive looping. And the innerHTML to create your new merging obj. – user3152069 Jan 02 '14 at 04:05
  • It appears that `insertAdjacentHTML` is supported by all major browsers. See MDN https://developer.mozilla.org/en-US/docs/Web/API/element.insertAdjacentHTML?redirectlocale=en-US&redirectslug=DOM%2Felement.insertAdjacentHTML – php_nub_qq Jan 02 '14 at 04:14
  • Well it is now version 24, I believe anyone who hasn't updated since 2012 brought this on their own `:D` – php_nub_qq Jan 02 '14 at 04:18
0

Please user insertBefore() JS HTML DOM METHOD for add string before your element content

Check MDN

OR user appendChild() JS HTML DOM METHOD for add string after your element content

Check MDN

Shyam
  • 782
  • 5
  • 12