Query slotElement.assignedNodes() results - javascript

I want to query elements inside of my shadow dom slot element. Do I need to loop through what assignedNodes() returns and parse them myself?

I solved this issue by having the child element loop through the element's parent nodes until it finds the tag I am looking for.
var el = this; //the child element
while (el.parentNode) {
el = el.parentNode;
if (el.tagName == 'TAG-NAME'){ // The parent's tag name you're searching for.
this.parentElement = el;
break;
}
}
I also tried this with this.closest(), but Firefox had issues with that jumping between shadow dom.

Related

Javascript remove item from DOM before rendering code

I'm trying to remove an element from my HTML document, which I'm able to do with the remove method, however, when console logging the NodeList with document.querySelectorAll() on some classes on elements that should've been removed, they're still showing up in the NodeList.
I need to remove an element from the webpage, but also from the NodeList, as if the element wasn't there initially on page load to prevent the rest of my application from thinking that it's there.
I would've thought that the remove method would've covered this, but unfortunately it doesn't, what am I missing and what's the workaround?
function removeElement (ident) {
const elem = document.querySelector(ident)
if (elem) {
elem.remove()
}
}
you have to get elements by their id name.
var elem = document.getElementById('myid');
elem.remove()
here 'myid' is the id of the item to be deleted.
if you want to delete it using query selector then take the help of elem's parent element.
let elem = document.querySelector(ident);
elem.parentElement.removeChild(elem);

Removing and creating HTML elements with same id using Javascript

I have a button that, when pressed, executes something like
function click(){
element = document.getElementById("element");
element.parentNode.removeChild(element);
var newelement = document.createElement("div");
body.appendChild(newelement);
newelement.id = "element";
}
I have also tried using element.outerHTML = "" instead of removeChild with no success. Before adding the bit about deleting the previous element with the id "element" things worked fine on the first click and an div named "element" was appended to the body. (Of course, on the second click, another element named "element" is appended, and I want to keep the id unique to one element.) Now, with the bit about removing previous elements, my button.onClick doesn't even do anything.
Another important piece of context: I'm trying to do this for elements that are generated using user input, so there's no guarantee on how many of these things are made--I just want them deleted when the user wants to generate more of them.
On the first click, I'm attempting to remove an empty element. Does that break something?
body does not exist in the scope you've provided and would throw an exception. I would try:
var body = document.querySelector("body");
See this for a example using your code:
https://jsfiddle.net/k0wL4y7p/2/
Also make sure you use var on all local variables so they are not declared globally. See below to learn about variable scope:
When to use var in Javascript
How about this... don't remove the Parent Element (Div1); instead to remove the children. Then, create the child and append it to the parent element.
Note: you must iterate over it to remove all child nodes & for p element id p1/p2 generate dynamic id or use class if you need it.
Your JS:
$(document).ready(function() {
$("#btn1").click(function() {
var element = document.getElementById("div1");
while (element.firstChild) {
element.removeChild(element.firstChild);
}
var para = document.createElement("p");
var node = document.createTextNode("New element after click.");
para.appendChild(node);
var element = document.getElementById("div1");
element.appendChild(para);
});
});
I prefer JQuery - no loop
$(document).ready(function(){
$("#btn1").click(function(){
$("#div1").empty();
$("#div1").append(" <p>Appended element after click</p>");
});
});
Your Html
<body>
<div id="div1">
<p id="p1">Paragraph element before click.</p>
<p id="p2">Another paragraph beofre click.</p>
</div>
<button id="btn1">Remove </button>
</body>
Hope it helps.

what's the difference between document.createElement and createDocumentFragment? [duplicate]

I was reading about document fragments and DOM reflow and wondered how document.createDocumentFragment differed from document.createElement as it looks like neither of them exist in the DOM until I append them to a DOM element.
I did a test (below) and all of them took exactly the same amount of time (about 95ms). At a guess this could possibly be due to there being no style applied to any of the elements, so no reflow maybe.
Anyway, based on the example below, why should I use createDocumentFragment instead of createElement when inserting into the DOM and whats the differnce between the two.
var htmz = "<ul>";
for (var i = 0; i < 2001; i++) {
htmz += '<li>link ' + i + '</li>';
}
htmz += '<ul>';
//createDocumentFragment
console.time('first');
var div = document.createElement("div");
div.innerHTML = htmz;
var fragment = document.createDocumentFragment();
while (div.firstChild) {
fragment.appendChild(div.firstChild);
}
$('#first').append(fragment);
console.timeEnd('first');
//createElement
console.time('second');
var span = document.createElement("span");
span.innerHTML = htmz;
$('#second').append(span);
console.timeEnd('second');
//jQuery
console.time('third');
$('#third').append(htmz);
console.timeEnd('third');
The difference is that a document fragment effectively disappears when you add it to the DOM. What happens is that all the child nodes of the document fragment are inserted at the location in the DOM where you insert the document fragment and the document fragment itself is not inserted. The fragment itself continues to exist but now has no children.
This allows you to insert multiple nodes into the DOM at the same time:
var frag = document.createDocumentFragment();
var textNode = frag.appendChild(document.createTextNode("Some text"));
var br = frag.appendChild(document.createElement("br"));
var body = document.body;
body.appendChild(frag);
alert(body.lastChild.tagName); // "BR"
alert(body.lastChild.previousSibling.data); // "Some text"
alert(frag.hasChildNodes()); // false
Another very important difference between creating an element and a document fragment:
When you create an element and append it to the DOM, the element is appended to the DOM, as well as the children.
With a document fragment, only the children are appended.
Take the case of:
var ul = document.getElementById("ul_test");
// First. add a document fragment:
(function() {
var frag = document.createDocumentFragment();
var li = document.createElement("li");
li.appendChild(document.createTextNode("Document Fragment"));
frag.appendChild(li);
ul.appendChild(frag);
console.log(2);
}());
(function() {
var div = document.createElement("div");
var li = document.createElement("li");
li.appendChild(document.createTextNode("Inside Div"));
div.appendChild(li);
ul.appendChild(div);
}());
Sample List:
<ul id="ul_test"></ul>
which results in this malformed HTML (whitespace added)
<ul id="ul_test">
<li>Document Fragment</li>
<div><li>Inside Div</li></div>
</ul>
You can think of a DocumentFragment as a virtual DOM. It's not connected to the DOM and unlike elements, it has no parent, EVER. You can then interact with the fragment as if it's a virtual document object. It's all in memory.
It's really helpful to use fragments when you have many DOM manipulations to make or style changes, because those will trigger reflows and repaints - expensive operations on the DOM that can slow the page load down.
The bonus you get with fragment is that it triggers only one reflow when the fragment is inserted into the DOM, no matter how many children it contains.
DocumentFragment is not an element or a Node. It's a stripped down Document object with a reduced set of properties and methods.
If you've ever heard of the virtual DOM with React, they are making heavy use of DocumentFragments in the ReactDOM library. That's why it's so performant.

Insert a div element as parent

I'm just wondering if the following is possible, lets say we have a dom element and we want to wrap this element in a div. So a div is inserted between the element and it's parent. Then the div becomes the element's new parent.
But to complicate things, elsewhere we have already done things like:
var testElement = document.getElementByID('testID')
where testID is a child of the element to be warapped in a div. So after we have done our insertion will testElement still be valid?
BTW: I'm not using jquery.
Any ideas?
Thanks,
AJ
You can use replaceChild [docs]:
// `element` is the element you want to wrap
var parent = element.parentNode;
var wrapper = document.createElement('div');
// set the wrapper as child (instead of the element)
parent.replaceChild(wrapper, element);
// set element as child of wrapper
wrapper.appendChild(element);
As long as you are not using innerHTML (which destroys and creates elements), references to existing DOM elements are not changed.
Assuming you are doing your manipulation using standard DOM methods (and not innerHTML) then — yes.
Moving elements about does not break direct references to them.
(If you were using innerHTML, then you would be destroying the contents of the element you were setting that property on and then creating new content)
You probably want something like:
var oldParent = document.getElementById('foo');
var oldChild = document.getElementById('bar');
var wrapper = document.createElement('div');
oldParent.appendChild(wrapper);
wrapper.appendChild(oldChild);
In pure JS you can try something like this...
var wrapper = document.createElement('div');
var myDiv = document.getElementById('myDiv');
wrapper.appendChild(myDiv.cloneNode(true));
myDiv.parentNode.replaceChild(wrapper, myDiv);
Here is another example, only the new element wraps around 'all' of its child elements.
You can change this as necessary to have it wrap at different ranges. There isn't a lot of commentary on this specific topic, so hopefully it will be of help to everyone!
var newChildNodes = document.body.childNodes;
var newElement = document.createElement('div');
newElement.className = 'green_gradient';
newElement.id = 'content';
for (var i = 0; i < newChildNodes.length;i++) {
newElement.appendChild(newChildNodes.item(i));
newChildNodes.item(0).parentNode.insertBefore(newElement, newChildNodes.item(i));
}
You will want to modify the 'document.body' part of the newChildNodes variable to be whatever the parent of your new element will be. In this example, I chose to insert a wrapper div. You will also want to update the element type, and the id and className values.

How to access HTML element without ID?

For instance in the snippet below - how do I access the h1 element knowing the ID of parent element (header-inner div)?
<div id='header-inner'>
<div class='titlewrapper'>
<h1 class='title'>
Some text I want to change
</h1>
</div>
</div>
Thanks!
function findFirstDescendant(parent, tagname)
{
parent = document.getElementById(parent);
var descendants = parent.getElementsByTagName(tagname);
if ( descendants.length )
return descendants[0];
return null;
}
var header = findFirstDescendant("header-inner", "h1");
Finds the element with the given ID, queries for descendants with a given tag name, returns the first one. You could also loop on descendants to filter by other criteria; if you start heading in that direction, i recommend you check out a pre-built library such as jQuery (will save you a good deal of time writing this stuff, it gets somewhat tricky).
If you were to use jQuery as mentioned by some posters, you can get access to the element very easily like so (though technically this would return a collection of matching elements if there were more than one H1 descendant):
var element = $('#header-inner h1');
Using a library like JQuery makes things like this trivial compared to the normal ways as mentioned in other posts. Then once you have a reference to it in a jQuery object, you have even more functions available to easily manipulate its content and appearance.
If you are sure that there is only one H1 element in your div:
var parent = document.getElementById('header-inner');
var element = parent.GetElementsByTagName('h1')[0];
Going through descendants,as Shog9 showed, is a good way too.
It's been a few years since this question was asked and answered. In modern DOM, you could use querySelector:
document.querySelector('#header-inner h1').textContent = 'Different text';
<div id='header-inner'>
<div class='titlewrapper'>
<h1 class='title'>
Some text I want to change
</h1>
</div>
</div>
The simplest way of doing it with your current markup is:
document.getElementById('header-inner').getElementsByTagName('h1')[0].innerHTML = 'new text';
This assumes your H1 tag is always the first one within the 'header-inner' element.
To get the children nodes, use obj.childNodes, that returns a collection object.
To get the first child, use list[0], that returns a node.
So the complete code should be:
var div = document.getElementById('header-inner');
var divTitleWrapper = div.childNodes[0];
var h1 = divTitleWrapper.childNodes[0];
If you want to iterate over all the children, comparing if they are of class “title”, you can iterate using a for loop and the className attribute.
The code should be:
var h1 = null;
var nodeList = divTitleWrapper.childNodes;
for (i =0;i < nodeList.length;i++){
var node = nodeList[i];
if(node.className == 'title' && node.tagName == 'H1'){
h1 = node;
}
}
Here I get the H1 elements value in a div where the H1 element which has CSS class="myheader":
var nodes = document.getElementById("mydiv")
.getElementsByTagName("H1");
for(i=0;i<nodes.length;i++)
{
if(nodes.item(i).getAttribute("class") == "myheader")
alert(nodes.item(i).innerHTML);
}
Here is the markup:
<div id="mydiv">
<h1 class="myheader">Hello</h1>
</div>
I would also recommend to use jQuery if you need a heavy parsing for your DOM.

Categories

Resources