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

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()

Related

How can I use jQuery to make an element's content the same as another?

I have a site with a drop-down menu and I want the titles in it to be the same as the content in an h1 tag on another part of my site
This is my jQuery -
const johnName = $("#john").siblings("span");
const johnNameMenu = $(".john").children("h1").val();
johnName.html(johnNameMenu);
This is the code on my site which I want to appear in the menu -
<section class="john">
<div class="team-header" id="john">
<div class="teamlogo">
<img src="images/logos/lazio.png" />
<h1>John's Team</h1>
</div>
</div>
<div class="john-roster team-rosters">
<?php include ('john.php'); ?>
</div>
</section>
This is the code in the dropdown menu -
<a href="#john" id="john-link" class="anchor">
<span></span></a>
I want the "John's Team" to appear in the drop-down menu.
What is wrong with my jQuery code?
For getting the text of an element you use the function text(); val() is for <input> elements.
Note: even though I left the HTML as-is, id should be unique in a page. You should be using class if you want to have multiple of those <a> tags in there.
Your selectors and use of .children were not right. If you still want to use .children the line would be $('.john').children().find('span').
I'd recommend using more specific selectors than using .john (children far down in hierarchy).
const johnName = $(".john span");
const johnNameMenu = $(".john h1").text();
console.log(johnNameMenu)
johnName.each(function(){
$(this).html(johnNameMenu);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
This is the code on my site which I want to appear in the menu -
<section class="john">
<div class="team-header" id="john">
<div class="teamlogo">
<img src="images/logos/lazio.png" />
<h1>John's Team</h1>
</div>
</div>
<div class="john-roster team-rosters">
<a href="#john" id="john-link" class="anchor">
<span></span></a>
<a href="#john" id="john-link" class="anchor">
<span></span></a>
</div>
</section>
try this
const johnName = $("#john").closest("selection").find("span");
const johnNameMenu = $(".john").children("h1").val();
johnName.html(johnNameMenu);

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"));

Copy HTML from element, replace text with jQuery, then append to element

I am trying to create portlets on my website which are generated when a user inputs a number and clicks a button.
I have the HTML in a script tag (that way it's invisible). I am able to clone the HTML contents of the script tag and append it to the necessary element without issue. My problem is, I cannot seem to modify the text inside the template before appending it.
This is a super simplified version of what I'd like to do. I'm just trying to get parts of it working properly before building it up more.
Here is the script tag with the template:
var p = $("#tpl_dashboard_portlet").html();
var h = document.createElement('div');
$(h).html(p);
$(h).find('div.m-portlet').data('s', s);
$(h).find('[data-key="number"]').val(s);
$(h).find('[data-key="name"]').val("TEST");
console.log(h);
console.log($(h).html());
console.log(s);
$("div.m-content").append($(h).html());
<script id="tpl_dashboard_portlet" type="text/html">
<!--begin::Portlet-->
<div class="m-portlet">
<div class="m-portlet__head">
<div class="m-portlet__head-caption">
<div class="m-portlet__head-title">
<h3 class="m-portlet__head-text">
<span data-key="number"></span> [<span data-key="name"></span>]
</h3>
</div>
</div>
<div class="m-portlet__head-tools">
<ul class="m-portlet_nav">
<li class="m-portlet__nav-item">
<i class="la la-close"></i>
</li>
</ul>
</div>
</div>
<!--begin::Form-->
<div class="m-portlet__body">
Found! <span data-key="number"></span> [<span data-key="name"></span>]
</div>
</div>
<!--end::Portlet-->
</script>
I'm not sure what I'm doing wrong here. I've tried using .each as well with no luck. Both leave the value of the span tags empty.
(I've removed some of the script, but the variable s does have a value on it)
You have two issues here. Firstly, every time you call $(h) you're creating a new jQuery object from the original template HTML. As such any and all previous changes you made are lost. You need to create the jQuery object from the template HTML once, then make all changes to that object.
Secondly, the span elements you select by data-key attribute do not have value properties to change, you instead need to set their text(). Try this:
var s = 'foo';
var p = $("#tpl_dashboard_portlet").html();
var $h = $('<div />');
$h.html(p);
$h.find('div.m-portlet').data('s', s);
$h.find('[data-key="number"]').text(s);
$h.find('[data-key="name"]').text("TEST");
$("div.m-content").append($h.html());
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script id="tpl_dashboard_portlet" type="text/html">
<div class="m-portlet">
<div class="m-portlet__head">
<div class="m-portlet__head-caption">
<div class="m-portlet__head-title">
<h3 class="m-portlet__head-text">
<span data-key="number"></span> [<span data-key="name"></span>]
</h3>
</div>
</div>
<div class="m-portlet__head-tools">
<ul class="m-portlet_nav">
<li class="m-portlet__nav-item">
<i class="la la-close"></i>
</li>
</ul>
</div>
</div>
<div class="m-portlet__body">
Found! <span data-key="number"></span> [<span data-key="name"></span>]
</div>
</div>
</script>
<div class="m-content"></div>
In my case only this is working:
var template = $('template').clone(true, true); // Copies all data and events
var $h = $('<div />');
$h.html(template);
$h.find('.input-name').attr('value', "your value here"); // Note: .val("your value here") is not working
$('.list').prepend($h.html());

JS and querySelectorAll

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>

Container structure issue with JQuery - Containing containers

I'm finishing up a memory game for school and I'd really like the cards to flip with a CSS animation, which on it's own is pretty straight forward. However I'm pretty new to JavaScript and JQuery which is leading to some trouble with achieving the proper container structure I need to make the cards flip when they are clicked.
Presently the game pieces generate within the board as follows:
const generate=(cards)=>{
cards.forEach(function(card, i) {
$(".gameBoard")
.append($("<div>").addClass("front")//
.append($("<div>").addClass("back").append($("
<img>").attr("src", cards[i]))));
});
};
OR:
<div class="gameBoard>
<div class="front"></div>
<div class="back"><img src="cards"></div>
</div>
But in order for the animation to function properly both the front and back divs need to exist in the same container like this:
<div class="gameBoard>
<div class="flip">
<div class="front></div>
<div class="back"><img src="cards></div>
</div>
</div>
How can I add the div I need (.flip) but have it contain the front and back divs, not just append on to the other divs being generated within the .gameboard container.
Thanks.
It's much simpler to create your DOM using template literals rather than jQuery methods. That way you just describe the HTML as you're accustomed to.
const generate=(cards)=>{
cards.forEach(function(card, i) {
$(".gameBoard").append(`
<div class=flip>
<div class=front></div>
<div class=back><img src="${cards[i]}"</div>
</div>
`);
});
};
generate([
"https://dummyimage.com/180x120/f00/fff.png&text=one",
"https://dummyimage.com/180x120/0f0/fff.png&text=two",
"https://dummyimage.com/180x120/00f/fff.png&text=three",
]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<div class=gameBoard></div>
You'll notice the ${cards[i]}, which lets you perform string interpolation by executing at runtime the code in the braces.
Here's a vanilla JS version.
const generate=(cards)=>{
var gb = document.querySelector(".gameBoard");
cards.forEach(card =>
gb.insertAdjacentHTML("beforeend", `
<div class=flip>
<div class=front></div>
<div class=back><img src="${card}"</div>
</div>
`)
);
};
generate([
"https://dummyimage.com/180x120/f00/fff.png&text=one",
"https://dummyimage.com/180x120/0f0/fff.png&text=two",
"https://dummyimage.com/180x120/00f/fff.png&text=three",
]);
<div class=gameBoard></div>
It also uses card instead of cards[i], and an arrow function for the callback.
And this one performs a single append.
const generate=(cards)=>{
document.querySelector(".gameBoard")
.insertAdjacentHTML("beforeend", cards.map(card =>
` <div class=flip>
<div class=front></div>
<div class=back><img src="${card}"</div>
</div>`).join(""));
};
generate([
"https://dummyimage.com/180x120/f00/fff.png&text=one",
"https://dummyimage.com/180x120/0f0/fff.png&text=two",
"https://dummyimage.com/180x120/00f/fff.png&text=three",
]);
<div class=gameBoard></div>

Categories