Unable to access descendant of an HTML element using jQuery - javascript

I have a problem with getting a html() value of child of a parent :D
function voteup(e){
var count = $(e).parents('.item').children('.count');
console.log(count.html()); // undefined
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="post_contain">
<img src="images/comments/dQ6dz.jpg" alt="">
</div>
<div class="item">
<p class="post-meta">
<span href="/gag/agVzE1g" target="_blank">
<span class="count">5</span>points
</span>
</p>
<div class="vote">
<ul class="btn-vote left">
<li class="badge-item-vote-up-li">
<a onclick="voteup(this)">Click me</a>
</li>
</ul>
</div>
</div>
In the function voteup(e), I need to get the value of the class 'count', but I don't retrieve the value with html()

children only traverses a single level of the DOM tree - i.e. it won't find grandchildren.
Instead, use closest to find the .item -- which finds the single nearest match, as opposed to parents which can find multiple -- and find to locate the child, since that will traverse arbitrarily deep HTML structures:
function voteup(e){
var count = $(e).closest('.item').find('.count');
alert(count.html());
var actual = parseInt(count.html(), 10);
count.text(actual + 1);
}

Related

get a nested element inside a div by class name

I am trying to get an span element which has a class of main-tag inside a nested div. But i don't want to get that element through querySelector as there are many elements in my html file with the same class and i don't intend to use IDs for that.
I know i am making some mistake in my recursive function. That's why this code is not working.
So for this i'm recursively calling a function to get the desired element. But undefined is returned by found variable.
function getElem(cell, name) {
let found;
if (cell.classList.contains(name)) return cell;
else if (cell.children.length === 0) return null;
else {
found = Array.from(cell.children).find((element) =>
element.classList.contains(name)
);
if (found === undefined) {
Array.from(cell.children).forEach((element) => {
found = getElem(element, name);
});
} else return found;
}
}
console.log(getElem(document.getElementById("block-one"), "main-tag"));
<div id="block-one">
<div class="something-one">
<span class="something-two">Hello</div>
<span class="abc">not found</div>
</div>
<div class="here">
<span class="main-tag">Yes, i am here</div>
<span class="bogus-tag">never find out</div>
</div>
</div>
Your markup is using </div> where </span> is expected.
You can use full CSS selectors with querySelector. So for instance, to find the first element with the class main-tag inside the element with id="block-one", you can do this:
const element = document.querySelector("#block-one .main-tag");
Live Example:
console.log(document.querySelector("#block-one .main-tag"));
<div id="block-one">
<div class="something-one">
<span class="something-two">Hello</span>
<span class="abc">not found</span>
</div>
<div class="here">
<span class="main-tag">Yes, i am here</span>
<span class="bogus-tag">never find out</span>
</div>
</div>
Or alternatively, you can call querySelector on an element to only look at its descendants:
const element = document.getElementById("block-one").querySelector(".main-tag");
Live Example:
console.log(document.getElementById("block-one").querySelector(".main-tag"));
<div id="block-one">
<div class="something-one">
<span class="something-two">Hello</span>
<span class="abc">not found</span>
</div>
<div class="here">
<span class="main-tag">Yes, i am here</span>
<span class="bogus-tag">never find out</span>
</div>
</div>
A key difference between those is that the second one will throw an error if there is no id="block-one" element; the first will just return null. You could fix that using the newish optional chaining operator:
const element = document.getElementById("block-one")?.querySelector(".main-tag");
element will be either A) The matching element if there is one; B) null if there's an id="block-one" element but there are no .main-tag elements in it; or C) undefined if there is no id="block-one" element at all. (Even though document.getElementById returns null when it doesn't find something, the optional chaining operator results in undefined when its left-hand operand is either undefined or null.)
Or just use the document.querySelector option (the first one above), which gives you the matching element or null.
You don't seem to want this from your HTML, but: If you want to allow for the possibility the element itself has the class (getElem seems to allow for that possibility), you can use a group selector:
const element = document.querySelector("#block-one.main-tag, #block-one .main-tag");
Live Example:
console.log(document.querySelector("#block-one.main-tag, #block-one .main-tag"));
<div id="block-one" class="main-tag">
<div class="something-one">
<span class="something-two">Hello</span>
<span class="abc">not found</span>
</div>
<div class="here">
<span class="main-tag">Yes, i am here</span>
<span class="bogus-tag">never find out</span>
</div>
</div>
That works because the first member of the group, #block-one.main-tag (without a space) only matches the id="block-one" element if it has the class. If block-one doesn't have the class but one of its descendants does, that's found by the other member of the group, #block-one .main-tag (with the space). If the block-one element has the class and one of its descendants does, the block-one element is the one found, since it's first in document order (a parent is before its children in document order).
Your HTML is invalid.
When fixed, you can get the span using selectors directly
console.log(document.querySelector("#block-one > div.here > span.main-tag").textContent)
<div id="block-one">
<div class="something-one">
<span class="something-two">Hello</span>
<span class="abc">not found</span>
</div>
<div class="here">
<span class="main-tag">Yes, I am here</span>
<span class="bogus-tag">never find out</span>
</div>
</div>

How to hide all parents of a child with a repeating data attribute

I need a dynamic jquery or javascript code, which hides all <div> elements, if the data-event-id="" is a repeating one on the <a> element, so there are no multiple elements with the same attribute, only the first one.
The parents should be invisible like result of CSS display:none; but they can also be "deleted" on the code, doesn't really matter.
since my knowledge is limited on css and html, i'm completely lost.
<div>
<a data-event-id="87" href="https://google.com">1</a>
</div>
<div>
<a data-event-id="48" href="https://google.com">2</a>
</div>
<div>
<a data-event-id="87" href="https://google.com">3</a>
</div>
<div>
<a data-event-id="20" href="https://google.com">4</a>
</div>
<div>
<a data-event-id="48" href="https://google.com">5</a>
</div>
On this example, it should only show following links:
1
2
4
Does anyone know how to do this?
With jQuery you can query for all a-elements and iterate over them. You can keep track of known event-ids with an array where you add newly discovered event-ids. If the id is already in that array, simply hide the parent-element.
let events = [];
$('a').each(function(){
let event_id = $(this).attr('data-event-id');
if (!events.includes(event_id)) {
events.push(event_id);
} else {
$(this).parent().hide();
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<a data-event-id="87" href="https://google.com">1</a>
</div>
<div>
<a data-event-id="48" href="https://google.com">2</a>
</div>
<div>
<a data-event-id="87" href="https://google.com">3</a>
</div>
<div>
<a data-event-id="20" href="https://google.com">4</a>
</div>
<div>
<a data-event-id="48" href="https://google.com">5</a>
</div>
That's quite simple: you can iterate through your element collection, and check if its dataset.eventId is present in a unique set—this can be done by leveraging on ES6's Set(), which stores unique values (so it kind of serves as a dictionary). For each iteration, you:
check if the eventId is in the set. If it is, remove the node
store the eventId into your unique set for future comparison.
const elements = Array.from(document.querySelectorAll('a'));
const eventIds = new Set();
elements.forEach(element => {
const eventId = element.dataset.eventId;
if (eventIds.has(eventId)) {
element.parentNode.remove();
}
eventIds.add(element.dataset.eventId);
});
<div>
<a data-event-id="87" href="https://google.com">1</a>
</div>
<div>
<a data-event-id="48" href="https://google.com">2</a>
</div>
<div>
<a data-event-id="87" href="https://google.com">3</a>
</div>
<div>
<a data-event-id="20" href="https://google.com">4</a>
</div>
<div>
<a data-event-id="48" href="https://google.com">5</a>
</div>
You can also use :not(:first)").remove();
var i;
for (i = 0; i < 10; i++) {
$("[data-event-id$='" + i + "']:not(:first)").remove();
}
See fiddle

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

Access specific child div with jQuery

I want to know how to access a specific element in a div when foreach-ing
Here is some code
HTML
<div class="row menu-filter-items">
<div class="col-md-4 margin-b-30 menu-item">
<a href="#" class="menu-grid">
<img src="images/img-1.jpg" alt="" class="img-fluid"/>
<div class="menu-grid-desc">
<!-- <span class="price float-right">$9.50</span> -->
<h4 class="a" id="title">Restaurant y</h4>
<p>
Description
</p>
</div>
</a>
</div>
</div>
Jquery:
$('#search').keyup(function(e){
var current_query = $('#search').val();
if(current_query != null)
{
$("div.menu-filter-items").hide();
$("div.menu-filter-items div.menu-item").each(function(){
var current_keyword = $(this).children('#title').text();
alert(current_keyword);
if (current_keyword.indexOf(current_query) >=0)
{
$("div.menu-filter-items").show();
}
});
}
else
{
$("div.menu-filter-items").show();
}
});
I want to access the H4 balise but I couldn't
Help please
thank you
Use
var current_keyword = $(this).find('#title').text();
instead of
var current_keyword = $(this).children('#title').text();
You should use find method.
The .children() method allows us to search through the children of these elements in the DOM tree and construct a new jQuery object from the matching elements. The .children() method differs from .find() in that .children() only travels a single level down the DOM tree while .find() can traverse down multiple levels to select descendant elements as well.
You can use find to perform a search with Jquery lib.
See full doc here : https://api.jquery.com/find/
For your case; you can use :
$( "div.menu-filter-items" ).find( "h4" )

Grabbing number from selected class based on string match

I need to grab the number between [ and ] within the selected class of an li list, and store the number in a variable. I've tried the following, but I'm missing something. I'm not sure of the regex required to look between brackets and grab a string.
Javascript
var assetID = $(".selected:contains('on-air-date').find('[]');
HTML
<ul id="asset-list" class="expandable selectable normal" style="height: 671px;">
<li class="selected">
<div class="thumb">
<a href="/content/assets/750">
<img src="https://www.google.com/images/srpr/logo11w.png">
</a>
</div>
<div class="title">
<div>
<strong>Title of story</strong>
<br>
<span class="on-air-date">
On air: 10/28/14 05:30:00pm
[750]
</span>
<br>
<span class="blue radius label">Staging</span>
<span class="green radius label">Live</span>
</div>
</div>
</li>
<li>
<div class="thumb">
<a href="/content/assets/4200">
<img src="https://www.google.com/images/srpr/logo11w.png">
</a>
</div>
<div class="title">
<div>
<strong>Another story title</strong>
<br>
<span class="on-air-date">
On air: 12/10/14 02:09:18pm
[4200]
</span>
<br>
<span class="blue radius label">type label</span>
</div>
</div>
</li>
<li>
<div class="thumb">
<a href="/content/assets/4201">
<img src="https://www.google.com/images/srpr/logo11w.png">
</a>
</div>
<div class="title">
<div>
<strong>Yet another story title</strong>
<br>
<span class="on-air-date">
On air: 12/10/14 02:09:18pm
[4201]
</span>
<br>
<span class="blue radius label">type label</span>
</div>
</div>
</li>
</ul>
JSFiddle: link
Your current code is invalid, as :contains is used to look for a text value within an element, not a class. You need to use find() and text() to retrieve the value in the element. From there you can use a regular expression to extract the value in the braces. Try this:
var selectedAirDateText = $('.selected').find('.on-air-date').text();
var matches = /\[(.+)\]/gi.exec(selectedAirDateText);
console.log(matches[1]); // = '750'
Example fiddle
A regular expression can help you get the number as follows:
var num = $('.selected span.on-air-date').text().replace(/[^\[]*\[(\d+)\].*/,'$1');
Demo
:contains('on-air-date') not valid, you cannot use contains to access the child elements with the specified class. Also .find('[]') not valid. The following code worked for me:
$('.selected').click(function () {
var assetID = $(this).find('.on-air-date').text().split('[')[1].replace(']', '');
//this first splits the text into two by '['
//then we get the second half by [1]
//finally we remove the last character ']' by using .replace
alert(assetID);
})
Demo: https://jsfiddle.net/k3keq3vL/1/
You'll need to first get the single item you need or run an $.each to get all in the page.
//run the each statement
$(".on-air-date").each(function(index,value) {
//set the string (str) variable to the value's text which is inside the <span>
var str = $(value).text();
// match the string with [ ] with anything inside. and then remove the last ]. Then take the substring of the content after the [
var value = str.match(/\[(.*?)\]/g)[0].replace(/\]/g,'').substring(1,str.length-1));
});
http://jsfiddle.net/k3keq3vL/8/
Open your console to see the list of numbers returned in the console.log of the string match and substring

Categories