Show and Hide handlers are applied multiple times on each click - javascript

This is my html code:
<span id="username_{{ member.id }}" onclick="showMembershipData('{{ member.id }}');">{{ member.user.username }}</span>
and this is my jQuery code
function showMembershipData(id)
{
$("#memberInfo_"+id).slideDown();
$("#username_"+id).click(function(){
hideMembershipData(id);
});
}
function hideMembershipData(id) {
$("#memberInfo_" + id).slideUp();
$("#username_" + id).click(function() {
showMembershipData(id);
});
}
I want the user name to be clickable and when clicked open the "more information" pane, or close it if it is opened. What happens now is:
username clicked for 1 time: pane opens.
Clicked 2nd time: pane closes. Up to here is fine...
clicked 3rd time pane opens and closes 2 times in a row (i.e. 4 operations: open, close, open, close)
and so on... Why? What am I doing wrong?

You are assigning handler inside each handler, and you only need to assign handler once or even consider using event delegation $.on(event, selector, handler) if you are adding and removing items.
consider code below, and remove handlers from markup:
add class username to elements with id username_xxx
add class memberInfo to elements with id memeberInfo_xxx
add data-id attribute to elements with id username_xxx
So markup going to look like:
<span class="username" data-id"{{ member.id }}">{{ member.user.username }}</span>
And the script:
$('body').on('click', '.username', function(e) {
var id = $(this).data('id')
$('#memberInfo_'+id).toggle()
})

The problem with your code is that even handlers are been attached multiple times. Basically with jQuery if you do something like
$("#element").click(functionName);
$("#element").click(functionName);
$("#element").click(functionName);
Then clicking the element once will fire functionName thrice! You need to refactor your code a bit to make sure that the event handlers are added and removed appropriately. Try this
function showMembershipData(id)
{
$("#memberInfo_"+id).slideDown();
$("#username_"+id).unbind("click").bind("click",(function(){
hideMembershipData(id);
});
}
function hideMembershipData(id) {
$("#memberInfo_" + id).slideUp();
$("#username_" + id).unbind("click").bind("click",(function() {
showMembershipData(id);
});
}

let's change the code a little bit, shall we
<span
id="username_{{ member.id }}"
class="member"
data-memberid="{{ member.id }}">{{ member.user.username }}</span>
on the jQuery side
$(".member").toggle(
function() { // click - show
var id = $(this).attr("data-memberid");
$("#memberInfo_" + id).stop().slideDown();
},
function() { // click again - hide
var id = $(this).attr("data-memberid");
$("#memberInfo_" + id).stop().slideUp();
});
easy :)

You can make life a whole lot easier by using jQuery's slideToggle() method - try the following:
function showMembershipData(id)
{
$("#memberInfo_"+id).slideToggle();
}
This will toggle the #memberInfo + id (whatever the ID is) when the link is clicked. Can I suggest using jQuery's click() function? (needs a class added to the username span):
$("#username_span").click(function()
{
$("#memberInfo_"+id).slideToggle();
});
Don't forget to add it to your $(document).ready() bit or whatever. Once you've done that, you can remove the onClick from the span.
James

Agree with the guys above...you keep registering the events. If all you're doing is opening and closing one:
$('#clickme').click(function() {
$('#book').slideToggle('slow', function() {
// Animation complete.
});
});
http://api.jquery.com/slideToggle/

Problem here is that you add an event handler each time showMembershipData gets called.
You should make sure only one event handler gets assigned.

It is happenign 2 times in a row because each time you call those functions they bind a click function which fires.
try
$("#username_"+id).click(function(){
var $showHideElement =$("#memberInfo_"+id);
if ($showHideElementis(':visible'){
$showHideElement.slideUp();
}else{
$showHideElement.slideDown();
}
})

Related

javascript click event not firing action

On page load, I have a search box that, once used, populates a div with multiple images. The javascript from the search uses this function to append all images into the div
function appendSomeItems(url, id, name, style) {
return '<div><div class="md-card md-card-hover"> <div id="getImage" class="gallery_grid_item md-card-content"> <img class ="uk-align-center imageClick"></a> <div class="gallery_grid_image_caption"> <span class="gallery_image_title uk-text-truncate">' + name + '</span> <span>' + style + '</span> </div></div></div></div>';
}
This works perfectly. Now I'm trying to make it so that when I click any one of the images it triggers an action (in this case a console log)
$('.imageClick').click(function handleImage() {
console.log(good);
});
However, it does nothing. No error but no console log.
What am I doing wrong here?
You need to use event-delegation in order to bind an event to dynamically created elements:
This approach uses document as the parent element, however, a good practice is to use the closest parent element.
$(document).on('click', '.imageClick', function handleImage() {
console.log(good);
});
Try with .on() to attach event on dynamically created element. This will allow attaching the event to the elements that are added to the body at a later time:
$('body').on('click', '.imageClick' function handleImage() {
console.log(good);
});
The problem is that you are calling $(".imageClick").click() before you dynamically create the items.
This means that jQuery doesn't actually bind the click listener to the items, since when $(".imageClick").click() is run, the elements don't actually exist yet.
Try this:
$("body").on("click", ".imageClick", function handleImage() {
console.log("good");
});
Also see this post for more information: In jQuery, how to attach events to dynamic html elements?

Jquery lag on click function

I've got a table with different columns identified with different classes.
I've also a checkbox binded to every column.
I created a function which is called on the click of any checkbox. In this function I hide/show the column which is linked to this.
It doesn't have any javascript error, and the code is the following:
$(document).ready(function(){
$('ul input').click(function(){
//alert('yooo');
if ($(this).is(':checked')) {
//alert('checked');
$("td."+replaceAll(" ","_",$(this).val())).show();
$("th."+replaceAll(" ","_",$(this).val())).show();
//alert($("td").length);
}
else{
//alert('unselected');
$("td."+replaceAll(" ","_",$(this).val())).hide();
$("th."+replaceAll(" ","_",$(this).val())).hide();
}
});
});
However, after every click, the action has a lag (after many clicks it becomes tooooooo slow, many seconds).
I tried also with .css instead of hide-show, but it doesn't make any change.
I understood that the problem was linked only to checkbox, not on callback or on jquery function. I solved the problem simply by working with radio input, adding a "true" and a "false" radio input for every checkbox that was in the page.
Instead of running the jQuery selector on every click like below:
$("td."+replaceAll(" ","_",$(this).val()))
You could set up some sort of caching like:
var cache = {} //<-- declare this outside your click handler
//add the code below inside your click handler
className = replaceAll(" ","_",$(this).val())
if(!cache[className])
cache[className ] = $("td."+className + ", th."+className); //select all the elements once and store in the cache object
$el = cache[className];
if ($(this).is(':checked'))
$el.show();
else
$el.hide();

To-do list works in the console, but not on the page

I'm making a to-do list application with HTML, CSS, and JavaScript.
I've got a button listed after each to-do (actually a span). When the user clicks the span it should currently gets the id of the span ready to pass to the delete function (which I haven't written yet).
Here is the click event:
$(".delete").click(function(e) {
var clickedtodelete = $(this).attr("id");
console.log("Deleting " + clickedtodelete);
});
When I test the page, I click a span with the class of .delete and should get to the console the following output: Deleting Test To-Do. However, nothing happens.
I do, however, get the correct output to the console if I first type the click event into the console manually. Thus, it can only be an error with getting the script from the page.
All of the other scripts from the same .js page work, however.
Finally, I get a MIME type warning, but I have been told that that will not affect it.
With a to-do list, I imagine the items are being generated dynamically. I suspect that the cause of your problem is that the click events are being bound before the elements you wish to bind them to exist. You can solve this using jQuery's on() method like so:
$(document).on({
click: function(e) {
var clickedtodelete = $(this).attr("id");
console.log("Deleting " + clickedtodelete);
}
}, '.delete');
With this solution, the event is attached to the document (which always exists) and simply checks the target every time it receives an event. This allows events to be added dynamically.
If your elements are added dynamically, you have to use delegation:
$(document).on("click",".delete", function (e) {
var clickedtodelete = $(this).attr("id");
console.log("Deleting " + clickedtodelete);
});
Or you are not waiting for DOM ready:
$(function(){...});
Or you could put your handler code just before the body closing tag:
<script>
$(".delete").click(function (e) {
var clickedtodelete = $(this).attr("id");
console.log("Deleting " + clickedtodelete);
});
</script>
</body>

change div class onclick on another div, and change back on body click

Let me define the problem a little bit more:
i have
<div class="contact">
<div id="form"></div>
<div id="icon"></div>
</div>
i want onclick on #icon, to change the class of .contact to .contactexpand( or just append it).
Then i want that the on body click to change the class back, but of course that shouldnt happen when clicking on the new class .contactexpand, and if possible that clicking on icon again changes the class back again.
I tried numerous examples and combinations but just couldn't get the right result and behavior.
Check this: Working example
Let's go step by step
I want onclick on #icon, to change the class of .contact to .contactexpand( or just append it). […] and if possible that clicking on icon again changes the class back again.
You want to use the toggleClass() method to achieve this. Simply:
$('#icon').on('click', function(e){
$(this).parent()
.toggleClass('contact')
.toggleClass('contactexpand');
});
Then i want that the on body click to change the class back
You will have to make sure that body removes contactexpand class and adds contact. At this point I would just give the container element an id (or class if you prefer), just to make things simpler. Then what you do is pretty simple:
$('body').on('click', function(e){
$('#thisdiv')
.removeClass('contactexpand')
.addClass('contact');
});
but of course that shouldnt happen when clicking on the new class .contactexpand.
This is the step that the other answers missed, I think. Since everywhere you click, you also click on the body element, you will always trigger the click event on the body, hence removing the contactexpand class and adding the contact one.
Enter event.stopPropagation(). This method will make sure that the events doesn't bubble up the DOM, and will not trigger the body click.
$('#thisdiv').on('click', function(e){
e.stopPropagation();
});
Working example
You can add a class to parent element like the following code.
$(".contact #icon").click(function(){
var element = $(this).parent(".contact");
element.removeClass("contact").addClass("contactexpand");
});
I like to the jQuerys toggleClass function like so:
$('#icon').click(function(){
$('#contactbox').toggleClass('contact');
$('#contactbox').toggleClass('contactexpand');
});
Or you could use addClass('className') and removerClass('className') if you would like to apend it rather than toggle it :)
Here is an example: http://jsfiddle.net/aUUkL/
You can also add an onclick event to the body of the page and use hasClass('className') to see whether or not to toggle the class when the body is clicked. You could use something like this (Although I havent tested this bit!):
$('body').click(function(){
if( $('#contactbox').hasClass('contactexpand') ){
$('#contactbox').addClass('contact');
$('#contactbox').removeClass('contactexpand');
}
});
You can do this
$('body').on('click', function(event) {
if ($(event.target).attr('id') == 'icon') {
$(event.target).parent().toggleClass('contactexpand');
} else {
$('.contact').removeClass('contactexpand');
}
});
Check out this jsfiddle
var $contact = $('.contact');
$contact.find('#icon').click(function(e, hide) {
e.stopPropagation();
$contact[hide ? 'removeClass' : 'toggleClass']('contactexpand');
});
$(document).on('click', function(e) {
if (e.srcElement === $contact[0]) return;
$contact.find('#icon').trigger('click', true);
});
http://jsfiddle.net/kZkuH/2/

Issue with selectors & .html() in jquery?

The function associated with the selector stops working when I replace it's contents using .html(). Since I cannot post my original code I've created an example to show what I mean...
Jquery
$(document).ready(function () {
$("#pg_display span").click(function () {
var pageno = $(this).attr("id");
alert(pageno);
var data = "<span id='page1'>1</span><span id='page2'> 2</span><span id='page3'> 3</span>";
$("#pg_display").html(data);
});
});
HTML
<div id="pg_display">
<span id="page1">1</span>
<span id="page2">2</span>
<span id="page3">3</span>
</div>
Is there any way to fix this??...Thanks
Not sure I understand you completely, but if you're asking why .click() functions aren't working on spans that are added later, you'll need to use .live(),
$("#someSelector span").live("click", function(){
# do stuff to spans currently existing
# and those that will exist in the future
});
This will add functionality to any element currently on the page, and any element that is later created. It keeps you have having to re-attach handlers when new elements are created.
You have to re-bind the event after you replace the HTML, because the original DOM element will have disappeared. To allow this, you have to create a named function instead of an anonymous function:
function pgClick() {
var pageno = $(this).attr("id");
alert(pageno);
var data="<span id='page1'>1</span><span id='page2'> 2</span><span id='page3'> 3</span>";
$("#pg_display").html(data);
$("#pg_display span").click(pgClick);
}
$(document).ready(function(){
$("#pg_display span").click(pgClick);
});
That's to be expected, since the DOM elements that had your click handler attached have been replaced with new ones.
The easiest remedy is to use 1.3's new "live" events.
In your situation, you can use 'Event delegation' concept and get it to work.
Event delegation uses the fact that an event generated on a element will keep bubbling up to its parent unless there are no more parents. So instead of binding click event to span, you will find the click event on your #pg_display div.
$(document).ready(
function()
{
$("#pg_display").click(
function(ev)
{
//As we are binding click event to the DIV, we need to find out the
//'target' which was clicked.
var target = $(ev.target);
//If it's not span, don't do anything.
if(!target.is('span'))
return;
alert('page #' + ev.target.id);
var data="<span id='page1'>1</span><span id='page2'>2</span><span id='page3'>3</span>";
$("#pg_display").html(data);
}
);
}
);
Working demo: http://jsbin.com/imuye
Code: http://jsbin.com/imuye/edit
The above code has additional advantage that instead of binding 3 event handlers, it only binds one.
Use the $("#pg_display span").live('click', function....) method instead of .click. Live (available in JQuery 1.3.2) will bind to existing and FUTURE matches whereas the click (as well as .bind) function is only being bound to existing objects and not any new ones. You'll also need (maybe?) to separate the data from the function or you will always add new span tags on each click.
http://docs.jquery.com/Events/live#typefn

Categories

Resources