I'm very new to javascript & jQuery and I'm having trouble with toggling a class when a button is clicked. The desired output is to have the user add items as they click a button. That works fine. However when they want to check an item off their list, I can't get the font to change to be strike-through when the user clicks the button that is inside the <li>.
I think I'm close but there's something amiss.
Any help is appreciated.
CODE:
function checkItem(element) {
// toggles the class shopping-item__checked when button inside the parent <li> is clicked
element.parent('li').toggleClass('.shopping-item__checked');
console.log(element);
}
// Event listeners
$(document).ready(function () {
console.log("ready!");
$('#js-shopping-list-form').submit(function (event) {
event.preventDefault();
addItem(state, $('#shopping-list-entry').val());
renderList(state, $('.shopping-list'));
});
$('ul.shopping-list > li').click(checkItem($(this).closest('shopping-item')));
});
HTML:
<div class="container">
<h1>Shopping List</h1>
<form id="js-shopping-list-form">
<label for="shopping-list-entry">Add an item</label>
<input type="text" name="shopping-list-entry" id="shopping-list-entry" placeholder="e.g., broccoli">
<button type="submit">Add item</button>
</form>
<ul class="shopping-list">
<li>
<span class="shopping-item">apples</span>
<div class="shopping-item-controls">
<button class="shopping-item-toggle">
<span class="button-label">check</span>
</button>
<button class="shopping-item-delete">
<span class="button-label">delete</span>
</button>
</div>
</li>
remove the '.' from the toggleclass,
function checkItem(element) {
// toggles the class shopping-item__checked when button inside the parent <li> is clicked
element.parent('li').toggleClass('shopping-item__checked');
console.log(element);
}
also u can try the following as alternative
function checkItem(element) {
// toggles the class shopping-item__checked when button inside the parent <li> is clicked
if(element.parent('li').hasClass('shopping-item__checked')){
element.parent('li').removeClass('shopping-item__checked');
}else{
element.parent('li').addClass('shopping-item__checked');
}
console.log(element);
}
You are binding event handlers the wrong way.
$('ul.shopping-list > li').click(checkItem($(this).closest('shopping-item')));
You need to pass the event information in the following manner.
function checkItem(event) {
//event information is passed. target contains the target element on which the event was fired. in this case the check button
var element = $(event.target);
// toggles the class shopping-item__checked when button inside the parent <li> is clicked
//element.parent('li').toggleClass('.shopping-item__checked');
element.closest('li').find('span.shopping-item').css('text-decoration','line-through');
console.log(element);
}
// Event listeners
$(document).ready(function () {
console.log("ready!");
$('#js-shopping-list-form').submit(function (event) {
event.preventDefault();
addItem(state, $('#shopping-list-entry').val());
renderList(state, $('.shopping-list'));
});
//bind each check button with the check item function
$('ul.shopping-list > li > div.shopping-item-controls > button.shopping-item-toggle').on('click', {event_data:this}, checkItem);
});
and modify your html to remove the span inside the button, coz it it's unecessary.
<div class="container">
<h1>Shopping List</h1>
<form id="js-shopping-list-form">
<label for="shopping-list-entry">Add an item</label>
<input type="text" name="shopping-list-entry" id="shopping-list-entry" placeholder="e.g., broccoli">
<button type="submit">Add item</button>
</form>
<ul class="shopping-list">
<li>
<span class="shopping-item">apples</span>
<div class="shopping-item-controls">
<button class="shopping-item-toggle">
<!--<span class="button-label">check</span>-->
<!-- recommend not to use the span, since you will not be able to capture click event of button -->
check
</button>
<button class="shopping-item-delete">
<span class="button-label">delete</span>
</button>
</div>
</li>
the .closest() method finds the closest matching ancestor, while the .find() method finds the closest matching child.
https://coderwall.com/p/wxjljq/jquery-find-and-closest-are-your-best-friends
First things first you are adding the callback function wrong for the jQuery click event.
$('ul.shopping-list > li').click(checkItem($(this).closest('shopping-item')));
You are actually passing in undefined as a callback function because you are calling checkItem() right away and that function returns nothing. So everytime you click on the li elements they do nothing.
Lets fix that by just adding in the function name without any paranthesis. So we are not calling it we are just passing it through as a parameter.
$('ul.shopping-list > li .shopping-item-toggle').click(checkItem);
I have also targeted the check button for the click in this example. Now everytime the button is clicked it will call checkItem and pass in an event object like so: checkItem(event);
Looking at your checkItem function it is expecting an element to be passed through, well lets change that part:
function checkItem(event) {
// toggles the class shopping-item__checked when button inside the parent <li> is clicked
$(this).closest('li').toggleClass('shopping-item__checked');
console.log(this);
}
I changed a few things here. I changed the parameter name from element to event and I changed element.parent('li').blah.blah to $(this).closest('li').blah.blah
this is going to represent the element clicked and I wrap it in a jquery selector so I can chain some stuff to it like the closest and toggleClass methods.
Now I noticed that this is going to work for the first element but its not going to work for elements that you add later. This is because you would have to add a click event to the new list item everytime you call addItem. There is an easier way to do that and it would require us to modify how we add the click event in the first place.
$('ul.shopping-list').on('click', 'li .shopping-item-toggle', checkItem);
This technique that we are using now is called Event Delagation. Now I am actually adding the click event on the entire shopping list and its going fire on all li .shopping-item-toggle items that were clicked inside the shopping list. This means the elements don't yet need to be added at this point for them to have a click event work on it. They can be added later and it will still work. Now when you add new items you can click on them and they will have the click event fire.
Related
I have a html form which contains a button. This button has a .click() event attached within a js file. This was working fine, until I used jquery .html() to substitute my main page content with the form content. The form shows on the page but clicking the button no longer triggers the event. I am wondering why this is? Code below...
html:
<body>
<div id="mainContent">
<!-- Visible page content will show here -->
</div>
<div id="otherScreens">
<form id="loginForm">
<label for="email">Email</label>
<input type="text" id="email" spellcheck="false">
<label for="password">Password</label>
<input type="password" id="password">
<button type="submit" id="signInBtn">Sign In</button>
<ul id="signInMessages"></ul>
</form>
</div>
css:
#otherScreens {
display: none;
}
js:
const mainContentArea = $(document).find('#mainContent');
let onPageContent = $(document).find('#loginForm').html();
$(document).ready(function () {
mainContentArea.html(onPageContent);
});
$('#signInBtn').click(function (event) {
event.preventDefault();
console.log("Hello world!");
}
I tested changing the .click() event to target #mainContent and it triggered upon clicking anywhere within the div on the webpage, as expected. So I'm not quite sure what's happening with the form button?
(does not seem to relate to suggested duplicate Q)
Just put your click function in document.ready(function()
Please check below full jQuery code and replace it with your current code:
const mainContentArea = $(document).find('#mainContent');
let onPageContent = $(document).find('#loginForm').html();
$(document).ready(function () {
mainContentArea.html(onPageContent);
$('#signInBtn').click(function (event) {
event.preventDefault();
console.log("Hello world!");
});
});
Thanks.
This is quite logical (and can be explained). You create an object, wire events to that object - then replace that object with a similar object and you expect the events to magically be wired.. That doesn't happen.
Each time you dynamically add (delete, replace, whatever) elements with events bound to that element, you need the DOM to be aware of that event. Even so, you could even end-up having more than one event wired to the same element.
So let's say (as an example).
function replaceElement(htmlContent) {
$('.mybutton').off('click'); // drop the event handler
$('#mainContent').html(htmlContent); // replace content
// add event handler
$('.mybutton').click(function() {
console.log('yup, working again');
});
}
EDIT with reproducible example, and following T.J. Crowder suggestion below (tnx)
I need a button to be automatically clicked when I click on an element with class 'menu'.
I can get the element on the DOM, length is ok, and when I put a debug watch on it2, all properties seem ok. However, in the application I'm applying it the click event is not fired. In that case the 'menu' items have also their own click event listeners doing their stuff, which might hold the reason. Anyone have an idea why may not be working?
I have a similar working example that I tried, and apparently works
document.querySelectorAll('.menu').forEach(item => {
item.addEventListener('click', event => {
if (document.querySelectorAll('.savebtn').length>0){
var all = document.querySelectorAll('.savebtn');
var it2=all[0];
it2.click();
}
})
})
<ul>
<li><a href="http://www.google.com/search?q=1" target="_blank" class="menu" > link 1</a></li>
<li> link 2</li>
</ul>
<form action="http://www.google.com/search" target="_blank">
<input type="text" name ="q">
<input type="submit" class = "savebtn" value="Submit">
</form>
any help ? Thanks
I'm trying to delete dynamically created elements each with their own delete button. This is the element that gets added with every button click. When the delete button of an element gets clicked I want that specific element to be deleted.
I use the following code to append the element:
$("#addsitem").click(function () {
$("#holdsitems").append('myFunction');
});
This is how I try to remove it:
$("#item").on("click", "#deleteitem", function() {
$("#item").remove();
});
I can only delete the elements that haven't been added.
This is all the relevant HTML code (myFunction) of the element:
<div id="item" class="itemdiv">
<form>
<div>
<div id="deleteitem">
<input type="button" name="Delete Button" value="Delete">
</div>
</div>
</form>
</div>
I'm rather new to jQuery and this is giving me headaches. Would appreciate it lots if someone could help me out!
You can use classes and the command .closest("selector") where this moves up the DOM tree until it finds the first element that matches that selector, you can then remove this.
You shouldn't be adding an id dynamically, unless you are adding an indices so that they are unique.
Demo
// Add new item on click of add button
$("#addsItem").click(function(event) {
// Stop submission of form - this is not necessary if you take it out of the form
event.preventDefault();
// Append new form item
$("#holdsitems").append('<div class="item-wrapper"><button type="button" class="deleteItem" >Delete</button></div>');
});
// Add DYNAMIC click event to class .deleteItem
$(document).on("click", ".deleteItem", function() {
// Move up DOM tree until first incidence of .item-wrapper and remove
$(this).closest(".item-wrapper").remove();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="item" class="itemdiv">
<form>
<div id="holdsitems">
<button id="addsItem">Add Item</button>
<div class="item-wrapper">
<button type="button" class="deleteItem">Delete</button>
</div>
</div>
</form>
</div>
I use the play framework 2.3.8 and I'm trying to change a certain text value next to a button. The button gets dynamically added via a generated list, so I am not able to find the correct text that is next to the button.
This is what it looks like:
My view class gets a list of questions questionList: List[Question] over which I iterate and put a bunch of buttons into my html:
#for(question <- questionList){
<!-- Questions -->
<li class="list-group-item" >
<button type="button" class="btn btn-default" id="upvoteButton"
value="voteUp" style="width: 30px; height: 30px; text-align: center; vertical-align: center;">
<span class="glyphicon glyphicon-arrow-up" aria-hidden="true" style="color:orange"></span>
</button>
<span class="num"> #question.voteScore </span>
(...)
In the class "num" is the actual voteScore for the question which I want to change on a button click. The id-tag is not helping, as the buttons get generated and therefore all have the same id-tag (Sidenote: Only the first id actually works, I guess the first button gets the unique id?).
My approach so far:
If I click on the num itself I can change it's value:
$(document).ready(function(){
$(document).on('click', '.num', function(){
$(this).html(111);
});
});
But trying to accomplish this with a button click fails:
$(document).ready(function(){
$(".btn-default").click(function(){
$(this).slideUp().slideDown();
console.log($('.num').html());
});
});
The output of console.log always is 76, no matter which button I click. I am not able to find the button that is linked to the correct num. How do I accomplish that?
try this:-
$(".btn-default").click(function(){
$(this).slideUp().slideDown();
$(this).next('.num').html('111');
});
or also you can try:-
$(".btn-default").click(function(){
$(this).slideUp().slideDown();
$(this).parent('li').find('.num').html('111');
});
I think that your buttons are not 'visible' while you are doing document.ready init call so I would suggest to add it this way,, to be live or bound to dom after dinamic call ends..
$(document).ready(function(){
$('body').on( 'click', '.btn-default' , function(){
$(this).slideUp().slideDown();
console.log($('.num').html());
});
});
hth, k
I am trying to create a to-do list using HTML/CSS, Javascript and JQuery. The problem I have occurs when I try to delete an item off the list. Here is the Javascript.
$(document).ready(function(){
$('#add').click(function(){
if($('#input').val() != '')
$('.container').append('<p class="todo">'+$('#input').val()+'</p><span class="del">×</span><br/>');
});
$(document).on('click','.del',function(){
$(this).click(function(){
$('.todo').hide();
});
});
});
The HTML
<body>
<h1 class="header">To-Do List</h1>
<hr/>
<br/>
<input type="text" id="input"/>
<button id="add">Add</button>
<br/>
<br/>
<div class="container">
</div>
</body>
What the above does is it removes all of the dynamically generated todo [paragraph] elements when a single del element [an x] is clicked. I am asking how to change the code so clicking the del element removes the todo element that it was generated with. I understand I can use ids but I feel that is too cumbersome. Thanks for the help.
You can use .prev() to hide only the immediate previous sibling .todo paragraph of clicked .del:
$('.container').on('click','.del',function(){
$(this).prev().hide();
});
Also take note that you don't need to use .click() event for .del any more since you've already using event delegation to attach the click event to them as well as using closest static parent for delegated event instead of $(document).
Try this jQuery, this also hides the 'x':
$(document).on('click','.del',function(){
$(this).hide();
$(this).prev().hide();
});