.firstElementChild, .lastElementChild... what about those in between? - javascript

I'm trying to update an existing markup element in React rather than replacing an entire fragment. When I assign a div container element to a variable with .getElement(); I can select the first element within the div with firstElementChild. Then I can find its ".style.color" for example.
Now there's a popover that's the before-last element that I also want to get to it (and its backgroundColor). Not the lastElementChild, the one before that. How do I "get to it"? Is there an array of children I can use?

Not the lastElementChild, the one before that. How do I "get to it"?
You can go from the lastElementChild to its previousSibling
Is there an array of children I can use?
There is a live HTMLCollection (which is array-like) called children

DOM_Selector_Image
As can be shown in the attached image. Which presents a basic website with the "HTML Tree Generator" Add on.
typing the following in the chrome console:-
document.firstElementChild.lastElementChild.lastElementChild.previousElementSibling;
Will give you the following results:
<p>​ The DOM ​</p>​
This is because
firstElementChild
This is the HTML document
lastElementChild
This is the Body
lastElementChild
This is the SCRIPT
previousElementSibling
This is the element before the SCRIPT which is the text "The DOM"

Related

JQuery working wierdly for function 'find':

I have the following jQuery line:
$('<html>hi</html>').find('a')
I expect the result to be a wrapped set of one element. However the result is an empty array ([]). Why?
-- EDIT --
For some reason the code below works.
$('<html><div>hi</div></html>').find('a');
Why is this happening?
That's because the html element is stripped when the string is parsed:
> $('<html>hi</html>')
[​hi​​]
i.e. the current collection contains an element that you are trying to find(). As the top-level a element doesn't (and can't) have a descendants the find() call will return an empty collection.
From jQuery documentation:
When passing in complex HTML, some browsers may not generate a DOM that exactly replicates the HTML source provided. As mentioned, jQuery uses the browser's .innerHTML property to parse the passed HTML and insert it into the current document. During this process, some browsers filter out certain elements such as <html>, <title>, or <head> elements. As a result, the elements inserted may not be representative of the original string passed.
edit: The second snippet can find() a element as when the html element is stripped the top-level element of the collection is a div element that does have a descendant.
As in the Documentation of .find() descriped
Get the descendants of each element in the current set of matched elements, filtered by a selector, jQuery object, or element.
$('<html>hi</html>')
will just provide an Object of your a-tag.
Demo
If there are multiple anchor-tags inside your html-string you can filter them, e.g.:
var elem = $('<html>hihi</html>');
var filter = elem.filter(function(){
return $(this).attr('href') === "cnn.com";
});
Demo
Edit
When passing in complex HTML, some browsers may not generate a DOM
that exactly replicates the HTML source provided. As mentioned, jQuery
uses the browser's .innerHTML property to parse the passed HTML and
insert it into the current document. During this process, some
browsers filter out certain elements such as <html>, <title>, or
<head> elements. As a result, the elements inserted may not be
representative of the original string passed.
Source: http://api.jquery.com/jQuery/#jQuery2 down to the Paragraph Creating New Elements
So jQuery uses .innerHTML. According to the docs
Removes all of element's children, parses the content string and
assigns the resulting nodes as children of the element.
So the html-string <html>test</html> gets stripped to <a></a>.
When wrapping a div around the anchor, the anchor stays a descendat of an elemnt and therefore gets found by the .find()-function.
You should read the documentation at Jquery docs about find()
$('html').find('a');
Check this jsfiddle

Why .closest(selector) returns more than one value?

Here is a part of my html. (it is written using ejs)
<div class="objAddDiv">
<tr><td><button class="addObj">Do this action</button></td></tr>
<table><div class="objects"></div></table>
</div>
I have several objAddDiv divs on this page. Each has the same structure inside of it. I use .append() to add more ejs to .objects. I am having a hard time adding to only the .objects div that is inside of the same div as the button. I tried doing the following
".addObj click": function(el, element){
$(".addObj").closest(".objAddDiv").find(".objects").append(//my ejs utility here)
}
The problem is that $(".addObj").closest(".objAddDiv") returns all .objAddDiv on the page. I have looked at the jquery documentation for .closest and it says closest should only return one element. Is there a better way to do this? What am I doing wrong. (these are not my real class names btw)
It's because you are calling that method on every element with a class of 'addObj':
For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
So you get the closest objAddDiv to each addObj element.
Assuming you are doing this inside the click event of the button use this to get the correct element:
$(this).closest(".objAddDiv").find(".objects").append(//my ejs utility here)
Here is the answer that I figured out (for anyone who comes next) I needed to use the element I passed into the function:
el.closest(".objAddDiv").find(".objects").append(//ejs append stuff)

What is the difference between appendChild, insertAdjacentHTML, and innerHTML

I want to know what the difference is between appendChild, insertAdjacentHTML, and innerHTML.
I think their functionality are similar but I want to understand clearly in term of usage and not the execution speed.
For example, I can use innerHTML to insert a new tag or text into another tag in HTML but it replaces the current content in that tag instead of appends.
If I would like to do it that way (not replace) I need to use insertAdjacentHTML and I can manage where I want to insert a new element (beforebegin, afterbegin, beforeend, afterend)
And the last if I want to create (not insertion in current tag) a new tag and insert it into HTML I need to use appendChild.
Am I understanding it correctly? Or are there any difference between those three?
element.innerHTML
From MDN:
innerHTML sets or gets the HTML syntax describing the element's descendants.
when writing to innerHTML, it will overwrite the content of the source element. That means the HTML has to be loaded and re-parsed. This is not very efficient especially when using inside loops.
node.appendChild
From MDN:
Adds a node to the end of the list of children of a specified parent node. If the node already exists it is removed from current parent node, then added to new parent node.
This method is supported by all browsers and is a much cleaner way of inserting nodes, text, data, etc. into the DOM.
element.insertAdjacentHTML
From MDN:
parses the specified text as HTML or XML and inserts the resulting nodes into the DOM tree at a specified position. [ ... ]
This method is also supported by all browsers.
....
The appendChild methods adds an element to the DOM.
The innerHTML property and insertAdjacentHTML method takes a string instead of an element, so they have to parse the string and create elements from it, before they can be put into the DOM.
The innerHTML property can be used both for getting and setting the HTML code for the content of an element.
#Guffa did explain the main difference ie innerHTML and insertAdjacentHTML need to parse the string before adding to DOM.
In addition see this jsPerf that will tell you that generally appendChild is faster for the job it provides.
One that I know innerHTML can grab 'inner html', appendChild and insertAdjacentHTML can't;
example:
<div id="example"><p>this is paragraph</p><div>
js:
var foo = document.getElementById('example').innerHTML;
end then now
foo = '<p>this is paragraph</p>';
DOCS:
appendChild
insertAdjacentHTML
innerHtml
innerHTML vs appendChild() performance
insertAdjacentHTML vs innerHTML vs appendChild performance
the main difference is location (positioning) :
(elVar mean element saved to variable)
** elVar.innerHTML: used to sets/get text and tags (like ) inside an element (if u use "=" it replace the content and "+=" will add to the end.
** divElvar.appendChild(imgElVar): to add pure element to the end of another element (or start with prepend) .
** insertedElVar.insertAdjacentElement(beforebegin,targetElvar): it insert element into spicific location before elVar (after it with "afterend").
-innerText: can replace/get/insertOnEnd text.but can read tags and text inside element with display:hidden , cant insert on start .
-innercontent : show all text inc hidden , cant read html tags and it put empty spaces instead of them , cant insert on start
-innerHTML: read all set all , cant insert on start
-prepend : insert text at start of elvar (but cant use to get/replace text or html)
prepend was needed for start, after it made its easy to make append , not for a need , its just bcz lol

Unnamed href link wrapped in two containers

I am trying to change the link of a basic <a>. It has no id. It is located in a header.aspx file that I cannot access directly. It is also the first grandchild element of a div with the id "SiteMenu". From that div I would like to use the following script. (I can put script refs in the footer and upload to the Theme dir):
document.getElementById("SiteMenu").childNodes[0].childNodes[0].href = "/search.aspx?keyword='+'&page=1";`
also tried:
document.getElementById("SiteMenu").firstChild.childNodes[0].href = "/search.aspx?keyword='+'&page=1";`
The basic structure of the HTML is:
<div id="SiteMap">
<p>
Home
</p>
</div>
I'm no JS pro. From some things I read before posting here, it seems like childNodes.childNodes is an invalid way to search through node levels in JS (or the DOM?).
Is there some other way to manipulate the href of my tag?
.childNodes[0] won't have any children since the first child is a text node, containing the line break and space before the <p> (at least in your example). You want to get the first element node.
For example:
document.getElementById("SiteMenu").children[0].children[0].href = '...';
See .children [MDN] for more information.
Alternative you can iterate over each child node and test its .nodeType [MDN] to see whether it is an element node or not.

Using JQuery to traverse DOM structure, finding a specific <table> element located after HTML 'comment'

I currently have a website source code (no control over the source) which contains certain content that needs to be manipulated. This would be simple on the surface, however there is no unique ID attribute on the tag in question that can uniquely identify it, and therefore allow for further traversal.
Here is a snippet of the source code, surrounding the tag in question.
...
<td width="100%">
<!--This table snaps the content columns(one or two)-->
<table border="0" width="100%">
...
Essentially, the HTML comment stuck out as an easy way to gain access to that element. Using the JQuery comment add-on from this question, and some help from snowlord comment below, I have been able to identify the comment and retrieve the following output using the 'dump' extension.
$('td').comments().filter(":contains('This table snaps the content columns(one or two)')").dump();
returns;
jQuery Object {
0 = DOMElement [
nodeName: DIV
nodeValue: null
innerHTML: [
0 = String: This table snaps the content columns(one or two)
]
]
}
However I am not sure how to traverse to the sibling element in the DOM.
This should be simple, but I haven't had much selector experience with JQuery. Any suggestions are appreciated.
I am thinking you could use the siblings method:
$('td').comments().siblings('table').yourcode...
From the docs:
Given a jQuery object that represents a set of DOM elements, the .siblings() method allows us to search through the siblings of these elements in the DOM tree and construct a new jQuery object from the matching elements.
The method optionally accepts a
selector expression of the same type
that we can pass to the $() function.
If the selector is supplied, the
elements will be filtered by testing
whether they match it.
If you have any control over this code at all, put an id on the table.
If you have to do something nasty, perhaps you could use
var tables = $("table");
To get all tables and then ascertain the table in question by index...
$(tables[5]).css("color", "aqua");
This breaks as soon as a table is added or removed, but if you cannot add an id to the table it seems like a potential alternative.

Categories