Get Ancestor by class name - javascript

I have a component which have buttons and list both of which perform events on click. I need a common way to get the ancestor element for these elements. The structure looks like
<div class='a'>
<button class ='b' data-name="hello">
<span class ='c'>clickMe
<span>somehting</span>
</span>
<button>
<ul class ='d'>
<li data-name="about">
<span class ='e'>something here
<span>somehting</span>
</span>
</li>
<li data-name="home">
<span class ='e'>something elser here
<span>somehting</span>
</span>
</li>
</ul>
</div>
I try to get the element button and li because I need to get data-name information.
e.target is the element that was clicked
var targetel = goog.dom.getAncestorByClass(e.target,null,class??);
Not sure how to get the correct element irrespective if its a button or li. Do i need to add a unique class to all the elements ?

Just use e.currentTarget
var result = document.querySelector('#result');
var clickables = document.querySelectorAll('button, li');
//add click listener to elements
for (var i = 0, l = clickables.length; i < l; i++) {
clickables[i].addEventListener('click', getDataName);
}
function getDataName(e) {
var dataName = e.currentTarget.getAttribute('data-name');
result.textContent = dataName;
}
<div class='a'>
<button class ='b' data-name="hello">
<span class ='c'>clickMe
<span>somehting</span>
</span>
</button>
<ul class ='d'>
<li data-name="about">
<span class ='e'>something here
<span>somehting</span>
</span>
</li>
<li data-name="home">
<span class ='e'>something elser here
<span>somehting</span>
</span>
</li>
</ul>
</div>
<div id="result">data-name of clicked element goes here</div>

https://api.jquery.com/parents/
Use the jquery.parents("li") function. it will select all the parents that match your css filter. so you can do
var parentli = targete1.parents("li");
var button = targete1.parents("div").children[0];
Or something similar to that.
EDIT:
Not sure why i got downvoted, here is my idea in action.
maybe press f12 to inspect element and look at the console log.
var onClick = function () {
var parentEl = $(this).parents("button, li")[0];
console.log(parentEl);
$("#result")[0].innerText = parentEl.getAttribute("data-name");
};
$('span.c').click(onClick);
$('li span.e').click(onClick);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='a'>
<button class='b' data-name="hello">
<span class='c'>clickMe
<span>something</span>
</span>
</button>
<ul class ='d'>
<li data-name="about">
<span class ='e'>something here
<span>somehting</span>
</span>
</li>
<li data-name="home">
<span class ='e'>something elser here
<span>something</span>
</span>
</li>
</ul>
</div>
<div id="result">result goes here</div>

Related

Javascript indexOf a list for a targeted event in a unordered list giving the wrong index

I am trying to get the index number of a 'li' element of a 'ul' from the html.
To do this I change the 'ul' into a list to get his children with:
[...ul.children]
However when I target any of the children I get a -1 as index instead of the correct index.
How to fix?
Is this due to the fact that the list items it's not empty and has a div or other elements inside?
Here is my javascript and my html:
const ul = document.querySelector('ul');
ul.addEventListener('click', myFunc);
function myFunc(e) {
const indexToShow = [...ul.children].indexOf(e.target);
console.log(indexToShow);
console.log(e.target);
}
<ul class="calendar-list">
<li class="list-item">
<div class="fight-link">
<span class="date">1 Dec 2022</span>
<span class="fighters-name">JAY</span>
</div>
</li>
<li class="list-item">
<div class="fight-link">
<span class="date">2 Dec 2022</span>
<span class="fighters-name">Jo</span>
</div>
</li>
<li class="list-item">
<div class="fight-link">
<span class="date">3 Dec 2022</span>
<span class="fighters-name">Bob</span>
</div>
</li>
</ul>
The click evennt triggers on the span, but you're comparing against the li.
So you'll need to search for the li using closest() to match the elements:
const ul = document.querySelector('ul');
ul.addEventListener('click', myFunc);
function myFunc(e) {
const indexToShow = [...ul.children].indexOf(e.target.closest('li'));
console.log(indexToShow);
}
<ul class="calendar-list">
<li class="list-item">
<div class="fight-link">
<span class="date">1 Dec 2022</span>
<span class="fighters-name">JAY</span>
</div>
</li>
<li class="list-item">
<div class="fight-link">
<span class="date">2 Dec 2022</span>
<span class="fighters-name">Jo</span>
</div>
</li>
<li class="list-item">
<div class="fight-link">
<span class="date">3 Dec 2022</span>
<span class="fighters-name">Bob</span>
</div>
</li>
</ul>
here is how you can achive this
const ul = document.querySelector('ul');
ul.addEventListener('click', myFunc);
function myFunc(e) {
const indexToShow = [...ul.children].indexOf(e.path[2]);
console.log(indexToShow);
console.log(e.target);
}

Toggle class between list elements on click of a button

I need to remove and add a class between elements of a list, if I hit the #swapThumb button it should remove the selected class from the current element and then added to the next element.
Here's what I have
html
<ul id="product-thumbnails" class="thumbnails list-inline">
<li class="vtmb vt-123 selected" style="">
<img src="https://via.placeholder.com/100x100">
</li>
<li class="vtmb vt-456" style="">
<img src="https://via.placeholder.com/100x100">
</li>
<li class="vtmb vt-789" style="display: none">
<img src="https://via.placeholder.com/100x100">
</li>
<li class="vtmb vt-101" style="">
<img src="https://via.placeholder.com/100x100">
</li>
<li class="vtmb vt-121" style="display: none">
<img src="https://via.placeholder.com/100x100">
</li>
</ul>
<button id="swapThumb">Next</button>
javascript
let thumbsNailsList = $('#product-thumbnails').find('li');
let swapButton = $('#swapThumb');
thumbsNailsList.each((index, item) => {
let thumbsAvailable = $(item).attr('style');
if (thumbsAvailable === '') {
$(swapButton).on('click', () => {
$(item).removeClass('selected');
$(item).closest($(item)).next().addClass('selected');
});
}
});
First I'm checking if the li element has an empty style attribute (this is needed), if so, trigger the click validation.
The click should remove the selected class from the first element and then added to the next one and so on (it should match the empty style attribute). Once the selected class hits the last element of the list it should return the class to the first element.
This code snippet will change the class of the element beneath it to selected and remove it from the current one, while keeping all the other classes. It will also loop back to the beginning element if next is clicked when on the last element. I've heard jQuery functions are more expensive that document functions and shouldn't be used for these kinds of things. Apply this to your problem and you should get the expected result
let i = 0;
let thumbsNailsList = document.getElementById("product-thumbnails").children;
let btn = document.getElementById("btn");
btn.onclick = function() {
var prevClasses = thumbsNailsList[i].className;
thumbsNailsList[i].className = prevClasses.replace("selected", "");
i = (i+1) % thumbsNailsList.length;
thumbsNailsList[i].className = "selected";
console.log(thumbsNailsList);
}
<ul id="product-thumbnails">
<li class='selected'></li>
<li class=''></li>
<li class=''></li>
<li class=''></li>
</ul>
<button id="btn">Next</button>

jQuery if list item contains ''-" .remove()?

I am restyling a list of related articles in a li and I would like to remove the "-" between the a tag and span without messing with the original content on the page (links). I must use jQuery and I'm not sure if there is a simple way of doing this.
<div class="related-articles card">
<h3 class="h2">
<i class="fa fa-book text-brand-primary-dark"></i> Related Articles
</h3>
<ul>
<li>
Title One
-
<span> Some Related Preview Text... </span>
</li>
<li>
Title Two
-
<span> Some Related Preview Text... </span>
</li>
<li>
Title Three
-
<span> Some RelatedPreview Text... </span>
</li>
</ul>
Here is my solution, get the children elements and assign it back, so the plain text present (-) will get removed!
$('.related-articles li').each(function() {
$(this).html($(this).children());
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="related-articles card">
<h3 class="h2">
<i class="fa fa-book text-brand-primary-dark"></i> Related Articles
</h3>
<ul>
<li>
Title One -
<span> Some Related Preview Text... </span>
</li>
<li>
Title Two -
<span> Some Related Preview Text... </span>
</li>
<li>
Title Three -
<span> Some RelatedPreview Text... </span>
</li>
</ul>
One way would be to loop through each <li>, extract the <a> and <span> elements and stitch them together manually, like this:
$("ul > li").each( (i, li) => {
const $li = $(li);
const $a = $li.find("a");
const $span = $li.find("span");
//create a temp element with just the <a> and <span>
const $tempItem = $("<li></li>");
$tempItem.append( $a ).append( $span );
//copy new HTML into old element
$li.html( $tempItem.html () );
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>
Title One
-
<span> Some Related Preview Text... </span>
</li>
<li>
Title Two
-
<span> Some Related Preview Text... </span>
</li>
<li>
Title Three
-
<span> Some RelatedPreview Text... </span>
</li>
</ul>
One option is:
$('.related-articles li a').map(function() {
return this.nextSibling;
}).remove();

jQuery select multiple same attribute value

I want select DOMs using jQuery.
HTML code
<li>
<span class="node>
<span class="con"></span>
<span class="check"></span>
<img>
<a title="high">abc</a>
</span>
</li>
<li>
<span class="node>
<span class="con"></span>
<span class="check"></span>
<img>
<a title="high">def</a>
</span>
</li>
<li>
<span class="node>
<span class="con"></span>
<span class="check"></span>
<img>
<a title="low">zwc</a>
</span>
</li>
I want select "check" class span DOMs what have "a tag" has "high" title in same level.
I tried to click that DOMs using this query:
$('a[title="high"]').each(function() {
$(this).prev().prev().click();
})
but this code have only first match value.
How can I select all DOMs?
My mistake. I want "check" not "con". Thanks.
The point of this question is "all" DOMs what have "high" title attr should be clicked.
you can use .closest().find()
$('a[title="high"]').each(function() {
$(this).closest('.node').find('.con').click();
})
Working Demo
You can use filter() to filter out elements from a set based on condition.
// Get all spans having class `con`
$('span.con').filter(function () {
// If this element has anchor element sibling with `high` as Title
// then return true, else return false
return $(this).siblings('a[title="high"]').length;
}).css('color', 'green');
$('span.con').filter(function() {
return $(this).siblings('a[title="high"]').length;
}).css('color', 'green');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul>
<li>
<span class="node">
<span class="con">First</span>
<span class="check"></span>
<img>
<a title="high">abc</a>
</span>
</li>
<li>
<span class="node">
<span class="con">Second</span>
<span class="check"></span>
<img>
<a title="high">def</a>
</span>
</li>
<li>
<span class="node">
<span class="con">Third</span>
<span class="check"></span>
<img>
<a title="low">zwc</a>
</span>
</li>
</ul>
Instead of .prev().prev() use siblings() to find the items in the same level and filter with .con.
$('a[title="high"]').each(function() {
$(this).siblings('.con').click();
});
If you want to know why actually your code is not working, you called prev() two times. By first one you select img, the second one will select .check. So you need to call prev() third time to reach .con. This is always confusing and may break anytime if you add more element in between. That's why this approach is not recommended.
As CSS and jQuery don't have previous sibling selector, you can use General sibling selector.
You can use General sibling selectors to select elements having specific attribute and then use jQuery's sibling() to select span.con.
$('span.check ~ a[title="high"]') // Select all anchors having `title` as "high"
// Which are next siblings of `span` having class of `check`
.siblings('span.check') // Select sibling `span` having class `con`
.css('color', 'green');
The selector $('span.check ~ a[title="high"]') will select anchor elements, to get the span, use siblings.
$('span.check ~ a[title="high"]')
.siblings('span.check')
.each(function() {
$(this).css('color', 'green').click();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul>
<li>
<span class="node">
<span class="con">First</span>
<span class="check">First Check</span>
<img>
<a title="high">abc</a>
</span>
</li>
<li>
<span class="node">
<span class="con">Second</span>
<span class="check">Second Check</span>
<img>
<a title="high">def</a>
</span>
</li>
<li>
<span class="node">
<span class="con">Third</span>
<span class="check">Third Check</span>
<img>
<a title="low">zwc</a>
</span>
</li>
</ul>
Actually your code is working fine. See I tried this,
HTML :
<li>
<span class="node>
<span class="con"></span>
<span class="check" onclick="console.log('span :'+1);"></span>
<img onclick="console.log('img :'+1);">
<a id = "m1" title="high" onclick="console.log('a :'+1);">abc</a>
</span>
</li>
<li>
<span class="node>
<span class="con"></span>
<span class="check" onclick="console.log('span :'+2);"></span>
<img onclick="console.log('img :'+2);">
<a id = "m2" title="high" onclick="console.log('a : '+2);">def</a>
</span>
</li>
<li>
<span class="node>
<span class="con"></span>
<span class="check" onclick="console.log('span : low');"></span>
<img onclick="console.log('img : low');">
<a id = "m3" title="low" onclick="console.log('low');">zwc</a>
</span>
</li>
JS:
$(function(){
$('a[title="high"]').each(function() {
// if you want to click all <a>
$(this).click();
// if you want to click all <img>
$(this).prev().click();
// if you want to click all <span> having class check
$(this).prev().prev().click();
});});
Console:
a :1
img :1
span :1
a : 2
img :2
span :2

Edit and Delete option in Div Using Javascript

I have a ul consisting of several li's in it. Now I wanted to add Edit And Delete option infront of every li so that it can be Edited or Deleted on click.
How can i do this ?
Thanks in Advance for any help :)
See this DEMO
$('ul li').each(function () {
$(this).append('<a class="delete" href="#">Delete</a> Edit')
});
$('ul li a.delete').on('click', function () {
$(this).parent().remove();
return false;
});
$('ul li a.edit').on('click', function () {
var val = $(this).siblings('span').html();
if (val) {
$(this).parent().prepend('<input type="text" class="txt" value="' + val + '" />');
$(this).siblings('span').remove();
$(this).html('Update');
} else {
var $txt = $(this).siblings().filter(function() { return $(this).hasClass('txt') });
$(this).parent().prepend('<span class="lead justified">' + $txt.val() + '</span>');
$txt.remove();
$(this).html('Edit');
}
return false;
});
I strongly suggest you use Jquery or another library to handle cross browser issues. Anyway, here is the solution with pure javascript... it should work in all modern browsers recent versions.
SOLUTION DEMO
HTML
<ul class="fa-ul">
<li>
<span> BE/ BTech/ MCS </span>
<button class="remove">Delete</button>
<button class="edit">Edit</button>
</li>
<li>
<span> Solid </span>
<button class="remove">Delete</button>
<button class="edit">Edit</button>
</li>
<li>
<span> Strong </span>
<button class="remove">Delete</button>
<button class="edit">Edit</button>
</li>
<li>
<span> Sharp </span>
<button class="remove">Delete</button>
<button class="edit">Edit</button>
</li>
<li>
<span> Ability</span>
<button class="remove">Delete</button>
<button class="edit">Edit</button>
</li>
<li>
<span> Deal problems</span>
<button class="remove">Delete</button>
<button class="edit">Edit</button>
</li>
<li>
<span> Strong </span>
<button class="remove">Delete</button>
<button class="edit">Edit</button>
</li>
<li>
<span> Excellent </span>
<button class="remove">Delete</button>
<button class="edit">Edit</button>
</li>
</ul>
JS
var removeClassElements = document.getElementsByClassName('remove');
for(var i = 0; i < removeClassElements.length; i++){
var element = removeClassElements[i];
element.addEventListener('click', remove);
}
var editClassElements = document.getElementsByClassName('edit');
for(var i = 0; i < editClassElements.length; i++){
var element = editClassElements[i];
element.addEventListener('click', edit);
}
function remove() {
var li = this.parentNode;
var ul = li.parentNode;
ul.removeChild(li);
}
function edit() {
var li = this.parentNode;
var span = li.children[0];
span.setAttribute('contenteditable', true);
span.focus();
}
PS: You don't need class="lead justified" in each li element. You can use a CSS rule like this:
.fa-ul li span:first-child {...}
You can use CSS trick to perform inplace edit on span's and jQuery#remove() for deleting li's.
Idea is to hide the text when Edit is clicked and show textbox and vice-versa on click of Delete.
$('button.edit').click(function(){
var label_element = $(this).parent().find('span'),
input_element = $(this).parent().find('input');
label_element.addClass('editing');
input_element.val(label_element.text());
input_element.addClass('editing');
});
$('button.delete').click(function(){
$(this).parent().remove();
});
$('input').blur(function(){
var label_element = $(this).parent().find('span');
label_element.text($(this).val());
$(this).removeClass('editing');
label_element.removeClass('editing');
});
Fiddle DEMO
<ul class="fa-ul">
<li><span class="lead justified"> BE/ BTech/ MCS </span>DeleteEdit</li>...
The function edit(this) is given incorrectly and this links to <a>Edit</a>.
You should add id property to the <span>.
<li><span class="lead justified" id="foo"> BE/ BTech/ MCS </span>DeleteEdit</li>
<script>
function edit(target) {
target.contenteditable = true;
}
</script>
You need do change some changes in your markups, You can take <div> instead of <span> and can apply HTML5's attribute contenteditable
Sample Markup
<li>
<div class="lead justified">BE/ BTech/ MCS</div>
Delete
Edit
</li>
Script
Edit
function edit(elem){
$(elem).siblings('div.lead').attr('contenteditable',true);
}
Delete
function remove(elem){
$(elem).closest('li').remove(); // Deletes li
return false;
}
Fiddle Demo

Categories