JS and querySelectorAll - javascript

A querySelectorAll question, most likely a silly one, but I don't see the solution.
I have something like the following
<div id="main_0"> ... </div>
<div id="main_1"> ... </div>
<div id="main_1_minor"> ... </div>
<div id="main_2"> ... </div>
<div id="main_2_minor"> ... </div>
.
.
I wish to select all and only those div's without minor.
I tried
var pattern = new RegExp('^main_\\d');
var elSelected = document.querySelectorAll('div[id^=main_]');
elSelected.filter(elt => pattern.test(elt.id)));
but clearly it is not enough. I am not sure how to formulate by RegEx that the id value has to terminate with a digit. I tried something like RegExp('^main_\\d$'); but I did not get it right.

You can use the :not() selector with the "attribute ends with" selector.
"div:not([id$=minor])"
If it should also verify that the id starts with main_, then you can add that too as you show in your question.
"div[id^=main_]:not([id$=minor])"
So this says "select all div elements where the id starts with main_ and does not end with minor".
If minor is not necessarily at the end, then you can use id*=minor for "contains" instead.
document.querySelectorAll("div[id^=main_]:not([id$=minor])")
.forEach(el => el.style.color = "red");
<div id="main_0"> main </div>
<div id="main_1"> main </div>
<div id="main_1_minor"> main ends with minor </div>
<div id="main_2"> main </div>
<div id="main_2_minor"> main ends with minor </div>

The filter won't work for NodeList, cast to array first. Also if you already selected all main divs the simplest regex would be enough.
var pattern = new RegExp(/\d+$/);
var elSelected = Array.prototype.slice.call(document.querySelectorAll('div[id^=main_]'));
elSelected.filter(elt => pattern.test(elt.id)).forEach(function(elt){
elt.style.backgroundColor = "yellow";
});
<div id="main_0">main_0</div>
<div id="main_1">main_1</div>
<div id="main_1_minor">main_1_minor</div>
<div id="main_2">main_2</div>
<div id="main_0_minor">main_0_minor</div>

Related

How can I get the path to a specific DOM element iterating a HTML collection?

This is the issue: I want to have nested divs with paragraphs inside with different texts.
I want to be able to get the paragraph that contains certain word, for example "mate" I did the below HTML structure trying to obtain an HTML collection and iterate it, and then using javascript, try to use the includes method to get the paragraph than contains that word, and finally, try to find a way to get the full path from the uppermost div to this p.
<div class="grandpa">
<div class="parent1">
<div class="son1">
<p>I like oranges</p>
</div>
<div class="son2">
<p>yeeeey</p>
<p>wohoo it's saturday</p>
</div>
<div class="son3"></div>
</div>
<div class="parent2"></div>
<div class="parent3">
<div class="son1">
<p>your team mate has been killed!</p>
<p>I should stop playing COD</p>
</div>
<div class="son2"></div>
</div>
</div>
I actually don't know how to achieve it, but at least I wanted to get an HTML collection to iterate, but I'm not being able to get it.... When I use this:
const nodes = document.querySelector('.grandpa');
console.log(typeof nodes);
I don't get an HTML collection, instead if I console.log typeof nodes variable it says it is an object..
How can I iterate this DOM tree, capture the element that contais the word "mate", and obtain (this is what I really want to achieve) the path to it?
Thanks!
You can loop through every element, remove all children elements, then check whether the textContent includes the string you are looking for:
const allElements = document.body.querySelectorAll('*');
const lookFor = "mate";
var elem;
for (let i = 0; i < allElements.length; i++) {
const cur = allElements[i].cloneNode(true); //doesn't mess up the original element when removing children
while (cur.lastElementChild) {
cur.removeChild(cur.lastElementChild);
}
if (cur.textContent.includes(lookFor)) {
elem = cur;
break;
}
}
console.log(elem);
<div class="grandpa">
<div class="parent1">
<div class="son1">
<p>I like oranges</p>
</div>
<div class="son2">
<p>yeeeey</p>
<p>wohoo it's saturday</p>
</div>
<div class="son3"></div>
</div>
<div class="parent2"></div>
<div class="parent3">
<div class="son1">
<p>your team mate has been killed!</p>
<p>I should stop playing COD</p>
</div>
<div class="son2"></div>
</div>
</div>

How to get the first class from two same classes with cheerio

currently i'm making a web scraper with node.Js using cheerio. i want to get the data inside the first of class="panel-items-list.
the html look like this
<div class="margin-bottom-=30">
<div class="side-list-panel">
<ul class="panel-item-list">...</ul>
</div>
</div>
<div class="margin-bottom-=30">
<div class="side-list-panel">
<ul class="panel-item-list">...</ul>
</div>
</div>
i already did like this
const relateArticle = $('.panel-items-list').map((i, section)=>{
let articles = $(section).find('h5');
return articles.text();
}).get();
but it return the data from both class="panel-items-list". how do i get data just from one class ? sorry my english is bad. thanks in advance !
To get the first class only from the .panel-item-list use .get(0) that means you are only selecting the first index found using .map
Also, in your current code jQuery your are not selecting the right class selector.
In addition use .trim() method when getting the text to clean up any unseen spaces within the text.
Live Working Demo:
const relateArticle = $('.panel-item-list').map((i, section) => {
let articles = $(section).find('h5');
return articles.text().trim();
}).get(0)
console.log(relateArticle) //Foo
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="margin-bottom-=30">
<div class="side-list-panel">
<ul class="panel-item-list">
<h5>
Foo
</h5>
</ul>
</div>
</div>
<div class="margin-bottom-=30">
<div class="side-list-panel">
<ul class="panel-item-list">
<h5>
Bar
</h5>
</ul>
</div>
</div>
Use first():
$('.panel-items-list').first().find('h5').text()

How do I replace instances of a word in multiple tags on page load?

Trying to replace a word that possibly will come in a foreach loop of a database items in razor view.
What I've tried so far
<section class="section bg-gray">
<div class="container">
<div class="row gap-y">
#foreach (var item in Model)
{
<div class="col-md-6 col-lg-4">
<div class="card d-block">
<p class="text-justify">#item.Text</p>
<p class="text-center mt-7">
<a class="btn btn-primary" href="#">Read more</a>
</p>
</div>
</div>
}
</div>
<script src="~/Scripts/jquery-3.3.1.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
var elements = getElementsByClassName("text-justify");
$(elements).each(function(element) {
element.innerHTML = element.innerHTML.replace(/wordToReplace/g, 'newWord');
});
});
</script>
</div>
</section>
Excuse my poor JavaScript, I'm new on front-end. I looked for similar questions but closer topics are usually about replacing instances of a word in one tag. Please help.
You don't need jQuery for this - you can use document.querySelectorAll and just replace the desired text of the elements that match the selector.
Note that I have dodgied up a text element and for the desired class and replacing justify with justified to demonstrate the usage.
let elements = document.querySelectorAll(".text-justify");
elements.forEach(function(element){
let textContent = element.innerText;
let newTextContent = textContent.replace(/justify/g, 'justified');
element.innerText = newTextContent;
})
<p class="text-justify">This is a text with the class of text-justify</p>
<p>This is a text without the class of text-justify</p>
<p class="text-justify">This is a text with the class of text-justify</p>
You don't need jQuery for this - use a simple forEach loop. I've also refactored some other parts of your code (eg you were missing document:
document.getElementsByClassName("text-justify").forEach(element => element.innerHTML = element.innerHTML.replace(/word/g, "newWord"));
But if you really want to use jQuery:
$(".text-justify").html((index, element) => element.replace(/word/g, "newWord"));

Get Nth class of an element having multiple class with out using .attr("class") in jquery

In a div with two classes, the first inner div
<div class="datacheck">
<div class="classic_div_data customdataid_305">
some values come here
</div>
<div class="optiondiv">
</div>
</div>
I need to get a substring (here the number 305) from the second class(customdataid_305) of the first inner div. For this need to get the classes.
I wrote in jquery and succeed
var xyz= $($(".datacheck").find("div")[0]).attr("class").split(" ")[1]
from which I gets the class.
Is there any simpler approach for this.
I am searching for something like this $(element).class() probably returns an array of classes
There's nothing that gives you an array of classes, although the native DOM classList is close. But I don't think classList will make things much simpler.
I'd do this:
var xyz = $(".datacheck .classic_div_data").attr("class").match(/\bcustomdataid_(\d+)\b/);
xyz = xyz && xyz[1];
The regex extracts the numeric portion of the class, without being fragile (sensitive to whether the class is the first or second in the list of classes, for instance).
Example:
var xyz = $(".datacheck .classic_div_data").attr("class").match(/\bcustomdataid_(\d+)\b/);
xyz = xyz && xyz[1];
console.log("xyz = '" + xyz + "'");
<div class="datacheck">
<div class="classic_div_data customdataid_305">
some values come here
</div>
<div class="optiondiv">
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
If you can change the HTML, though, I wouldn't use a class for this at all, I'd us a data-* attribute instead:
<div class="classic_div_data" data-custom-id="305">
then
var xyz = $(".datacheck [data-custom-id]").attr("data-custom-id");
Example:
var xyz = $(".datacheck [data-custom-id]").attr("data-custom-id");
console.log("xyz = '" + xyz + "'");
<div class="datacheck">
<div class="classic_div_data" data-custom-id="305">
some values come here
</div>
<div class="optiondiv">
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
One of the major problems you have with your current design is that if the order of the classes changes, or someone adds another class, your logic breaks. You're also getting a DOMElement from a jQuery object which you turn back in to a jQuery object again.
It would be a much better approach to use data-* attributes to store your custom data, like this:
$('.classic_div_data').click(function() {
console.log($(this).data('customdataid'));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="datacheck">
<div class="classic_div_data" data-customdataid="305">
some values come here
</div>
<div class="optiondiv"></div>
</div>
<div class="datacheck">
<div class="classic_div_data" data-customdataid="205">
some more values come here
</div>
<div class="optiondiv"></div>
</div>
You can get the nth class easily from the classList of element object,
var x = $(".datacheck").find("div").get(0);
var nthClass = x.classList[1]
var res = nthClass.replace("customdataid_", "");
console.log(res); //305
You can use regex in .match() to finding last digit in class.
var digit = $(".datacheck > :first").attr("class").match(/[\d]+$/g)[0];
console.log(digit);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="datacheck">
<div class="classic_div_data customdataid_305">some values come here</div>
<div class="optiondiv"></div>
</div>

How to order divs with JQUERY

i have divs like this:
<div class="oferta SYB">
<div class="infoferta">
<div class="datosoferta">
<div class="ofertapagas">Pagás<br/> $ 67</div>
<div class="ofertavalor">Valor<br /> $ 160</div>
<div class="ofertadescuento">Descuento $ 93</div>
</div>
</div>
i want to order the divs with the class="oferta" by the value in "ofertapagas" or the value in "ofertavalor" or the value in "ofertadescuento", i dont know how to, i cannot use the database, i just can use Jquery, i am using the last version of it.
Some Help please!!
jQuery abstracts Array.prototype.sort. Since jQuery wrappet sets are Array like objects, you can just call .sort() on them or apply sort on them.
var $datosoferta = $('.datosoferta');
$datosoferta.children().detach().sort(function(a,b) {
return +a.textContent.split(/\$/)[1].trim() - +b.textContent.split(/\$/)[1].trim();
}).appendTo($datosoferta);
See http://typeofnan.blogspot.com/2011/02/did-you-know.html
Demo: http://jsfiddle.net/Rfsfs/
Using ui. JQuery UI - Sortable Demos & Documentation
For your code;
$( ".offer" ).sortable({
update: function(event, ui) { // do post server. }
});
If you place those offer DIVs in some sort of container (another DIV?) you can then fetch all the offers and sort by their childrens' values.
In the HTML below, I put the offer divs inside a container div, and added a data-value attribute to each of the child divs containing data, for easier access (no regular expressions required).
<div id="ofertas_container">
<div class="infoferta">
<div class="datosoferta">
<div class="ofertapagas" data-value="67">Pagá $ 67</div>
<div class="ofertavalor" data-value="130">Valor $ 130</div>
<div class="ofertadescuento" data-value="93">Descuento $ 93</div>
</div>
</div>
<div class="infoferta">
<div class="datosoferta">
<div class="ofertapagas" data-value="57">Pagá $ 57</div>
<div class="ofertavalor" data-value="150">Valor $ 150</div>
<div class="ofertadescuento" data-value="43">Descuento $ 43</div>
</div>
</div>
<div class="infoferta">
<div class="datosoferta">
<div class="ofertapagas" data-value="107">Pagá $ 107</div>
<div class="ofertavalor" data-value="250">Valor $ 250</div>
<div class="ofertadescuento" data-value="1000">Descuento $ 1000</div>
</div>
</div>
</div>
Pagá
Valor
Descuento
The JS / jQuery function:
ofertas_sort = function(sort_key) {
// array of offer divs
var ofertas = $('.infoferta');
// the div classname corresponding to the key by which
// we are sorting
var sort_key_sel = 'div.' + sort_key;
// in large lists it'd be more efficient to calculate
// this data pre-sort, but for this instance it's fine
ofertas.sort(function(a, b) {
return parseInt($(sort_key_sel, a).attr('data-value')) -
parseInt($(sort_key_sel, b).attr('data-value'));
});
// re-fill the container with the newly-sorted divs
$('#ofertas_container').empty().append(ofertas);
};
Here's the code on jsFiddle, with some links at the bottom of the HTML to demo the sorting: http://jsfiddle.net/hans/Rfsfs/2/
I changed some of the values to make the sorting more visible.

Categories