Is there an easy way to clear an SVG element's contents? - javascript

In HTML, I can clear a <div> element with this command:
div.innerHTML = "";
Is there an equivalent if I have an <svg> element? I can't find an innerHTML nor innerXML or even innerSVG method.
I know the SVG DOM is a superset of the XML DOM, so I know I can do something like this:
while (svg.lastChild) {
svg.removeChild(svg.lastChild);
}
But this is both tedious and slow. Is there a faster or easier way to clear an SVG element?

If you're using jQuery, you can just do
$("#svgid").empty();
This deletes all child elements of the svg while leaving its other attributes like width and height intact.

You already gave one answer: you can always just loop over all children and remove them. If you think that you have too many child nodes then maybe you want to replace the svg node by an empty one. If your svg node has some attributes you may use a tag where you place all the child nodes and then just replace the node with an empty one.

Use d3.js. This will remove all contents nodes from svg.
svg.selectAll("*").remove();

I agree to use the clone and replace the element with the cloned one.
Only one line code:
svg.parentNode.replaceChild(svg.cloneNode(false), svg);

I've tried svg.text("") and it seems to work. Clears out all the inner text, keeps the attributes.

No need to loop, just assign an empty string
svg.innerHTML = "";

If you want to keep defs of your svg as me use this
function clear(prnt){
let children = prnt.children;
for (let i=0;i<children.length;){
let el = children[i];
if (el.tagName!=='defs'){
el.remove();
}else(i++);
}
}

You can use the clone and replace the element with the cloned one.
var parentElement = svg.parentElement
var emptySvg = svg.cloneNode(false);
parentElement.removeChild(svg);
parentElement.appendChild(emptySvg);
This will append the svg at the end,
you might want to get the element before and append accordinaly

use this? http://keith-wood.name/svg.html
there's also raphael: jQuery SVG vs. Raphael
I'd be tempted to trawl through and see who they're doing their .destroy() methods.

element = document.getElementById("elementID");
element.parentNode.removeChild(element);
I got the idea from http://www.carto.net/svg/manipulating_svg_with_dom_ecmascript/

Related

Using svg.js, how can I access the child nodes of an element?

I am accessing an existing DOM SVG element in my HTML using
svgEle = SVG.adopt(svgDocument.getElementById('svg'));
How can I access child elements of svgEle without adopting them individually?
I have tried
elementById = svgEle.select("#" + id);
and
elementById = svgEle.get(id);
In SVG.js 3.0+ the API changed and you should use .find() or .findOne() methods instead of .select().
See reference here: https://svgjs.dev/docs/3.0/referencing-creating-elements/#using-css-selectors
You use select(<CSS Selector>).
svgEle = SVG.adopt(document.getElementById('svg'))
svgEle.select("#keys")
.stroke('yellow')
SVG.get(<ID>) only works for SVG elements created by SVG.js.
Here is jsfiddle to illustrate: https://jsfiddle.net/dotnetCarpenter/yy2opz8s/2/

<br> not being appended to div

ogres = document.getElementById('${contentID}')
.
let prettify = streamArray[streamArray.length - 1].split(/--/),
layers = document.createTextNode(prettify[0]),
onions = document.createTextNode(prettify[1]),
breaking = document.createElement('br');
I have an array of two elements that I've created called prettify.
I have definitely confirmed that the prettify[0] and prettify[1] are the elements I want so I make them into onions and layers which are text nodes to be appended to the div.
You'll note I also have breaking which is a break element I create and also append to the div.
I then have the div, orges.
Now for some unknown reason when I do this:
ogres.appendChild(layers);
ogres.appendChild(breaking);
ogres.appendChild(onions);
ogres.appendChild(breaking);
on the html page, this is created:
layersonions
<br>
1: why is this happening
2: how do I fix it?
3: no I don't plan on keeping these variable names, but they are fun :3
When you use document.createElement('br'); to create an element, it is appended as the second node of the parent.
Since you are using the same reference again, it simply detaches the existing element and appends it again in the new position.
It is a single reference to the element. To fix it you will have to create and append an element on the fly.
ogres.appendChild(layers);
ogres.appendChild(document.createElement('br'));
ogres.appendChild(onions);
ogres.appendChild(document.createElement('br'));
appendChild
If you still want to use the variable reference then you could use the cloneNode method which will clone the existing node before insertion.
ogres.appendChild(layers);
ogres.appendChild(breaking);
ogres.appendChild(onions);
ogres.appendChild(breaking.cloneNode(false));
cloneNode

How to write to a <div> element using JavaScript?

I've searched around using Google and Stack Overflow, but I haven't seemed to find a answer to this. I want to write text inside a <div> element, using JavaScript, and later clear the <div> element, and write more text into it. I am making a simple text adventure game.
This is what I am trying to do:
<DOCTYPE!HTML>
<body>
<div class="gamebox">
<!-- I want to write in this div element -->
</div>
</body>
As a new user to JavaScript, how would I be able to write inside the div element gamebox? Unfortunately, my JavaScript skills are not very good, and it would be nice if you can patiently explain what happens in the code.
You can use querySelector to get a reference to the first element matching any CSS selector. In your case, a class selector:
var div = document.querySelector(".gamebox");
querySelector works on all modern browsers, including IE8. It returns null if it didn't find any matching element. You can also get a list of all matching elements using querySelectorAll:
var list = document.querySelectorAll(".gamebox");
Then you access the elements in that list using 0-based indexes (list[0], list[1], etc.); the length of the list is available from list.length.
Then you can either assign HTML strings to innerHTML:
div.innerHTML = "This is the text, <strong>markup</strong> works too.";
...or you can use createElement or createTextNode and appendChild / insertBefore:
var child = document.createTextNode("I'm text for the div");
div.appendChild(span); // Put the text node in the div
Those functions are found in the DOM. A lot of them are now covered in the HTML5 specification as well (particularly Section 3).
Select a single element with document.querySelector or a collection with document.querySelectorAll.
And then it depends, on what you want to do:
Writing Text into the div or create an Element and append it to the div.
Like mentioned getElementsByClassName is faster. Important to know it when you use this you get returned an array with elements to reach the elment you want you specify its index line [0], [1]
var gameBox = document.getElementsByClassName('gamebox')[0];
Here how you can do it
//returns array with elements
var gameBox = document.getElementsByClassName('gamebox');
//inner HTML (overwrites fsd) this can be used if you direcly want to write in the div
gameBox[0].innerHTML ='<p>the new test</p>';
//Appending when you want to add extra content
//create new element <p>
var newP = document.createElement('p');
//create a new TextNode
var newText = document.createTextNode("i'm a new text");
//append textNode to the new element
newP.appendChild(newText);
//append to the DOM
gameBox[0].appendChild(newP);
https://developer.mozilla.org/en-US/docs/Web/API/document.createElement
https://developer.mozilla.org/en-US/docs/Web/API/document.getElementsByClassName

Remove an element from the DOM based on a variable reference to it?

I'm dynamically creating a div like this:
var gameScoreDiv= document.createElement('div');
gameScoreDiv.innerHTML= 'Score: 0';
wrapperDiv.appendChild(gameScoreDiv);
Later I need to remove this div from DOM. How can I get rid of that div?
Is it possible to simply delete the gameScoreDiv variable and have it remove also the DOM element (I have a feeling the answer is no)?
2019 update
You can remove node with ChildNode.remove() now:
gameScoreDiv.remove()
It's supported by every major browser with the not surprising exception of IE (for which you can add a tiny polyfill though, if needed).
You can do:
gameScoreDiv.parentNode.removeChild(gameScoreDiv);
or, if you still have reference to the wrapperDiv:
wrapperDiv.removeChild(gameScoreDiv);
In jQuery it would be:
$(gameScoreDiv).remove();
but this will use the parentNode way, see the source.
You're looking for the removeChild method.
In your case I see that wrapperDiv is the parent element, so simply call it on that:
wrapperDiv.removeChild(gameScoreDiv);
Alternatively, in another scope where that isn't available, use parentNode to find the parent:
gameScoreDiv.parentNode.removeChild(gameScoreDiv);
you can give your dynamically created div an id, and later you can see if any element with this id exists, delete it. i.e.
var gameScoreDiv= document.createElement('div');
gameScoreDiv.setAttribute("id","divGameScore");
gameScoreDiv.innerHTML= 'Score: 0';
wrapperDiv.appendChild(gameScoreDiv);
and later:
var gameScoreDiv= document.getElementById('divGameScore');
wrapperDiv.removeChild(gameScoreDiv);
You can try this:
gameScoreDiv.id = "someID";
//Remove the div like this:
var element = document.getElementById('someID');
element.parentNode.removeChild(element);

How to remove only the parent element and not its child elements in JavaScript?

Let's say:
<div>
pre text
<div class="remove-just-this">
<p>child foo</p>
<p>child bar</p>
nested text
</div>
post text
</div>
to this:
<div>
pre text
<p>child foo</p>
<p>child bar</p>
nested text
post text
</div>
I've been figuring out using Mootools, jQuery and even (raw) JavaScript, but couldn't get the idea how to do this.
Using jQuery you can do this:
var cnt = $(".remove-just-this").contents();
$(".remove-just-this").replaceWith(cnt);
Quick links to the documentation:
contents( ) : jQuery
replaceWith( content : [String | Element | jQuery] ) : jQuery
The library-independent method is to insert all child nodes of the element to be removed before itself (which implicitly removes them from their old position), before you remove it:
while (nodeToBeRemoved.firstChild)
{
nodeToBeRemoved.parentNode.insertBefore(nodeToBeRemoved.firstChild,
nodeToBeRemoved);
}
nodeToBeRemoved.parentNode.removeChild(nodeToBeRemoved);
This will move all child nodes to the correct place in the right order.
You should make sure to do this with the DOM, not innerHTML (and if using the jQuery solution provided by jk, make sure that it moves the DOM nodes rather than using innerHTML internally), in order to preserve things like event handlers.
My answer is a lot like insin's, but will perform better for large structures (appending each node separately can be taxing on redraws where CSS has to be reapplied for each appendChild; with a DocumentFragment, this only occurs once as it is not made visible until after its children are all appended and it is added to the document).
var fragment = document.createDocumentFragment();
while(element.firstChild) {
fragment.appendChild(element.firstChild);
}
element.parentNode.replaceChild(fragment, element);
$('.remove-just-this > *').unwrap()
More elegant way is
$('.remove-just-this').contents().unwrap();
Use modern JS!
const node = document.getElementsByClassName('.remove-just-this')[0];
node.replaceWith(...node.childNodes); // or node.children, if you don't want textNodes
oldNode.replaceWith(newNode) is valid ES5
...array is the spread operator, passing each array element as a parameter
Replace div with its contents:
const wrapper = document.querySelector('.remove-just-this');
wrapper.outerHTML = wrapper.innerHTML;
<div>
pre text
<div class="remove-just-this">
<p>child foo</p>
<p>child bar</p>
nested text
</div>
post text
</div>
Whichever library you are using you have to clone the inner div before removing the outer div from the DOM. Then you have to add the cloned inner div to the place in the DOM where the outer div was. So the steps are:
Save a reference to the outer div's parent in a variable
Copy the inner div to another variable. This can be done in a quick and dirty way by saving the innerHTML of the inner div to a variable or you can copy the inner tree recursively node by node.
Call removeChild on the outer div's parent with the outer div as the argument.
Insert the copied inner content to the outer div's parent in the correct position.
Some libraries will do some or all of this for you but something like the above will be going on under the hood.
And, since you tried in mootools as well, here's the solution in mootools.
var children = $('remove-just-this').getChildren();
children.replaces($('remove-just-this');
Note that's totally untested, but I have worked with mootools before and it should work.
http://mootools.net/docs/Element/Element#Element:getChildren
http://mootools.net/docs/Element/Element#Element:replaces
I was looking for the best answer performance-wise while working on an important DOM.
eyelidlessness's answer was pointing out that using javascript the performances would be best.
I've made the following execution time tests on 5,000 lines and 400,000 characters with a complexe DOM composition inside the section to remove. I'm using an ID instead of a class for convenient reason when using javascript.
Using $.unwrap()
$('#remove-just-this').contents().unwrap();
201.237ms
Using $.replaceWith()
var cnt = $("#remove-just-this").contents();
$("#remove-just-this").replaceWith(cnt);
156.983ms
Using DocumentFragment in javascript
var element = document.getElementById('remove-just-this');
var fragment = document.createDocumentFragment();
while(element.firstChild) {
fragment.appendChild(element.firstChild);
}
element.parentNode.replaceChild(fragment, element);
147.211ms
Conclusion
Performance-wise, even on a relatively big DOM structure, the difference between using jQuery and javascript is not huge. Surprisingly $.unwrap() is most costly than $.replaceWith().
The tests have been done with jQuery 1.12.4.
if you'd like to do this same thing in pyjamas, here's how it's done. it works great (thank you to eyelidness). i've been able to make a proper rich text editor which properly does styles without messing up, thanks to this.
def remove_node(doc, element):
""" removes a specific node, adding its children in its place
"""
fragment = doc.createDocumentFragment()
while element.firstChild:
fragment.appendChild(element.firstChild)
parent = element.parentNode
parent.insertBefore(fragment, element)
parent.removeChild(element)
If you are dealing with multiple rows, as it was in my use case you are probably better off with something along these lines:
$(".card_row").each(function(){
var cnt = $(this).contents();
$(this).replaceWith(cnt);
});
The solution with replaceWith only works when there is one matching element.
When there are more matching elements use this:
$(".remove-just-this").contents().unwrap();

Categories

Resources