Reputation: 11122
I have a division that I need to change its outer HTML upon an event. The problem is that upon setting the outerHTML
I am not able to reference the new selected DOM object unless I explicitly catch it again.
Is there a way to directly update the variable reference upon calling outerHTML
(in my case the reference of the div
variable below) ?
$("#changeDiv").click(function(){
var div = $(this).prev();
div[0].outerHTML = `<div id="imSecondtDiv"> <p> World </p> </div>`;
console.log(div); // logs [div#imFirstDiv, prevObject: n.fn.init[1], context: button#changeDiv]
// the following line does not affect the newly added division
// since the var `div` references the old DOM object
// unless I add div = $(this).prev(); before setting the html of
// the paragraph it will not set it
div.find('p').html('Override');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="imFirstDiv"> <p> Hello </p> </div>
<button id="changeDiv" >Change Div 1</button>
Upvotes: 11
Views: 1829
Reputation: 6830
Is there a way to directly update the variable reference upon calling
outerHTML
?
No. According to MDN Web Docs:
While the element will be replaced in the document, the variable whose
outerHTML
property was set will still hold a reference to the original element.
const p = document.querySelector('p');
p.outerHTML = '<p>Goodbye, world!</p>';
console.log(p.textContent);
<p>Hello, world!</p>
As a workaround, however, you can create a live HTMLCollection
from which to get the element both before and after the update:
const Ps = document.getElementsByTagName('p');
Ps[0].outerHTML = '<p>Goodbye, world!</p>';
console.log(Ps[0].textContent);
<p>Hello, world!</p>
Upvotes: 0
Reputation: 331
I have solved this by getting a reference element (sibling or parent) of tag that's going to be replaced.
Here is a function which is not dependent on which element are you going to change:
function replaceElement(ele, outerHTML)
{
var parent = false, refEle;
//if element that's going to be changed has previousElementSibling, take it as reference. If not, the parentElement will be the reference.
if (ele.previousElementSibling !== null)
refEle = ele.previousElementSibling;
else
{
refEle = ele.parentElement;
//indicate that parentElement has been taken as reference
parent = true;
}
//change the outerHTML
ele.outerHTML = outerHTML;
//return the correct reference
if (parent)
return refEle.firstElementChild;
else return refEle.nextElementSibling;
}
So in your case, you would invoke it this way:
div[0] = replaceElement(div[0], '<div id="imSecondtDiv"> <p> World </p> </div>');
I hope it will work with jQuery as well, as I am writing all my scripts only in native javascript.
Upvotes: 4
Reputation: 16609
As you are seeing changing the outerHTML
makes things behave a bit strangely, as you are completely replacing the original element but still referencing the old one.
It would be better to create a new div
, add it after()
the old one then remove()
the old one. This maintains the position of the div
in the correct place.
$("#changeDiv").click(function(){
// get the oldDiv
var oldDiv = $(this).prev();
// Create a newDiv
var newDiv = $('<div id="imSecondtDiv"> <p> World </p> </div>');
// add newDiv after oldDiv one, then remove oldDiv from the DOM.
oldDiv.after(newDiv).remove();
// now you still have the reference to newDiv, so do what you want with it
newDiv.find('p').html('Override');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="imFirstDiv"> <p> Hello </p> </div>
<button id="changeDiv" >Change Div 1</button>
If you really really do need to use outerHTML, you can simply grab $(this).prev()
again:
$("#changeDiv").click(function(){
var div = $(this).prev();
div[0].outerHTML = `<div id="imSecondtDiv"> <p> World </p> </div>`;
// the "new" div is now before the button, so grab the reference of THAt one
div = $(this).prev();
// the following line does not affect the newly added division
// since the var `div` references the old DOM object
// unless I add div = $(this).prev(); before setting the html of
// the paragraph it will not set it
div.find('p').html('Override');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="imFirstDiv"> <p> Hello </p> </div>
<button id="changeDiv" >Change Div 1</button>
Upvotes: 2