JavaScript .closest returning null - javascript

I have the following simple layout which I am unable to change. I am trying to use JavaScript to get the extra element which is closest to the button that was pressed
With help from another question I was able to get the preventDefault part working but now I am struggling with closest
<div class="buttons">
<div class="button">
<button class="myButton">Click Me</button>
<div class="extra">64736</div>
</div>
<div class="button">
<button class="myButton">Click Me</button>
<div class="extra">5446</div>
</div>
<div class="button">
<button class="myButton">Click Me</button>
<div class="extra">78667</div>
</div>
</div>
document.querySelector('.myButton').addEventListener('click', myFunction);
function myFunction() {
event.preventDefault();
close = this.closest(".extra");
console.log(close)
}
But this is giving me null when I press the button, where am I going wrong?

A combination of closest and querySelector can be used:
document.querySelectorAll('.myButton').forEach(function(button) {
button.addEventListener('click', myFunction);
});
function myFunction(evt) {
evt.preventDefault();
var closest = evt.currentTarget.closest(".button").querySelector('.extra');
console.log(closest)
}
<div class="buttons">
<div class="button">
<button class="myButton">Click Me</button>
<div class="extra">64736</div>
</div>
<div class="button">
<button class="myButton">Click Me</button>
<div class="extra">5446</div>
</div>
<div class="button">
<button class="myButton">Click Me</button>
<div class="extra">78667</div>
</div>
</div>
More info:
https://developer.mozilla.org/en-US/docs/Web/API/Element/closest
https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector

.closest traverses up the dom and does not look at sibling or child elements. In the answer by #MaartenDev he is using .closest to step up one level and target the buttons parent div. He then chains queryselector to step back down into the children and select using the .extra class.
Another solution would be to use .nextElementSibling so you do not have to step up and back down. This would only work if your html elements were direct siblings and the item you were trying to target followed the element you were calling nextElementSibling on.
Here is an example of this.
document.querySelectorAll('.myButton').forEach(function(button){
button.addEventListener('click',myFunction);
})
function myFunction() {
event.preventDefault();
var closest = this.nextElementSibling;
console.log(closest);
}
<div class="buttons">
<div class="button">
<button class="myButton">Click Me</button>
<div class="extra">64736</div>
</div>
<div class="button">
<button class="myButton">Click Me</button>
<div class="extra">5446</div>
</div>
<div class="button">
<button class="myButton">Click Me</button>
<div class="extra">78667</div>
</div>
</div>

Related

While clicking one of the three buttons cannot disable the other two jQuery

I'm developing a test. I want to disable two of the three buttons when one of them is clicked and to slideDown() a comment under the buttons when one of the options is chosen. I manage to make comments slide down but cannot disable the other comments when the other buttons are pushed. I'm using jQuery. I have already read many possible solutions but they don't seem to work in my case.
Here's a piece of my code:
<div class="btns">
<button class="btn" id="q1b1" value=0>A</button>
<button class="btn" id="q1b2" value=1>B</button>
<button class="btn" id="q1b3" value=0>C</button>
</div>
<div class="content">
<div class="com" id="q1com1">
<p>
comment1
</p>
</div>
<div class="com" id="q1com2">
<p>
comment2
</p>
</div>
<div class="com" id="q1com3">
<p>
comment3
</p>
</div>
<script>
$(document).ready(function(){
if($('#q1b1').click(function(){
$('#q1com1').slideDown(500);
$('#q1b2', '#q1b3').prop('disabled', true);
}));
else if($('#q1b2').click(function(){
$('#q1com2').slideDown(500);
$('#q1b1', '#q1b3').prop('disabled', true);
}));
else if($('#q1b3').click(function(){
$('#q1com3').slideDown(500);
$('#q1b1', '#q1b2').prop('disabled', true);
}));
});
</script>
</div>
Don't put click event handlers in an if condition. You need to assign each button it's own click handler on load and then run the code when the event happens.
To make this as simple as possible you can assign the same event handler to all the buttons then relate the button to the appropriate .com div by its index. Try this:
$(document).ready(function() {
var $comments = $('.content .com');
var $btns = $('.btn').click(function() {
$btns.not(this).prop('disabled', true);
var index = $(this).index();
$comments.eq(index).slideDown(500);
});
});
.com { display: none; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="btns">
<button class="btn">A</button>
<button class="btn">B</button>
<button class="btn">C</button>
</div>
<div class="content">
<div class="com">
<p>comment1</p>
</div>
<div class="com">
<p>comment2</p>
</div>
<div class="com">
<p>comment3</p>
</div>
</div>
Note that this approach removes the need for id attributes and is therefore infinitely extensible with no maintenance required for the JS logic.
I don't know where you got this structure, but it makes no sense:
if($('#q1b1').click(function(){
//...
}))
A click handler isn't a conditional statement. It doesn't return a boolean value. Any and every example you'll find on using click handlers in jQuery would just assign the handler:
$('#q1b1').click(function(){
//...
});
This structure assigns the function you give it as the "handler" for when that element is clicked. Which means at any point after this line of code executes, if a user clicks the #q1b1 element then this function will execute.
you need to bind click event directly inside document.ready and not inside if/else block.
User comma (,) in single string for multiple jquery selector instead of multiple string separated by comma.
See below code
$(document).ready(function(){
$('#q1b1').click(function(){
$('#q1com1').slideDown(500);
$('#q1b2,#q1b3').prop('disabled', true);
});
$('#q1b2').click(function(){
$('#q1com2').slideDown(500);
$('#q1b1,#q1b3').prop('disabled', true);
});
$('#q1b3').click(function(){
$('#q1com3').slideDown(500);
$('#q1b1,#q1b2').prop('disabled', true);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div class="btns">
<button class="btn" id="q1b1" value=0>A</button>
<button class="btn" id="q1b2" value=1>B</button>
<button class="btn" id="q1b3" value=0>C</button>
</div>
<div class="content">
<div class="com" id="q1com1">
<p>
comment1
</p>
</div>
<div class="com" id="q1com2">
<p>
comment2
</p>
</div>
<div class="com" id="q1com3">
<p>
comment3
</p>
</div>
</div>
$(document).ready(function(){
$('#q1b1').click(function(){
$('#q1com1').slideDown(500);
$('.btn').attr('disabled', true);
$(this).attr('disabled', false);
})
$('#q1b2').click(function(){
$('#q1com2').slideDown(500);
$('.btn').attr('disabled', true);
$(this).attr('disabled', false);
})
$('#q1b3').click(function(){
$('#q1com3').slideDown(500);
$('.btn').attr('disabled', true);
$(this).attr('disabled', false);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="btns">
<button class="btn" id="q1b1" value=0>A</button>
<button class="btn" id="q1b2" value=1>B</button>
<button class="btn" id="q1b3" value=0>C</button>
</div>
<div class="content">
<div class="com" id="q1com1">
<p>
comment1
</p>
</div>
<div class="com" id="q1com2">
<p>
comment2
</p>
</div>
<div class="com" id="q1com3">
<p>
comment3
</p>
</div>
</div>

remove button from second div which will same id(class) button in first div html,jquery

I want to remove <button>.
for example remove second <div> tag <button> when i have to click on second <div> tag <button> like <div class="demo2">
<div class="demo1">
<button id="btn1" class="btn1">Add1</button>
</div>
<div class="demo2">
<button id="btn1" class="btn1">Add1</button>
</div>
<script src="jquery-3.1.1.min.js"></script><script>
$(document).ready(function()
{
alert("aaa");
$("#demo2 .btn1").remove();
});
</script>
I try this Code:
<script>
$(document).ready(function()
{
$("#btn1").remove();
});
</script>
it will remove first <button> but I want to remove second <div>
and <button>
You need .demo2 and not #demo2 since demo2 is a class and
not an id
$(document).ready(function()
{
alert("aaa");
$(".demo2 .btn1").remove();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="demo1">
<button id="btn1" class="btn1">Add1</button>
</div>
<div class="demo2">
<button id="btn1" class="btn1">Add2</button>
</div>
This can also be a little more complicated cond=sider you don't know which id are repeating, in that case you can use a loop like below
$(document).ready(function()
{
$('.demo1 button').each(function(){
var id = $(this).attr('id');
$('.demo2 button').each(function() {
if($(this).attr('id') === id) {
$(this).remove();
}
})
})
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="demo1">
<button id="btn1" class="btn1">Add1</button>
<button id="btn2" class="btn1">Add1</button>
</div>
<div class="demo2">
<button id="btn1" class="btn">Add2</button>
<button id="btn2" class="btn">Add2</button>
<button id="btn3" class="btn">Add2</button>
</div>
Not sure exactly what you want to do, but firstly you can't use an the same id CSS tag twice. If it's just to remove the second button after the alert then just change the id and remove that single button.
$(document).ready(function() {
alert("aaa");
$("#btn2").remove();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="demo1">
<button id="btn1" class="btn1">Add1</button>
</div>
<div class="demo2">
<button id="btn2" class="btn1">Add1</button>
</div>
This is how you can get the context of the i'th element having the same selector:
getElementAt(selector, i) {
return $(selector + ":eq(" + i + ")");
}
and you can use it like this:
getElementAt("[id=btn1]", 1).remove();
The # id operator returns the first element having the given id, as the browser assumes that a unique identifier can be present maximum once in a document. Therefore your HTML is invalid and you should fix it, but if you do not have time now to do that, you can use [id=btn1] instead of #. You can also use document.querySelectorAll("[id=btn1]")[i] if you like.

Hiding an element through DOM traversal

What if it has few parents? (as in grandparents, great grandparents)
<div class="lvl1">
<div class="lvl1.1">
<div class="lvl1.2">
<button class="btn-submit">Click Me</button>
<div class="a1">Hello
<div>
</div>
</div>
<div class="lvl2">
<div class="b1">
<div class="b2">Make me disappear!</div>
</div>
</div>
<div class="lvl3">
<div class="c1">Thank you.
</div>
</div>
JS
$(function(){
$(".btn-submit").click(function() {
$(this).parent(".lvl1").siblings(".lvl2").children(".b2").hide();
});
});
How to use .parent, .parents, .siblings, .children, .next, .prev to show and hide the div?
If I assume that you have that structure repeated and want to remove the one in the same copy as the .btn_submit that was clicked, we go up to the .lvl1 via closest, over to the .lvl2 via .nextAll().first() (or we could just use .next), and then .find the .b2 in there:
$(".btn-submit").click(function() {
$(this).closest(".lvl1").nextAll(".lvl2").first().find(".b2").hide();
});
Your code is very close, just two things that I had to change:
Instead of using .siblings(".lvl2"), which will find all of them, I used .nextAll(".lvl2").first() to just find the one immediately after "this" .lvl1.
I used find instead of children, because children will only go down one level (direct child), not search descendants
I also used closest(".lvl1") so that if you move the .btn_submit deeper into .lvl1, it will continue working.
Live Example:
$(function() {
$(".btn-submit").click(function() {
$(this)
.closest(".lvl1")
.nextAll(".lvl2")
.first()
.find(".b2")
.hide();
});
});
<div class="lvl1">
<button class="btn-submit">Click Me</button>
<div class="a1">Hello
</div>
</div>
<div class="lvl2">
<div class="b1">
<div class="b2">Make me disappear!</div>
</div>
</div>
<div class="lvl3">
<div class="c1">Thank you.
</div>
</div>
<div class="lvl1">
<button class="btn-submit">Click Me</button>
<div class="a1">Hello
</div>
</div>
<div class="lvl2">
<div class="b1">
<div class="b2">Make me disappear!</div>
</div>
</div>
<div class="lvl3">
<div class="c1">Thank you.
</div>
</div>
<div class="lvl1">
<button class="btn-submit">Click Me</button>
<div class="a1">Hello
</div>
</div>
<div class="lvl2">
<div class="b1">
<div class="b2">Make me disappear!</div>
</div>
</div>
<div class="lvl3">
<div class="c1">Thank you.
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
there is possible to disappear div directly using,
$(".b2").hide();
but if you want to use ".parent, .parents, .siblings, .children, .next, .prev",
$(".btn-submit").parent().siblings(".lvl2").children().children(".b2").hide();
need to you children() Two times... because .b2 is not directly child to .lvl2,
another best way to hide ".b2" is,
$(".btn-submit").parent().siblings(".lvl2").find(".b2").hide();
so your Ans is:
$(".btn-submit").click(function() {
$(".btn-submit").parent().siblings(".lvl2").find(".b2").hide();
});
.children selects the children and not descendants of the element. You just need to replace the .children with the .find method and your code will select the target element.

Retrieve a specific parent of child button using jQuery

I have this html structure (very general), the id of the div is added dynamically, by a function that creates sequential objects made this way:
<div id="mydiv1">
<div> Stuff</div>
<div>
<button id="remove"></button>
</div>
</div>
The button "remove" should remove the div where he is, so I have to retrieve the id of the div to do it. I do not know how. How can you make using jQuery? thank you
<form>
<div id="mydiv1">
<div> Stuff</div>
<div>
<button id="remove"></button>
</div>
</div>
<div id="mydiv2">
<div> Stuff</div>
<div>
<button id="remove"></button>
</div>
</div>
</form>
I tried:
("#remove").click(function(event) {
var id = event.target.id;
}
But the result is: "remove" instead of "mydiv1" or "mydiv2"
You should use class instead of id for the buttons (id should be unique):
$('.remove').click(function() {
$(this).closest('div[id^="mydiv"]').remove();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<form>
<div id="mydiv1">
<div>Stuff 1</div>
<div>
<button class="remove">REMOVE</button>
</div>
</div>
<div id="mydiv2">
<div>Stuff 2</div>
<div>
<button class="remove">REMOVE</button>
</div>
</div>
</form>
EDIT: Updated to new code posted by OP
For mydiv2 change button like this:
$(".remove").click(function() {
var id = $(this).data('id');
$("#mydiv"+id).remove();
}
<button class="remove" data-id="2"></button>
Use $(this).parent('div') to get the first parent node of type <div>
$("#remove").click(function(event) {
var parent = $(this).parent('div');
parent.remove();
}
EDIT
So add a class to your divs, let say .divRow for example
<form>
<div id="mydiv1" class="divRow">
<div> Stuff</div>
<div>
<button id="remove"></button>
</div>
</div>
<div id="mydiv2" class="divRow">
<div> Stuff</div>
<div>
<button id="remove"></button>
</div>
</div>
</form>
and your javascript would be in this case
$("#remove").click(function(event) {
var parent = $(this).parent('.divRow'),
id = parent.attr("id");
alert(id);
parent.remove();
}
Try
$('.remove').click(function() {
var id = $(this).parent().parent().attr('id');
//This will give you the id
});
For the next part of your question try this:
$(document).on('click','.remove',function() {
var id = $(this).parent().parent().attr('id');
//This will give you the id
});

Using jQuery html() method in several clicks

I am working on this demo. I am trying to find out why the HTML disappears after using the second button.
As long as you only click on btn #from-content-1 or only on #from-content-2 every thing is fine but if you click on #from-content-1 and then on #from-content-2 and back to the #from-content-1 again, the content disappears!
Here is the code which I have:
<div class="row">
<div class="container">
<div id="dest">Here is the Destination</div>
</div>
</div>
<div class="sr-only">
<div id="content-1">This Is From Content 1</div>
<div id="content-2">This Is From Content 2</div>
</div>
<button class="btn btn-default" id="from-content-1">From Content 1</button>
<button class="btn btn-default" id="from-content-2">From Content 2</button>
and js script is
<script>
$("#from-content-1").on("click",function(){
$("#dest").html($('#content-1'));
});
$("#from-content-2").on("click",function(){
$("#dest").html($('#content-2'));
});
</script>
How can I fix this?
You move the nodes! Do that instead:
<script>
$("#from-content-1").on("click",function(){
$("#dest").html($('#content-1').html());
});
$("#from-content-2").on("click",function(){
$("#dest").html($('#content-2').html());
});
</script>
$("#dest").html($('#content-1')); should be $("#dest").html($('#content-1').html()); and $("#dest").html($('#content-2')); should be $("#dest").html($('#content-2').html());
$("#from-content-1").on("click",function(){
$("#dest").html($('#content-1').html());
});
$("#from-content-2").on("click",function(){
$("#dest").html($('#content-2').html());
});

Categories