I've looked around and can't seem to find a solution to directly replacing an element with a HTML string using vanilla JavaScript (not jQuery).
I'm storing a bunch of svg's in a directory that's publicly accessible, and I want to be able to include them in my files via the image tag <img src="path/to/svgs/example.svg">. However, this comes with its drawbacks as they can't be coloured/styled when they're pulled in as an image (to my knowledgE).
I discovered this example jQuery Image to SVG but obviously this uses jQuery's replaceWith function. I'm trying to replicate the functionality but struggling with the aforementioned function. All examples I've found end up creating a parent div element, and appending the new HTML to that newly created element.
TL;DR: Can I directly replace an element (IMG to SVG) using vanilla JavaScript without creating parent nodes?
jQuery is also using JavaScript behind replaceWith method, so if you want to replace one element with another you need to do next steps:
Create new element
Add it after/before an element that needs to be replaced
Then remove original element
e.g
If we have HTML list
<ul>
<li>before</li>
<li id="my-element">My element</li>
<li>after</li>
</ul>
and we want to replace list item, with id "my-element", with the new element then we need to do next:
//get reference to element that we want to replace
var elementToReplace = document.getElementById('my-element');
//create new element which will replace existing element
var newLi = document.createElement('li');
//just setting html in it
newLi.innerHTML = 'Just added';
//getting parent element reference and executing method "insertBefore" passing our new element and reference of element that we want to replace
elementToReplace.parentNode.insertBefore(newLi, elementToReplace.nextSibling);
//then we remove original element
elementToReplace.parentNode.removeChild(elementToReplace);
I hope this helps.
Assuming you have already loaded the SVG into a string (via XmlHttpRequest, fetch etc). Then you can parse it using the DOMParser.
var parser = new DOMParser();
var doc = parser.parseFromString(stringContainingSVGSource, "image/svg+xml");
See: Parse SVG and add it to a svg element
Then you can replace the original <img> using something like the insertBefore/removeChild method that Senad suggests.
Related
(Sorry for the bad title, I can't think of a better one)
I recently learned that you can do something like this in jquery:
$("<div><span>content</span></div>").css("color", "red").appendTo("body");
My question is about the following:
$("<div><span>content</span></div>")
How does jquery turn this from a string into dom elements, and how could you do the same thing in vanilla js (no jquery)?
I have attempted to look through the jquery source code, but I don't really understand it.
Any explanation is greatly appreciated!
the equivalent in pure javascript would be
var newDiv = document.createElement("DIV");
newDiv.style.color = "red";
var newSpan = document.createElement("SPAN");
newSpan.innerHTML = "content";
newDiv.appendChild(newSpan);
document.body.appendChild(newDiv);
jquery shortcuts this by defining functions that are chainable meaning the next function uses the previous functions return value as its input so in your example it is adding the css to your html code and then adding all of that code to the body
jQuery is creating a new instance of a jQuery object that contains a reference to the DOM elements created by parsing <div><span>content</span></div>.
One really useful thing jQuery does is that every invocation of jQuery or any of its API methods returns either the newly created jQuery instance or the current jQuery instance. The benefit of this is that you can chain your calls to transform a set of DOM elements.
In this case, $(...) returns a jQuery instance containing the DOM elements you want to operate on. Next, you chained css() which adds style properties to that element. Finally, you chain appendTo() which adds that to a target DOM element. In this case, that target is the <body> element.
Here's how this process would look (roughly) in JavaScript:
First, we need to create the DOM elements we wish to insert.
var node = document.createElement("div");
node.innerHTML = "<div><span>content</span></div>";
var myElement = node.children[0];
Then we'll set the style properties.
myElement.style.color = "red";
Finally, lets append it to an existing element.
document.body.appendChild(myElement);
The creation of the DOM elements from a string happens through the magic of the innerHTML property. When the JavaScript parser encounters a string being set to an elements innerHTML, it will parse that string into DOM elements and insert those elements as children.
Therefore, what jQuery is doing under the hood is creating a dummy element, setting the string you provided as a value on the dummy elements innerHTML property. This causes the DOM elements to be created and inserted as the dummy elements children. Lastly, it retrieves the reference to the children element (the elements you want).
This line creates an jQuery wrapped object from an html string, essentially creating a div with a span inside it whose text is the word content:
$("<div><span>content</span></div>")
This applies a CSS property to the created element telling it to display the text in red:
.css("color", "red")
This adds the created and styled element to the DOM at the end of the body tag:
.appendTo("body");
Can someone explain why this doesn't change the audio file src attribute, I would think it would?
var correctAudio = document.createElement('audio');
correctAudio.setAttribute('id', 'correctAudio');
correctAudio.setAttribute('src', 'sfx/correct/3.mp3');
function playCorrect(){
var num = Math.floor((Math.random()*4)+1);
num = num.toString();
$('#correctAudio').attr('src','sfx/correct/'+num+'.mp3');
correctAudio.play();
}
playCorrect();
It only works if I call document.body.appendChild(correctAudio);
Seems as if jQuery can only access the element if it is appended to the page - is this correct or is this a jQuery bug?
It is correct behaviour. jQuery searches the document for a matching element, the element is not part of the document.
You can just wrap the existing reference to the DOM object using jQuery (rather then searching the document for a new reference to wrap):
$(correctAudio)
… but you might find you still can't play it when it isn't part of the document.
I've always wondered how this jQuery feature works: $('<span>Hello world</span>')[0]
That is supposed to return a reference to the newly created span element. How can I achieve the same result using the native DOM methods? insertAdjacentHTML? innerHTML? documentFragment?
I need to insert a HTML fragment and hold a reference to the outer element without the need of using createElement/appendChild.
Thanks.
It's possible to create an element, set its innerHTML, and return the first child. The container element is never added to the DOM:
var el = document.createElement('div');
el.innerHTML = '<span>Hello world</span>';
console.log(el.firstChild);
If that's wrapped in a function, I believe the original container will be eligible for garbage collection as soon as the child is appended somewhere else.
jQuery seems to be doing something more sophisticated, checking if the string contains a single tag or not, and creating a fragment for more complicated strings. See the parseHTML method on jQuery's source code.
I have a scenario where I have to remove the numbers from the name of the xml tag. For example, if there is a tag <xxx1>1234</xxx1>, I need an output as <xxx>1234</xxx>. I surfed through the net and was not able to find a solution. Please help.
You could take a dom elements children and append to a new dom element in its place rather than changing the element details itself.
Pseudo code:
curElementContent = get element from dom and get its contents
newElement = create new dom element
append curElementContent to newElement
remove curElement from dom and insert newElement.
You could give this a try:
tags.replace(/<xxxx\d>/gi, '<xxxx>').replace(/<\/xxxx\d>/gi,'</xxxx>');
Where tags contains the string you need to update.
Got it working by converting the xml into an xml string and using the below regex.
xmlString = xmlString.replace(/\d+>/g, '>');
I'm trying to make a simple image browser for TinyMCE which I am using in my CMS. As part of this I need to detect whether the user has selected an existing image, so I can display the "edit" form instead of the "choose an image form".
var selected_html = ed.selection.getContent();
var $elem = $(selected_html);
console.log($elem);
The first function returns the user selected text from the editor window as a string of HTML. I then would like to use jQuery (although plain javascript is just ok too) to check if this string contains an img tag before subsequently grabbing the src and title attributes for editing.
Now I've got as far as getting the html to turn into an object. But after this I can't manage to search it for the img element. After reading this (How to manipulate HTML within a jQuery variable?) I tried:
$elem.find('img');
But it just comes out as an "undefined" object...
I think I'm missing something fairly obvious here (it is getting late), but after an hour I still can't figure out how to grab the img tag from the selection. :(
Many thanks in advance.
Because the <img> is at the root of the jQuery object, you need to use .filter() instead of .find().
$elem.filter('img');
The .filter() method looks at the element(s) at the top level of the jQuery object, while .find() looks for elements nested in any of the top level elements.
If you're not sure beforehand where the target element will be, you could place the HTML into a wrapper <div> to search from. That way the HTML given will never be at the top.
var selected_html = ed.selection.getContent();
var $elem = $('<div>').html(selected_html);
var $img = $elem.find('img');
Try to see what is really inside your $elem variable. Just do a console.log($elem) using both Firefox and Firebug and you should be able to manage quite alright! ;)