How to add event to element created with js? - javascript

I created the script below. It puts the body in a div, as desired. However, the event handler fails. I'm sure it's a simple error.
body_html = document.body.innerHTML;
new_html = "<div id='realBody'>" + body_html + "</div>";
document.body.innerHTML = new_html;
document.body.getElementById("realBody").addEventListener("mouseover", function(event) {alert('body');});
How to make the event work? (Feel free to rewrite the whole thing if there's a better (simpler) way.
Edit: This works, some comments say it's the wrong way to put the body into a div, but i see no problems:
body_html = document.body.innerHTML;
new_html = "<div id='realBody'>" + body_html + "</div>";
document.body.innerHTML = new_html;
document.getElementById("realBody").addEventListener("mouseenter", function(event) {alert('body');});
thx!

You need to change document.body.getElementById() to document.getElementById()
document.getElementById("realBody").addEventListener("mouseover", function(event) {alert('body');});

You should attach event listener like,
body_html = document.body.innerHTML;
new_html = "<div id='realBody'>" + body_html + "I am border</div>";
document.body.innerHTML = new_html;
document.getElementById("realBody").addEventListener("mouseover", function (event) {
alert('body');
});
DEMO

The error you're receiving is probably because of this line:
document.body.getElementById("realBody").addEventListener("mouseover", function (event) { alert('body'); });
you need to modify it to this:
document.getElementById("realBody").addEventListener("mouseover", function (event) { alert('body'); });
document.body.getElementById() just needs to be document.getElementByid()
A more proper way to add elements to the DOM would be to do something like below:
var divEl = document.createElement("div");
divEl.id = "realBody";
var textNode = document.createTextNode("Hover over me");
divEl.appendChild(textNode);
document.body.appendChild(divEl);
divEl.onmouseover = function (event) {
alert('body');
}

As everybody explained, you need to call the getElementById() on the document object, not in an element.
But your code will loose any event handlers attached to the elements prior to your code execution as you are clearing the html and creating a new dom structure you overwritting the innerHTML.
Instead just move the existing dom to the new element like
var wrapper = document.createElement('div');
wrapper.id = 'realBody';
while (document.body.firstChild) {
wrapper.appendChild(document.body.firstChild);
}
document.body.appendChild(wrapper);
wrapper.addEventListener("mouseover", function (event) {
console.log('body');
});
Demo: Fiddle

Related

get dynamic text in text area on every click on div

I want to open the CKEDITOR on click-event of div, and want the div contents in that textarea of ckeditor
but somehow this is not working.
Thanks in advance, and sorry for my poor english
function createEditor() {
$('DIV').click(function(event) {
var id1 = event.target.id;
//alert(id1);
document.getElementById("editor1").value = '';
var newtext = document.getElementById(id1).innerHTML;
alert(newtext);
document.getElementById("editor1").value += newtext;
});
document.getElementById("contents").style.display = "block";
}
Remove createEditor() function and try it
$('DIV').click(function(event) {
var id1 = event.target.id;
//alert(id1);
document.getElementById("editor1").value = '';
var newtext = document.getElementById(id1).innerHTML;
alert(newtext);
document.getElementById("editor1").value += newtext;
});
document.getElementById("contents").style.display = "block";
Try this to add data to the textarea.
$("#editor1").val(newtext);
or use
$('#editor1').append(newtext);
This solution will rely more on jQuery. First, if you want this function to be triggered when ever a div is clicked, get rid of your function(), it's not necessary since your event will be triggered every time a div is clicked.
This should solve your problems:
$('div').click(function(e) {
$id1 = $(this).attr("id");
alert($id1);
$("#editor1").val(' '); //Are you sure you want to empty your textarea?
$newtext = $("#"+$id1).html();
alert($newtext);
$("#editor1").val($newtext); //Because when you append the newtext it won't append but replace the text it's already on this.
$("#contents").css("display","block");
});
Here's a fiddle with a similar example of using your function:
If you just want the text of the clicked div and you're using jQuery try
$("div").click( function() {
var newtext = $(this).text();
$("#editor1").text( newtext );
});

Unable to attach event to an element in contextual fragment

I tried to attach an event to an element in a contextual fragment and then appended this element to body. But the event doesn't get attached.
var range = document.createRange();
var listE1 = "<div>Hello World</div>"
range.selectNode(document.getElementsByTagName("div").item(0));
var element = range.createContextualFragment(listEl);
element.querySelector("div").addEventListener("click", function () {
alert("hello");
}, true);
document.body.appendChild(element);
After appending this element to body, the div doesn't have any event at all
I stumbled upon here after looking for the same answer and I know this is a very old question hope this helps or points to a better direction.
The range.createContextualFragment(listEl); returns a DocumentFragment. In a nutshell a DocumentFragment is minimalized DOM object. It doesn't have an attachEventListener.
If you want you can either use DOMParser or use document.createElement
Here's an example of how you can use DOMParser
let listE1 = "<div>Hello World</div>"
let element = new DOMParser().parseFromString(listE1 , 'text/html').documentElement;
element.addEventListener("click", function () {
alert("hello");
}, true);
document.body.appendChild(element);
Hope this helps.
only a lot of little mistake, the code should run right easy:
we should add the fragment to document, then add the event listener
var range = document.createRange();
var listE1 = "<div id='hello'>Hello World</div>"
range.selectNode(document.getElementsByTagName("div").item(0));
var element = range.createContextualFragment(listE1); // listel -> liste1
document.body.appendChild(element); // should add to document first
document.querySelector("div#hello").addEventListener("click", function() { // element->document
alert("hello");
}, true);

Javascript addEventListener inside a loop

I'm trying to add an event listener to some elements which I generate in the loop. I must use div.lastChild - although in this example it's pretty stupid. But that's just demonstration:
<div id="someArea">
</div>
<script type="text/javascript">
var func = function() {
alert('Callback works');
}
var func1 = function() {
alert('Test');
}
var func2 = function() {
alert('Test2');
}
var div = document.getElementById("someArea");
var callbacks = [func, func1, func2];
for(var i = 0; i <= 2; i++) {
div.innerHTML += '<input type="button" value="' + i + '" />';
(function(i) {
console.log(div.lastChild);
div.lastChild.addEventListener('click', callbacks[i], false);
}(i));
}
</script>
The event works only for the last button. What am I missing here?
Why it's not working.
When you do this...
div.innerHTML += '<input type="button" value="' + i + '" />';
...in every iteration of the loop you're destroying the old DOM nodes inside div (and therefore their handlers), and recreating new nodes (but no handlers). The destruction includes the input elements that were added in previous iterations.
That's why only the last one works, since after that point, you've assigned the handler to the last element, but the other ones are brand new and untouched.
A solution.
Instead of treating the DOM as though it was a string of HTML markup, consider using DOM methods for element creation...
for(var i = 0; i <= 2; i++) {
var input = document.createElement('input');
input.type = 'button';
input.value = i;
input.addEventListener('click', callbacks[i], false);
div.appendChild(input);
}
Notice that I removed the immediately invoked function. For your code, it was unnecessary since i is being evaluated in the loop instead of later in the handler.
The DOM is not HTML, but .innerHTML makes you think it is.
It's important to understand innerHTML. When working with the DOM, there is no HTML markup. So when you get the .innerHTML, the DOM is being analyzed, and a new HTML string is created.
When you assign to .innerHTML, you're destroying all the current content, and replacing it with new nodes created from the HTML string.
So when you do...
div.innerHTML += '<input...>'
...you're first creating the new HTML string from the current content, then concatenating the new HTML content to the string, then destroying the old nodes and creating new ones from the new string.
This is terribly inefficient, and as you've already seen, it destroys any data associated with the original elements, including handlers.

How can I pass an object to a function in innerHTML (JavaScript)?

How can I pass an object to a function in innerHTML?
Here is an example:
function clickme()
{
var coord = {x:5, y:10};
testimageih(coord);
}
function testimageih(coord)
{
var html = "<img id=\"sam1\" border=\"0\" name=\"sam1\" src=\"sample.gif\" " +
"onLoad=\"ImageOnLoad(" + coord + ");\"></img>";
document.getElementById("content").innerHTML = html;
}
function ImageOnLoad(coord)
{
if (coord) alert("Success");
else alert("Fail");
}
How can I pass this object, coord? It's my only other recourse, at the moment, is passing coord.x and coord.y, instead of the object.
Thank you.
The simplest way is to create an image, attach the event handler and insert the element using DOM methods.
function testimageih(coord)
{
var img = document.createElement('img');
img.id = 'sam1';
img.border = 0;
img.name = 'sam1';
img.src = 'sample.gif';
img.onload = function() {
ImageOnLoad(coord);
};
document.getElementById('content').appendChild(img);
}
Note that this has one difference to the code you have above: it doesn't remove any elements currently in #content. If that will happen, you will have to do the removal separately.
You could use document.createElement instead of innerHTML.
// Create the element
var element = document.createElement('img');
element.setAttribute('border', 0);
element.setAttribute('name', 'sam1');
element.setAttribute('src', 'sample.gif');
// Attach onLoad handler to it (passing it the object)
element.onload = function() { ImageOnLoad(coord) };
// Replace the contents of your... div?
var content = document.getElementById("content")
content.innerHTML = '';
content.appendChild(element);
The way you are implementing it now, yes--you're creating HTML as a string, and embedding JavaScript within that string; your options are limited.
And geez, use single-quotes around the html var so you don't have to escape everything :(

jQuery: how to change tag name?

jQuery: how to change tag name?
For example:
<tr>
$1
</tr>
I need
<div>
$1
</div>
Yes, I can
Create DOM element <div>
Copy tr content to div
Remove tr from dom
But can I make it directly?
PS:
$(tr).get(0).tagName = "div";
results in DOMException.
You can replace any HTML markup by using jQuery's .replaceWith() method.
example: http://jsfiddle.net/JHmaV/
Ref.: .replaceWith
If you want to keep the existing markup, you could use code like this:
$('#target').replaceWith('<newTag>' + $('#target').html() +'</newTag>')
No, it is not possible according to W3C specification: "tagName of type DOMString, readonly"
http://www.w3.org/TR/DOM-Level-2-Core/core.html
Where the DOM renameNode() Method?
Today (2014) no browser understand the new DOM3 renameNode method (see also W3C)
check if run at your bowser: http://jsfiddle.net/k2jSm/1/
So, a DOM solution is ugly and I not understand why (??) jQuery not implemented a workaround?
pure DOM algorithm
createElement(new_name)
copy all content to new element;
replace old to new by replaceChild()
is something like this,
function rename_element(node,name) {
var renamed = document.createElement(name);
foreach (node.attributes as a) {
renamed.setAttribute(a.nodeName, a.nodeValue);
}
while (node.firstChild) {
renamed.appendChild(node.firstChild);
}
return node.parentNode.replaceChild(renamed, node);
}
... wait review and jsfiddle ...
jQuery algorithm
The #ilpoldo algorithm is a good start point,
$from.replaceWith($('<'+newname+'/>').html($from.html()));
As others commented, it need a attribute copy ... wait generic ...
specific for class, preserving the attribute, see http://jsfiddle.net/cDgpS/
See also https://stackoverflow.com/a/9468280/287948
The above solutions wipe out the existing element and re-create it from scratch, destroying any event bindings on children in the process.
short answer: (loses <p/>'s attributes)
$("p").wrapInner("<div/>").children(0).unwrap();
longer answer: (copies <p/>'s attributes)
$("p").each(function (o, elt) {
var newElt = $("<div class='p'/>");
Array.prototype.slice.call(elt.attributes).forEach(function(a) {
newElt.attr(a.name, a.value);
});
$(elt).wrapInner(newElt).children(0).unwrap();
});
fiddle with nested bindings
It would be cool to copy any bindings from the at the same time, but getting current bindings didn't work for me.
To preserve the internal content of the tag you can use the accessor .html() in conjunction with .replaceWith()
forked example: http://jsfiddle.net/WVb2Q/1/
Inspired by ericP answer, formatted and converted to jQuery plugin:
$.fn.replaceWithTag = function(tagName) {
var result = [];
this.each(function() {
var newElem = $('<' + tagName + '>').get(0);
for (var i = 0; i < this.attributes.length; i++) {
newElem.setAttribute(
this.attributes[i].name, this.attributes[i].value
);
}
newElem = $(this).wrapInner(newElem).children(0).unwrap().get(0);
result.push(newElem);
});
return $(result);
};
Usage:
$('div').replaceWithTag('span')
Working pure DOM algorithm
function rename_element(node, name) {
let renamed = document.createElement(name);
Array.from(node.attributes).forEach(attr => {
renamed.setAttribute(attr.name, attr.value);
})
while (node.firstChild) {
renamed.appendChild(node.firstChild);
}
node.parentNode.replaceChild(renamed, node);
return renamed;
}
You could go a little basic. Works for me.
var oNode = document.getElementsByTagName('tr')[0];
var inHTML = oNode.innerHTML;
oNode.innerHTML = '';
var outHTML = oNode.outerHTML;
outHTML = outHTML.replace(/tr/g, 'div');
oNode.outerHTML = outHTML;
oNode.innerHTML = inHTML;
To replace the internal contents of multiple tags, each with their own original content, you have to use .replaceWith() and .html() differently:
http://jsfiddle.net/kcrca/VYxxG/
JS to change the tag name
/**
* This function replaces the DOM elements's tag name with you desire
* Example:
* replaceElem('header','ram');
* replaceElem('div.header-one','ram');
*/
function replaceElem(targetId, replaceWith){
$(targetId).each(function(){
var attributes = concatHashToString(this.attributes);
var replacingStartTag = '<' + replaceWith + attributes +'>';
var replacingEndTag = '</' + replaceWith + '>';
$(this).replaceWith(replacingStartTag + $(this).html() + replacingEndTag);
});
}
replaceElem('div','span');
/**
* This function concats the attributes of old elements
*/
function concatHashToString(hash){
var emptyStr = '';
$.each(hash, function(index){
emptyStr += ' ' + hash[index].name + '="' + hash[index].value + '"';
});
return emptyStr;
}
Related fiddle is in this link
Since replaceWith() didn't work for me on an element basis (maybe because I used it inside map()), I did it by creating a new element and copying the attributes as needed.
$items = $('select option').map(function(){
var
$source = $(this),
$copy = $('<li></li>'),
title = $source.text().replace( /this/, 'that' );
$copy
.data( 'additional_info' , $source.val() )
.text(title);
return $copy;
});
$('ul').append($items);
Take him by the word
Taken the Question by Word "how to change tag name?" I would suggest this solution:
If it makes sense or not has to be decided case by case.
My example will "rename" all a-Tags with hyperlinks for SMS with span tags. Maintaining all attributes and content:
$('a[href^="sms:"]').each(function(){
var $t=$(this);
var $new=$($t.wrap('<div>')
.parent()
.html()
.replace(/^\s*<\s*a/g,'<span')
.replace(/a\s*>\s*$/g,'span>')
).attr('href', null);
$t.unwrap().replaceWith($new);
});
As it does not make any sense to have a span tag with an href attribute I remove that too.
Doing it this way is bulletproof and compatible with all browsers that are supported by jquery.
There are other ways people try to copy all the Attributes to the new Element, but those are not compatible with all browsers.
Although I think it is quite expensive to do it this way.
Jquery plugin to make "tagName" editable :
(function($){
var $newTag = null;
$.fn.tagName = function(newTag){
this.each(function(i, el){
var $el = $(el);
$newTag = $("<" + newTag + ">");
// attributes
$.each(el.attributes, function(i, attribute){
$newTag.attr(attribute.nodeName, attribute.nodeValue);
});
// content
$newTag.html($el.html());
$el.replaceWith($newTag);
});
return $newTag;
};
})(jQuery);
See : http://jsfiddle.net/03gcnx9v/3/
Yet another script to change the node name
function switchElement() {
$element.each(function (index, oldElement) {
let $newElement = $('<' + nodeName + '/>');
_.each($element[0].attributes, function(attribute) {
$newElement.attr(attribute.name, attribute.value);
});
$element.wrapInner($newElement).children().first().unwrap();
});
}
http://jsfiddle.net/rc296owo/5/
It will copy over the attributes and inner html into a new element and then replace the old one.
$(function(){
$('#switch').bind('click', function(){
$('p').each(function(){
$(this).replaceWith($('<div/>').html($(this).html()));
});
});
});
p {
background-color: red;
}
div {
background-color: yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Hello</p>
<p>Hello2</p>
<p>Hello3</p>
<button id="switch">replace</button>
You can use this function
var renameTag = function renameTag($obj, new_tag) {
var obj = $obj.get(0);
var tag = obj.tagName.toLowerCase();
var tag_start = new RegExp('^<' + tag);
var tag_end = new RegExp('<\\/' + tag + '>$');
var new_html = obj.outerHTML.replace(tag_start, "<" + new_tag).replace(tag_end, '</' + new_tag + '>');
$obj.replaceWith(new_html);
};
ES6
const renameTag = function ($obj, new_tag) {
let obj = $obj.get(0);
let tag = obj.tagName.toLowerCase();
let tag_start = new RegExp('^<' + tag);
let tag_end = new RegExp('<\\/' + tag + '>$');
let new_html = obj.outerHTML.replace(tag_start, "<" + new_tag).replace(tag_end, '</' + new_tag + '>');
$obj.replaceWith(new_html);
};
Sample code
renameTag($(tr),'div');
Try this one also. in this example we can also have attributes of the old tag in new tag
var newName = document.querySelector('.test').outerHTML.replaceAll('h1', 'h2');
document.querySelector('.test').outerHTML = newName;
<h1 class="test">Replace H1 to H2</h1>

Categories