Trigger function based on Class Change - javascript

I have the following. I am trying to trigger the function based on the css class changing but it's not working.
<script type="text/javascript">
jQuery(document).ready(function(){
jQuery("#slider-banner").bind("cssClassChanged",function(){
console.log("I'm Here!");
if(jQuery("#slider-banner").hasClass('living-nutrients'))
{
jQuery("#home-middle-first").css("background-image","url([image path])");
}
else if(jQuery("#slider-banner").hasClass('right-partner'))
{
jQuery("#home-middle-second").css("background-image","url([image path])");
}
else if(jQuery("#slider-banner").hasClass('with-you'))
{
jQuery("#home-middle-third").css("background-image","url([image path])");
}
});
jQuery("#slider-banner").trigger('cssClassChanged');
The colsole displays my console.log message on page load, but not when the class changes again after page load. Anyone see what I'm doing wrong?
UPDATE:
So I've learned that "cssClassChanged" is not legit... I was attempting to adapt an answer I found somewhere else... I do realize that if jQuery were a weapon, I'd be dangerous! (knowing that is half the battle, right?)
My attempt to adapt gdoron's answer linked to below:
<script type="text/javascript">
jQuery(document).ready(function()
{
function checkForChanges()
{
if(jQuery("#slider-banner").hasClass('living-nutrients'))
{
jQuery("#home-middle-first").css("background-image","url([image path])");
}
else if(jQuery("#slider-banner").hasClass('right-partner'))
{
jQuery("#home-middle-second").css("background-image","url([image path])");
}
else if(jQuery("#slider-banner").hasClass('with-you'))
{
jQuery("#home-middle-third").css("background-image","url([image path])");
}
else
setTimeout(checkForChanges, 500);
}
});
</script>
I'm still missing something, though. It only works for the first class on page load.
Someone asked how I'm changing the classes. I'm using a slider and on each slide is a div with the ID "slider-banner" and the class varies depending on which of the three ID'd areas below it that I am trying to switch the background image for.

There is no such event cssClassChanged I think that explains all...
10 hours ago I answered how you can detect class change, read my answer there
Update:
function checkForChanges()
{
var sliderBanner = jQuery("#slider-banner");
if(sliderBanner.hasClass('living-nutrients'))
{
jQuery("#home-middle-first").css("background-image","url([image path])");
}
else if(sliderBanner.hasClass('right-partner'))
{
jQuery("#home-middle-second").css("background-image","url([image path])");
}
else if(sliderBanner.hasClass('with-you'))
{
jQuery("#home-middle-third").css("background-image","url([image path])");
}
setTimeout(checkForChanges, 500);
}
jQuery(checkForChanges);

There is no built-in event named "cssClassChanged". You have created your own custom event, and are triggering it manually during page load. It will not fire automatically -- you'll have to call trigger('cssClassChanged') each time you change the CSS class.

There is no cssClassChanged event that I am aware of, you need to manually trigger it. However, you aren't changing the class in the code you posted, therefore I'm not sure where you would want to trigger it.

you can wire your own click event listener on slideshow (prev/next) buttons - they will be added in addition to the existing ones.
in your event listeners, you can check css-class for whatever element you are interested in.
$(".prev").on("click", function() {
//user has explicitly clicked "prev"!!
});
$(".next").on("click", function() {
//user has explicitly clicked "next"!!
});

Related

How to trigger a class change event when the code that changes the class is out of reach

I need to trigger an event on a class when that class changes
The only known change noticed in the DOM is that the class obtains a second class (say the class is "selectable", it becomes "selectable selected")
https://jsfiddle.net/zn1xj7wb/1/
In this fiddle, the blue squares may be selected and the css change happens when the class changes (adds "selected")
The goal is to be able to do something in another part of my code like that:
$("[class*='selectable']").on('classChange', function() {
//do stuff like change the background color or add text
//alert("this selectable div has been selected");
});
I am unsure how to proceed as jquery has no event for a class change, and I cannot add "classChange" the trigger to the hidden part of the code that adds and removes the "selected" class for it to be picked up by my code.
EDIT: the reason I need the trigger to be the class change is that it is a graph that uses up the first click to change the class (select the node of the graph) and so a first click on the div of that class does not register, only the second time, and I cannot have to click twice to //do stuff.
I'm not sure I understand your problem, but what I would do is atach the event to the document, like this:
$(document).on("click",".selectable", function() {
//do your stuff here
});
Now, as I've read you need to do something right after you add the class "selected" to "selectable", so you could do it in the function by checking wether it has the class or not and then do your stuff after you add the class "selected".
$(document).on("click",".selectable", function() {
if($(this).hasClass("selected")){
$(this).removeClass("selected")
//do your stuff
}else{
$(this).addClass("selected")
//do some different stuff
}
});
EDIT: Okay, so that won't work (see comments). However, I was able to come up with another solution. While you could regularly scan the whole DOM for changes using an external library, in this instance, you can make the app more performant by limiting your scope to just the selectable items.
What the following code does (jsfiddle link below) is take an initial sampling of the selected elements on the page. Then, once per event loop, it re-samples those selected elements. For each element that wasn't there before, it triggers a custom event:
$(document).ready(function() {
$('.selectable').on('customSelectEvent', (e) =>{
console.log("hello, world!");
// Do your stuff here
});
// Get the starting list of selectable elements
var selecteds = $('.selected');
// Using setInterval to make sure this runs at the back of the event loop
setInterval(() => {
let loopSelecteds = $('.selected');
$.each(loopSelecteds, function(loopIndex, loopSelected) {
let alreadySelected = false;
$.each(selecteds, function(index, selected) {
if ($(selected).get(0) === $(loopSelected).get(0)) {
alreadySelected = true;
}
});
if (!alreadySelected) {
$(loopSelected).trigger('customSelectEvent');
}
});
selecteds = loopSelecteds;
}, 0);
})
Some things to note here:
setInterval(()=>{...}, 0) is being used to cast this operation to the back of the event loop, so it will evaluate once per turn. Use caution when doing this, because if you do it too much, it can impact performance.
$().get(0) === $().get(0) is testing the DOM elements to see if they are the same element. We don't want to trigger the event if they are. Credit: https://stackoverflow.com/a/19546658/10430668
I'm using $.each() here because it's intelligent enough to handle collections of jQuery objects, which other loops weren't (without some fiddling).
Someone spot check me on this, but you may be able to put the custom event listener elsewhere in the code.
JS Fiddle: https://jsfiddle.net/zn1xj7wb/15/
This is my first answer, which doesn't work in this use case. I'll include it so that users who aren't so stuck can benefit from it:
Is there any reason you can't bind another listener to the click event
and test if it's got the right class? Such as:
$(document).ready(function() {
$(".selectable").click((e) => {
const currentElement = $(e.currentTarget);
// This is a little tricky: don't run the code if it has the class pre-setTimeout()
if (currentElement.hasClass('selected')) {
return;
}
// Using setTimeout to cast the evaluation to the end of the event loop
setTimeout(()=>{
if (currentElement.hasClass('selected')) {
// Do your things here.
alert("selected!");
}
},0);
})
})

trigger function if scroll reaches a certain point only once. Not every time

I want to check if my users arrive at a certain point in my page. SO I created the following JS code:
$(document).on('scroll', function() {
if($(this).scrollTop()>=$('#page2').position().top){
alert("trigger");
}
})
Which checks if the users reached my id="page2". But I want this to trigger ONLY once, no matter if the users goes back up and back down, right now it gets trigger everytime the page2.position().top = scrollTop.
How can I do this ?
You can use event.namespace and off() to unbind event handler after execution of desired statement.
$(document).on('scroll.something', function() {
if ($(this).scrollTop() >= $('#page2').position().top) {
//Do something
//Unbind the event
$(document).off('scroll.something')
}
})
You can use this code to achieve your desired output.
var checkonce = false;
$(document).on('scroll', function() {
if($(this).scrollTop()>=$('#page2').position().top){
if(checkonce == false) {
alert("trigger");
checkonce = true;
}
}
});
You can just off the scroll event on your document after the first scroll has reached.
Edit: Also it would be better if you name your events, Which will help us remove the specific event by using the name. (Satpal already mentioned this in his answer before me, I am improving my answer standard as well.)
$(document).on('scroll.Page2ScrollEvent', function() {
if($(this).scrollTop()>=$('#page2').position().top){
$(this).off('scroll.Page2ScrollEvent'); // remove specific scroll event.
alert("trigger");
}
})

Jquery help: .click() to each individual element

I've written up this code to add a class (.box-open which adds display:block) to my box (.sharebox) when a button (#share-but) is clicked but the problem is I'm having trouble making this only apply to one .share div at a time because everytime I click a button, all the .shareboxs get the class .box-open applied to it.
function shareBox() {
$('.share').each(function( index ) {
$(this).on('click', '#share-but', function() {
if ($('.sharebox').hasClass('box-open')) {
$('.sharebox').removeClass('box-open');
}
else {
$('.sharebox').addClass('box-open');
}
});
});
}
shareBox();
Here is an image of the problem (I'm building a Tumblr Theme). Hopefully it's a lot easier to understand. http://24.media.tumblr.com/c5c4252607bf4a9905c7c9de5b592c60/tumblr_ml4t2fSuQo1rqce8co1_500.png <---- This happened when I clicked one of the buttons, but I only want one .sharebox to have the class .box-open added to it when I click the #share-but inside the same .share div.
I hope all of this made sense. I'm still very noob at Javascript/Jquery as I only started learning like 2 weeks ago so any help is much appreciated!
You have to use $(this) instead of $('.sharebox') to address source of event
$('.sharebox').addClass('box-open');
Would be
$(this).addClass('box-open');
The id of element is supposed to be unique in document so you can bind click directly to '#share-but', if it is not unique you can bind it like this.
$('.share').on('click', '#share-but', function() {
if ($('.sharebox').hasClass('box-open')) {
$('.sharebox').removeClass('box-open');
}
else {
$('.sharebox').addClass('box-open');
}
});
You can use toggleClass to make it simple, I assume you have single item with id #share-but,
$('#share-but').click(function(){
$(this).toggleClass("box-open");
});
This would be a simpler version, you can toggle the classname :)
$('.share').on("click", "#share-but", function() {
$(this).find(".sharebox").toggleClass('box-open');
});

JavaScript / jQuery not on element

How can i create an action for an element which will change when the user is not over it. mouseover and mouseleave can't be applied in this situation because the element is activated on page load and the mouse location can be outside the element.
Here is the condition:
if mouse is not over element:
close element
else:
do nothing
So what i want to know is how can i check with jQuery/JavaScript if the current mouse position is not on the specific element.
Thanks!!
You could bind the event handler to the body and check for the requested target:
$().ready(function() {
$("body").on('mouseover',function(event) {
if($(event.target).attr('id') === 'yourid' ) {
console.log('do close this element');
} else {
console.log('do nothing');
}
});
});
I would use a global boolean to keep track of whether the mouse is currently hovering over the element or not. Then, you can periodically check that boolean using setInterval (with some reasonable time interval) which will decide whether the element should be hidden or not.
var mouseIsOver = false;
$('#elementId').hover(
function () {
mouseIsOver = true;
},
function () {
mouseIsOver = false;
}
);
setInterval(function() {
if (mouseIsOver == false) {
$('#elementId').fadeOut();
}
}, 250);
There is a brilliant jQuery plugin for just this. It's called jQuery outside events.
Check the homepage here: http://benalman.com/code/projects/jquery-outside-events/docs/files/jquery-ba-outside-events-js.html
The usage is super-simple and straight forward. I'd recommend this with great experience earlier.

jQuery: Can't cache onclick handler?

I've got a step-by-step wizard kind of flow where after each step the information that the user entered for that step collapses down into a brief summary view, and a "Go back" link appears next to it, allowing the user to jump back to that step in the flow if they decide they want to change something.
The problem is, I don't want the "Go Back" links to be clickable while the wizard is animating. To accomplish this I am using a trick that I have used many times before; caching the onclick handler to a different property when I want it to be disabled, and then restoring it when I want it to become clickable again. This is the first time I have tried doing this with jQuery, and for some reason it is not working. My disabling code is:
jQuery.each($("a.goBackLink"), function() {
this._oldOnclick = this.onclick;
this.onclick = function() {alert("disabled!!!");};
$(this).css("color", "lightGray ! important");
});
...and my enabling code is:
jQuery.each($("a.goBackLink"), function() {
this.onclick = this._oldOnclick;
$(this).css("color", "#0000CC ! important");
});
I'm not sure why it's not working (these are good, old-fashioned onclick handlers defined using the onclick attribute on the corresponding link tags). After disabling the links I always get the "disabled!!!" message when clicking them, even after I run the code that should re-enable them. Any ideas?
One other minor issue with this code is that the css() call to change the link color also doesn't appear to be working.
I wouldn't bother swapping around your click handlers. Instead, try adding a conditional check inside of the click handler to see if some target element is currently animating.
if ($('#someElement:animated').length == 0)
{
// nothing is animating, go ahead and do stuff
}
You could probably make this a bit more concise but it should give you an idea... Havent tested it so watch your console for typeos :-)
function initBack(sel){
var s = sel||'a.goBackLink';
jQuery(s).each(function(){
var click = function(e){
// implementation for click
}
$(this).data('handler.click', click);
});
}
function enableBack(sel){
var s = sel||'a.goBackLink';
jQuery(this).each(function(){
var $this = jQuery(this);
if(typeof $this.data('handler.click') == 'function'){
$this.bind('goBack.click', $this.data('handler.click'));
$this.css("color", "lightGray ! important");
}
});
}
function disableBack(sel){
var s = sel||'a.goBackLink';
jQuery(s).each(function(){
var $this = jQuery(this);
$this.unbind('goBack.click');
$this.css("color", "#0000CC ! important");
});
}
jQuery(document).ready(function(){
initBack();
jQuery('#triggerElement').click(function(){
disableBack();
jQuery('#animatedElement').animate({/* ... */ }, function(){
enableBack();
});
});
});

Categories