Immediate nested DOM declaration in javascript - javascript

How can I get a nested DOM element in javascript instead of using jQuery?
Example:
$('#id') = document.getElementById('id');
I would like to convert this jQuery selector $('.nav > li') to javascript. How can I do that?

You have a really nice function called document.querySelectorAll() which can select elements with css queries.
document.querySelectorAll('.nav > li');
If you plan to use it more than once, you can also use a var so it'll feel like using jQuery
var _ = document.querySelectorAll.bind(document)
var menuItems = _('.nav > li');

Just to complement the answers suggesting querySelectorAll, here's how you would achieve that with old school DOM operations.
var selected = [];
// get all elements that have the class 'nav' (.nav)
var navs = document.getElementsByClassName('nav');
var i, j, children;
// iterate over each nav and get a list of their direct children (.nav >)
for(i = 0; i < navs.length; i++) {
children = navs[i].children;
// iterate over the children and select if the tag is li (.nav > li)
for(j = 0; j < children.length; j++) {
if(children[j].tagName === 'LI') {
selected.push(children[j]);
}
}
}
Also serves as a good example of why declarative programming is better suited to this kind of task.

Related

how to use querySelector to match to specific id after having obtained a nodelist from querySelectorAll

I am using querySelectorAll property initially to obtain nodelists of certain tags,and then from this nodelist i am iterating through each node looking for a certain match to an id property using querySelector,however the result always is null.
var x=document.body.querySelectorAll("script");
for(var i=0;i<x.length;++i)
{
var y=x[i].querySelector("#myid");
console.log(y);
if(y!== null)
{
console.log(i+1);
}
}
i always get an output of null,please help.
If you want to select for example script tags that have the name attribute equal to myName use this:
var elems = document.querySelectorAll('script[name = "myName"]');
You can put as many CSS selectors as ou want to narrow the search.
If you want for example to select div elements that are direct children of li element, and that have the attribute name begin with "abc" and that have an id and a class someClass then use this:
var elems = document.querySelectorAll('li > div[name ^= "abc"][id].someClass');
Here is link to all CSS Selectors!
Krishna your querySelectorAll will grab a nodelist for you. There is no reason for you to add an additional query selector within your loop.
var myId = document.querySelector('#myid');
var collection = document.body.querySelectorAll("script");
for (var i = 0; i < collection.length; i++) {
if (collection[i].includes(myId)) {
console.log(i+1);
}
}

Get all the elements that start with a particular innerHTML using query selector?

I am currently having problem with selecting and matching the innerHTML using querySelectorAll.
Here is what i did:
document.querySelectorAll('*[class^="js-display-url"]').contains('product')
What the html is:
<span class="js-display-url">product/poss/newslanges</span>
But i want to match the class js-display-url starting with product but can't do that. please help.
With DOM selectors you cannot select elements based on the inner HTML, but you can loop through all the elements with that class and single out the ones that match your condition:
var allElements = document.querySelectorAll('*[class^="js-display-url"]');
var myElements = [];
for (var i = 0; i < allElements.length; i++) {
if (allElements[i].innerHTML.startsWith('product')) {
myElements.push(allElements[i]);
}
}
There isn't a DOM selector which will filter based on text nodes, but you can filter using some array methods, since a NodeList is array-like.
In particular, Array.prototype.filter can get the elements that meet your criteria.
var filter = Array.prototype.filter;
var allElements = document.querySelectorAll('.js-display-url');
var productElements = filter.call(allElements, function(element) {
return element.innerText.startsWith('product');
});
console.log(productElements);
<span class="js-display-url">product/poss/newslanges</span>

Javascript building element reference node list

How can i build a nodelist, which is reference to the selected node?
Example document.querySelectorAll('tr') returns a nodelist contains all the tr element node references on page.
I`m writing methods, to return element nodelist references by search criteria.
But if i using insertBefore, appendChild, etc... this function will remove the nodes from the elements.
Example i have a 4x4 table, and i want to return the first 2 rows:
var nl = document.createDocumentFragment();
el = document.querySelectorAll('tr');
for ( var a = 0; a < 2 && a < el.length; a++)
{
nl.appendChild(el[a]);
}
console.log(nl);
This nl returns the first 2 rows of the table, but it will removes from the document. Removed from the DOM and append to nl as child.
I want to retrieve only the node(s) reference like querySelectorAll as a list, not as documentFragment childNodes.
Any idea how to archieve this?
If you don't want to move things around in the DOM, don't use the methods that move things around!
var nl = new Array();
var el = document.querySelectorAll('tr');
for ( var a = 0; a < 2 && a < el.length; a++)
{
nl.push(el[a]);
}

YUI nested selectors

I am a YUI(AUI) beginner. In jQuery I would do
$(image).find(selector).text();
How can this be achieved in YUI?
AUI().use('event', 'node', function(A) {
var subImages = A.all('.sub_image_conatiner');
for (var i = 0; i < subImages.size(); i++){
var image = subImages.get(i);
//get child elements of image here
}
});
I thought Y.all(foo).all(selector).get('text') would just work but it unfortunately doesn't.
I'd recommend that you use only one selector to match the sub elements:
Y.all('.parent-class .child-class').get('text');
If you can't, then you don't have to iterate through the nodes like a normal JS array. You can use .each().
var texts = [];
Y.all(foo).each(function (node, i) {
texts = texts.concat(node.all(bar).get('text'));
});
console.log(texts);
I'll file a bug with YUI to see if it makes sense to add Y.NodeList.prototype.all

Optimization appending <li> into <ul> with jQuery

I populate a list with search results appending li elements. I update DOM for each result.
for (var i = 0; i < topics.length; i++) {
$("#searchResults").append(
$("<li />")
.append(result.Name)
.addClass("example")
);
};
I want to make a group of li elements first and update DOM-tree just once.
I try something like this:
var list = $([]);
for (var i = 0; i < topics.length; i++) {
list.append(
$("<li />")
.append(result.Name)
.addClass("example")
);
};
$("#searchResults").append(list);
But div $("#searchResults") is empty.
Where is the problem?
Something like this should be much faster:
var ul = $("<ul />");
for (var i = 0, l=topics.length; i < l; i++) {
$("<li />", { text: result.Name, "class": "example" }).appendTo(ul);
};
$("#searchResults").append(ul.contents());
By using a document fragment ($("<ul />")) and appending to it, then appending at the end, we're not messing with the entire DOM each append. Also we're not repeatedly selecting #searchResults each loop...or checking .length would could also be expensive.
Note: this method still uses the DOM to create elements (as opposed to a string), eliminating issues of result.Name having HTML that could screw things up, etc.
Creating DOM elements on the fly will usually be slower than just using innerHTML (or a wrapper around that). Also, concatenating string with + will usually be slower than using Array.join('').
In the end, I suspect something like this would be the fastest:
var list = [];
for (var i = 0; i < topics.length; i++)
list.push("<li class=example>",topics[i].Name,"</li>");
$("#searchResults").html(list.join(''));
Try just using a string. Add all your li's to a string and then put them into the innerHTML of the searchResults div.
var list = '';
for (var i = 0; i < topics.length; i++) {
list +="<li class=example>" + result.Name + "</li>";
}
$("#searchResults").innerHTML = list;
If you are looking for efficacy this is probably better because you are not using the DOM engines a lot. (although unless you are adding hundreds of li's it is probably insignificant anyway.
All previous solutions still suffer from recalculating, painting and layout for every single element we add.
Instead of appending the elements directly to the document when they are created, append them to the DocumentFragment instead, and finish by adding that to the DOM.
var el;
var i = 0;
var fragment = document.createDocumentFragment();
while (i < 500) {
el = document.createElement('li');
el.innerText = '1ist ' + i;
fragment.appendChild(el);
i++;
}
div.appendChild(fragment);

Categories