click event being removed on previous elements - javascript

answer:
/* I bound the events via the parent instead of binding it
on each span tag individually. this allowed me to manipulate
the span tags uniquely. ( thank you Jason P ) */
$( '.selected-option-wrapper' ).on( 'click', 'span', function() { });
disclaimer:
I am losing my mind.
details:
I am trying to list in html a bunch a options that a user selected via a ul/li dropdown. I want the user to click on a li a and have part of the html within the a tag, placed in a separate div.
For example:
html
// html within the li tag that I want cloned over
<a id="met" class="item-1" href="#">
<div class="left check-wrapper">
<span class="gicon-ok"></span>
</div>
<div class="hide item-display"> // exact element to be moved over
<span class="gicon-remove-sign left remove-option-item"></span>
<div class="left">Metallic Thread</div>
</a>
javascript
$( '.options' ).find( 'a' ).on( 'click', function( e ) {
ind_option_html = $( this ).find( '.item-display' ).clone();
/* attach a click event to the span tag */
ind_option_html.find( 'span' ).on( 'click', function() {
console.log( this );
});
/* this is in a $.each loop that appends each new ind_option_html */
$( '.selected-option-wrapper' ).show().append( ind_option_html );
});
problem
whenever I click just one li a the function fires fine, the this for the span tag is logged out. but what is amazing is that when a user clicks another li a the click event is placed on ONLY the most recent span tag.
Where is the onclick event going with the first span tag?

I'm not sure why you're having the problem you are, but you can probably avoid it using event delegation. Instead of binding the event handler each time, do it like this when the DOM is ready:
$('.selected-option-wrapper').on('click', 'span', function() { ... });
See on(), and the section about direct and delegated events.

Where is the initial var ind_option_html (or is it an accidental global)? Looks like all of the instances of the click handler use the same reference, which is always the last one to be processed.
So your fix would be:
ind_option_html = $( this ).find( '.item-display' ).clone();
to:
var ind_option_html = $( this ).find( '.item-display' ).clone();

Related

How to sync slideToggle() elements so they expand/collapse all together regardless of current state?

I'm trying to show/hide sections using triggers based on classes. So it's easy to throw the trigger class on any element and it will slideToggle the next show/hide element class in the DOM.
The first part works fine. Now I'm adding a trigger to expand/collapse ALL elements. Trouble is, I can't figure out how to sync their states.
For example: I click on 3 of 8 elements so they slide open and become visible, the other 5 are still closed... Now when I click my expand/collapse all trigger, using slideToggle just switches their states so I end up with 3 closed and 5 open.
How do I get their states to sync regardless of what their current state is?
I've been trying to figure out the conditionals to check if the trigger has the opened or close class on it, then toggle the next element, but I've only made a mess so far.
Here's my code:
jQuery( document ).ready( function( $ ) {
// The element to hide/reveal
$( '.bodhi-hide-reveal' ).hide();
// The trigger to hide/reveal
$( '.bodhi-reveal-trigger' ).click( function( e ) {
e.preventDefault();
// Target only the next element to hide/reveal and toggle it
$( this ).next( '.bodhi-hide-reveal' ).slideToggle();
// Toggle the trigger class
$( '.bodhi-reveal-trigger' ).toggleClass( 'opened closed' );
});
// Expand/collapse all button
$( '.expand-collapse-all' ).click( function( e ) {
e.preventDefault();
// Find all hide/reveal elements and toggle them all together
$( 'body' ).find( '.bodhi-hide-reveal' ).slideToggle();
});
});
Just a class named "opened" is enough to detect if the next div is open or close. So I write an IF/ELSE block to decide whether to slideUp or SlideDown. Also you have to decide what would you do when some of divs are expanded? Do you want to collapse all or expand all? I prefer to collapse all first. So I search to find an opened one (using array length) and if I find it, I collapse all divs, elsewhere I expand all:
Also there are some inefficient selectors like $( 'body' ).find(). I also replace those selectors with efficient ones:
jQuery( document ).ready( function( $ ) {
// The element to hide/reveal
$('.bodhi-hide-reveal').hide();
$('.bodhi-reveal-trigger').removeClass("opened");
// The trigger to hide/reveal
$('.bodhi-reveal-trigger').click( function( e ) {
e.preventDefault();
// Target only the next element to hide/reveal and toggle it
$(this).next('.bodhi-hide-reveal').slideToggle();
// Toggle the trigger class
$(this).toggleClass('opened');
});
// Expand/collapse all button
$('.expand-collapse-all').click( function( e ) {
e.preventDefault();
//Check if there is at least one open div:
if ($('.bodhi-reveal-trigger.opened').length){
$('.bodhi-reveal-trigger').removeClass("opened")
$('.bodhi-hide-reveal').stop().slideUp();
}
else {
$('.bodhi-reveal-trigger').addClass("opened")
$('.bodhi-hide-reveal').stop().slideDown();
}
});
});

why i can't toggle classes?

I work on a small to-do list that you can add new task then when you click on the li element it should add 2 classes and remove 1
<ul id="myUL" class="todoList">
<li class='todoList card border-primary'>my li</li>
</ul>
this is my js code for toggling classes
$( "#myUL" ).children().on("click",function() {
$( this ).toggleClass( "checked" );
$( this ).toggleClass( "border-primary" );
$( this ).toggleClass( "border-success" );
});
I included it in the bottom bootstrap.min ,and jquery-3.3.1.min js files because it dependencies for bootstrap.
But my code works only on the first element. How can I fix it ?
This works only on the first element because you run the JS code to attach eventlisteners only once. Thus, only the first element has the 'click' eventlistener attached to it.
You can add a listener to the parent and then handle it from there.
Or, alternative is remove all the eventlisteners of all li's and then re-add them using the code you have right now. This is not a good practice but will get the work done.
Here is a example from w3schools
// Add a "checked" symbol when clicking on a list item
var list = document.querySelector('ul');
list.addEventListener('click', function(ev) {
if (ev.target.tagName === 'LI') {
ev.target.classList.toggle('checked');
}
}, false);
Source: https://www.w3schools.com/howto/howto_js_todolist.asp
Have you tried something like this?
$("#myUL li").click(function() {
$(this).toggleClass("checked");
$(this).toggleClass("border-primary");
$(this).toggleClass("border-success");
});

jquery and Jplist jquery plugin table data with many pages

$( '#list' ).on( "click", ".list-item", function( event ) {
event.preventDefault();
console.log( "toto" + $(this).text());
var $this = this;
$(this).addClass('selected');
$('.list-item').not($this).removeClass('selected');
});
Hello, I have a problem with the line $('.list-item').not($this).removeClass('selected'); which doesn't work for div present in another pages when navigated. thank you for your help.
I don't know that particular plugin, but I looked into it and it seems it caches the 'other' pages somewhere while they are not displayed. At the moment your script is executed the elements are not existing in the DOM.
You will have to run a code similar to yours everytime the plugin loads a page:
// event "loadNewPage" is not an actual event; you will have to figure out which callbacks/hooks/events your plugin offers
$( '#list' ).on( "loadNewPage", function( event ) {
$('.list-item').removeClass('selected');
});
This only works if your changes are cached as well, otherwise you will have to save the selected element in your javascript and reselect it everytime the plugin displays a page.
In the JPList plugin, when you navigate only the content of the div elements are replaced and not the complete div. So, you'll have to reset the selected class upon navigation or any such event.
While initializing the plugin with default options use 'redrawCallback'
i.e.,
redrawCallback: function() {
$('.list .selected').removeClass('.selected');
}
The above code will reset the selected class upon the div.
and also update your code to be
$( '#list' ).on( "click", ".list-item", function( event ) {
$('.list .selected').removeClass('selected');
event.preventDefault();
console.log( "toto" + $(this).text());
var $this = this;
$(this).addClass('selected');
});
Try this approach, as this would first remove the existing selected class from the elements and add selected class to clicked element

Prevent parent click from firing if a specific child is click

I want to prevent my parent click method to fire if the user clicks on a specific child element.
Example html:
<div data-type="parent_holder" style="width:500px; height:500px;">
<div data-type="child_holder" style="width:50px; height:50px; position:absolute;">
click
</div>
</div>
Example js:
I use jquery on in my js because I attach the element dynamically to a sortable list.
$( "#sortable" ).on( "click", "[data-type=parent_holder]", function() {
alert('parent');
});
$( "#sortable" ).on( "click", "[data-type=child_holder]", function() {
alert('child');
});
So what I want is, when a user clicks on the parent_holder it should alert parent, but if the user clicks on the child_holder it should alert child, and not alert parent.
I have searched stackoverflow and I have tried many of the suggestions, like :not(), bubbling, stopPropagation(), but I can't seem to get the right result.
Sounds like event propagation is happening in your case,
just avoid that by using event.stopPropagation()
Try,
$( "#sortable" ).on( "click", "[data-type=child_holder]", function(e) {
e.stopPropagation();
alert('child');
});
DEMO
Use:
e.stopPropagation();
or
return false;
in child click handler to prevent event propagation from parent events.
If for some reason you still need the click event to bubble from child element, you could filter instead the target inside parent click handler:
$( "#sortable" ).on( "click", "[data-type=parent_holder]", function(e) {
if(!$(e.target).is('[data-type=parent_holder]')) return;
alert('parent');
});
--DEMO--

Check if any element is appended to parent

I am cloning a div and appending it to a parent div on different button click. this cloning and appending event is happening from different different JS files, so I want an event to be triggered when element is added to parent div. One method is to go and add the same code or call a function different places. I was wondering if there is an inbuilt function in jquery which will be triggered when any child is appended to it. Following is my code(Fiddle)
JS/Jquery:
$('.but').on('click',function(){
$('.sample').clone(true)
.removeClass('sample')
.addClass($(this).text())
.appendTo($('.parent'));
$('.rem').fadeIn();
});
$('.rem').on('click',function(){
$('.parent').children('.com:last-child').remove();
});
/*this is my conventional code this will be trigged every time when new element is added to parent div
if(elements are increased in parent div){
do your thing
}
*/
HTML:
<div class="button-wrp">
<div class="but cm">red</div>
<div class="but cm">green</div>
<div class="but cm">blue</div>
<div class="rem cm">Remove</div>
</div>
<div class="parent"></div>
<div class="sample com"></div>
If you want to see all this thing working, please click on fiddle link
You can use the jQuery event system. This would the idea:
First you set your listener:
$( 'div' ).on( 'child_appended', function(){
// this is your parent with a new child
var parent_with_new_child = this;
} );
And then when you append a new child you can to this:
$( '.parent' ).append( $( '.child' ) ).trigger( 'child_appended' );
For more reference go here

Categories