applying functions to dynamic content javascript/jquery - javascript

Ok so I'm trying to start/stop a setInterval function by changing the id of an element and applying two different functions to the different id's. here's the code at the moment:
$(document).ready(function(){
var seq
$('#start').click(function(){
$(this).attr('id','stop');
seq=self.setInterval(function(){blah()},125);
});
$('#stop').click(function(){
$(this).attr('id','start');
clearInterval(seq);
});
});
when I click the #start element, the setInterval starts and the id changes to #stop, but if I click again (on the element now called #stop), the code for #start is carried out (another setInterval is added)
thanks
the function 'blah' is just an example of a made up function

When you say:
$('some selector').click(...
That binds a click handler to all elements that match some selector at that moment - it doesn't automatically apply to elements that might match it in future.
To have the handler apply to elements that match the selector at the time of the click event you need to use a delegated event handler, which means attaching the handler to a parent element (or to document if the element has no static parent):
$(document).ready(function(){
var seq
$(document).on('click', '#start', function(){
$(this).attr('id','stop');
seq=self.setInterval(function(){blah()},125);
});
$(document).on('click', '#stop', function(){
$(this).attr('id','start');
clearInterval(seq);
});
});
The .on() method lets you attach "normal" non-delegated handlers or delegated handlers depending on the parameter you pass to it.
The other option is to not change the id and just use a single click handler that tests the current state in some manner:
$(document).ready(function(){
var seq;
$('#start').click(function(){
if (seq) {
clearInterval(seq);
seq = null;
} else
seq=self.setInterval(function(){blah()},125);
});
});

I would NOT change the id since this will not change the event bindings. You generally should never change an elements id tag. The better plan (at least to me) is to set it as a class. Then use html data tags to decide what the state is.
<button type="button" class="buttonClass" data-state="start">Button Text</button>
$(document).ready(function(){
var seq
$('.buttonClass').click(function(){
var state = $(this).data('state');
if(state=='start') {
//do start interval stuff
seq=self.setInterval(function(){blah()},125);
$(this).data('state','stop'); //Change the state now
} else if(state=='stop') {
//do stop interval stuff
clearInterval(seq)
$(this).data('state','start'); //Change the state again
}
});
});

Why don't you just check for the state like this (no need to add event listener to document):
$(document).ready(function(){
var seq;
$('#start').on('click', function(){
if(!$(this).hasClass('running')){
seq=self.setInterval(function(){blah()},125);
$(this).addClass('running');
}
else{
$(this).removeClass('running');
clearInterval(seq);
}
});
});

Related

How to wrap multiple dynamic eventListeners into one?

I just started to learn js and need a little help: I have the following function:
//SET CHAT BEHAVIOR
function chatSettings() {
console.log('ChatSettings called')
function BtnAndScrollBar(texteditor) {
console.log('BTNAndScrollBar called');
const sendBtn = $('.cl.active').find('.sendBtn');
const attachBtn = $('.cl.active').find('.attachBtn');
console.log(sendBtn)
}
function sendAndDeleteMessage(send) {
console.log(send);
}
var sendBtn = $('.cl.active').find('.sendBtn');
sendBtn.mousedown(function () {
sendAndDeleteMessage(this);
});
var textEditor1 = $('.cl.active').find('.chatTextarea');
textEditor1.on('focus change mousedown mouseout keyup mouseup', function (){
console.log(this);
BtnAndScrollBar(this)
});
}
$('document').ready(function () {
console.log('hello');
$('.tabs').tabs();
chatSettings();
});
I prepared a js.fiddle - As you can see from console.log when clicking into the textarea, the eventListener always listens to #cl1, even if .cl.active switches along with the according TAB.
The events in the textarea are just relevant, if .cl is active. My target is to wrap all three eventListener into one and apply the event to the textarea in the active stream, but all I tried went wrong... Can anyone help? #Dontrepeatyourself #DRY
$(".chatTextarea").on(
'focus change mousedown mouseout keyup mouseup',
function (this) {
//this.id can contain the unique id
greatFunction(this);
});
This will bind event individually with unique id found with this keyword and also wraps all event listener into one function but this is better when you want to process each event with same functionality
please let me know if this helps.
Peace
$(".cl textarea").on('focus change mousedown mouseout keyup mouseup', function () {
greatFunction(this)
});
Tada!
P.S. Is there a reason greatFunction is defined inside window.onload?
Try using $(document).ready function to load code when the page loads.
Also use $('textarea #cl1').on to get the textarea with the #cl1 or whichever id you want to use and then call the function after using the .on.
Hope this helps!
Let me know if it works!
$(document).ready(function () {
function greatFunction(elem) {
//do stuff
}
$('textarea').on('focus change mousedown mouseout keyup mouseup', function () {
greatFunction(this)
});
}
First off, I changed the onload to bind with jQuery, so all your logic is doing jQuery bindings, rather than swapping back and forth between jQuery and vanilla javascript. Also, doing an actual binding removes an inline binding.
Next, the binding has been condensed into a single delegate event listener. Since you eluded in your comments that it wasn't working for the active element after the active was moved or added, this reflected that you were dealing with dynamic elements. Delegate event listeners are one way to handle such things.
Delegate event listeners bind on a parent element of the elements that will change, or be created. It then waits for an event to happen on one of it's children. When it gets an event it is listening for, it then checks to see if the element that it originated from matches the child selector (second argument) for the listener. If it does match, it will then process the event for the child element.
Lastly, I added some buttons to swap around the active class, so you could see in the snippet that the event handler will start working for any element that you make active, regardless of it starting out that way.
$(window).on('load', function () {
function greatFunction (elem) {
console.log(elem.value);
}
$(document.body).on(
'focus change mousedown mouseout keyup mouseup',
'.cl.active .chatTextarea',
function () {
greatFunction(this);
}
);
$('.makeActive').on('click', function () {
$('.active').removeClass('active');
$(this).closest('div').addClass('active');
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="cl1" class="cl active"><textarea class="chatTextarea">aa</textarea><button class="makeActive">Make Active</button></div>
<div id="cl2" class="cl"><textarea class="chatTextarea">bb</textarea><button class="makeActive">Make Active</button></div>
<div id="cl3" class="cl"><textarea class="chatTextarea">cc</textarea><button class="makeActive">Make Active</button></div>

jQuery delete trigger conditionally

I was wondering if Javascript or jQuery have a way to delete an event listener. Let's say I want to make a function that I want to trigger only once, for example let's say I want to have a button that shows some hidden elements on the document, I would make this function (assuming the hidden elements have a hidden class that hides them):
jQuery('#toggler').click(function() {
console.log('Hidden elements are now shown');
jQuery('.hidden').removeClass('hidden');
});
Simple enough, right ? Now, my actual problem comes in, I don't want jquery to run that function again and again each time the button is clicked, because the elements are already revealed, so is there a clean way to do it ? So, in this example after clicking the toggler multiple times I want to get only one console message.
I could do jQuery(this).unbind('click'), but this results into removing ALL triggers and I only want to remove the current trigger.
What I usually do when I face such scenarios is solve it like this (which is ugly and doesn't actually prevent code execution, but only handles the code's results) :
var toggler_clicked = false;
jQuery('#toggler').click(function() {
if(toggler_clicked) return;
toggler_clicked = true;
console.log('Hidden elements are now shown');
jQuery('.hidden').removeClass('hidden');
});
Also I don't want to use jQuery's one, because I will have the same problem when I'll need to delete the trigger conditionally, so if you can help please give me a dynamic answer.
Thanks in advance !
You have to name your function like that:
var myFunction = function() {
console.log('Hidden elements are now shown');
jQuery('.hidden').removeClass('hidden');
};
And bind it this way
jQuery('#toggler').click(myFunction);
Then you can unbind it with :
jQuery('#toggler').off('click',myFunction);
Without unbinding the other listeners
You can try this:
var myFunc = function() {
console.log('Hidden elements are now shown');
jQuery('.hidden').removeClass('hidden');
jQuery(this).unbind('click', myFunc);
};
jQuery('#toggler').click(myFunc);
This way of calling unbind is such that only the listener for myFunc handler is removed and not all the events connected to the click on the toggler.
I would use the .on() and its opposite .off() methods to attach/detach the event handler. It is the recommended way since 1.7 instead of the .bind() and .unbind() versions that became deprecated as of jQuery 3.0.
$("#toggler").on("click", function(event) {
console.log('Hidden elements are now shown');
$('.hidden').removeClass('hidden');
// if (/* Add your condition here */) {
$(this).off(event);
// }
});
$("#toggler").on("click", function(event) {
console.log('Hidden elements are now shown');
$('.hidden').removeClass('hidden');
// if (/* Add your condition here */) {
$(this).off(event);
// }
});
.hidden {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="toggler">Toggle</button>
<div class="hidden">
HIDDEN
</div>
Try this
var myFunction = function() {
console.log('Hidden elements are now shown');
jQuery('.hidden').removeClass('hidden');
};
Add the event listener like this:
jQuery('#toggler').addEventListener("click", myFunction);
And remove it like this:
jQuery('#toggler').removeEventListener("click", myFunction);
So all together this will do the trick:
var myFunction = function() {
console.log('Hidden elements are now shown');
jQuery('.hidden').removeClass('hidden');
jQuery('#toggler').removeEventListener("click", myFunction);
};
jQuery('#toggler').addEventListener("click", myFunction);
more about the HTML DOM removeEventListener() Method
Jquery unbind function takes 2 parameters eventType and handler
You can put your event listener into separate function like this:
var clickEventHandler = function(){
//your logic goes here
}
After you add listener as reference:
jQuery('#toggler').click(clickEventHandler);
And then, later, anytime, anywhere you want you can unbind that specific handler:
jQuery('#toggler').unbind('click', clickEventHandler);
What i used to do in the past is toggle the click behavior using css classes, ex i used to set a click listener on the parent and delegate to all of the children something that jquery is doing now by default i believe. Anyway based on the css class it will trigger an event for ex.
$('.some-parent-element').on(
'click',
'the-behavior-css-class',
function() { // do stuff here.... }
)
Now if you want to remove this behavior you can just toggle the class of the element and it should do the job. ex
$('.some-parent-element').on(
'click',
'hide-me-on-click-or-whatever',
function() {
$(this).toggleClass('hide-me-on-click-or-whatever')
// perform the action
}
)
You can check if the element has the class hidden

'.on' click not running function?

I have a function that when it runs new markup is generated on the fly...
$('.search input[type="image"]').on('click', function(){
// Open directions in a map
if($('#TXT_SAddr').val() === ''){
return false;
$('.directions .search').css('background' , '#ff0000');
} else {
var from = $('#TXT_SAddr').val();
var to = $('.postal-code').html();
var directions = 'http://maps.google.com/maps?saddr=' + from + '&daddr=' + to + '&output=embed';
var modal = '<div class="apply-modal modal"><a class="close-apply-now" style="margin-bottom: 20px;"><img src="http://site.co.uk/images/closeModal.png" alt="Close" style="border-width:0px;"></a><div class="holder"><iframe src="'+directions+'" style="border:none; width:100%; height:500px;" border="0"></iframe></div></div>';
$('body').prepend('<div class="modalOverlay"/>' + modal);
$('.modal').animate({
'opacity': 1,
'top': '100px'
}, 700, 'easeOutBack');
}
return false;
});
If you can see, the above generates a div with an anchor under the class name of 'close-apply-now'.
I now want to bind a function to this and I've tried using...
$('a.close-apply-now').on('click', function(){
alert('asdasd');
});
with no luck, can anybody see where I may be going wrong? Not even my alert is working.
Since the close-apply-now div is added dynamically, you need to use event delegation to register the event handler like:
// New way (jQuery 1.7+) - .on(events, selector, handler)
$('body').on('click', 'a.close-apply-now', function(event) {
event.preventDefault();
alert('asdasd');
});
This will attach your click event to any anchors with class close-apply-now within the body element.
The syntax for event delegation is slightly different.
The event need to be bind to an element which is already existing in the dom while the target element selector needs to be passed as the second argument
$(document).on('click', 'a.close-apply-now', function(){
alert('asdasd');
});
The close-apply-now div is added dynamically. You have to add the selector parameter, otherwise the event is directly bound (doesn't work for dynamically loaded content) instead of delegated. See http://api.jquery.com/on/#direct-and-delegated-events
Change your code to
$(document.body).on('click', '.update' ,function(){
The jQuery set receives the event then delegates it to elements matching the selector given as argument. This means that contrary to when using live, the jQuery set elements must exist when you execute the code.
Use jQuery's live() method. Description: Attach an event handler for all elements which match the current selector, now and in the future.
$("a.close-apply-now").live("click", function(){
alert('asdasd');
});
Try Both in Jsfiddle

Trapping all `a` clicks including ones added dynamcally

I know you can bind to click events with jQuery like so:
$('a').click(function(){});
But what about html elements that are added dynamically? Lets say I have a div with the following contents:
<div>
<a href='location.html'>location</a>
</div>
Now I call:
$('a').click(
function(){
console.log("going to " + $(this).attr('href'));
return true;
});
And that will work fine. But if somewhere along the line I call
$('div').("<a href='location2.html'>location2</a>");
without explicitly binding that event handler to that event then the event handler will pick up on it.
Is it possible to rebind when ever a new a element is added. Or even better, when ever the location.href property is changing so I can add a get parameter to it every time.
For example if I was binding to a click event on an a element the event handler would be:
function(){
var newid = parseInt(Obj.Request('pageid'), 10) + 1;
location.href = $(this).attr('href') + '?pageid=' + newid.toString();
return false;
}
Assuming the Obj.Request is a function that returns a get parameter. (I already have this in place).
Use it in this manner:
$(document).on( 'click', 'a', function() {
console.log("going to " + $(this).attr('href'));
return true;
});
Working on your fiddle link.
You want to use the function .on.
$('a').on('click', function() {
//works on non dynamic elements present at page load
});
$('#some_non_dynamic_parent_ID').on('click', 'a', function() {
//works on dynamic elements added later
});
You want to use .on(), but as a delegation method.
Bind it to the closest static parent - for this example I'll just use body.
$('body').on('click', 'a', function(e){
e.preventDefault();
});
This will wait until the event bubbles up to the body element and check what the original target of the event was - if it was an a element, it'll fire the handler.
You can use .on() or live() functions if you use jquery upper then 1.7 version. About the difference of these functions you can read in this article

jQuery: Any way to "refresh" event handlers?

I have two divs, one that holds some stuff and the other with all possible stuff. Clicking on one of the divs will transfer items to the other div. The code I came up with is:
$("#holder > *").each(function() {
$(this).click(function(e) {
$(this).remove();
$("#bucket").append(this);
});
});
$("#bucket > *").each(function() {
$(this).click(function(e) {
$(this).remove();
$("#holder").append(this);
});
});
This one works perfectly, except that the event handlers need to be refreshed once I append or remove elements. What I mean is, if I first click on an element, it gets added to the other div, but if I click on this element again, nothing happens. I can do this manually but is there a better way to achieve this?
Try jquery live events .. the $.live(eventname, function) will bind to any current elements that match as well as elements added to the Dom in the future by javascript manipulation.
example:
$("#holder > *").live("click", function(e) {
$(this).remove();
$("#bucket").append(this);
});
$("#bucket > *").live("click", function(e) {
$(this).remove();
$("#holder").append(this);
});
Important:
Note that $.live has since been stripped from jQuery (1.9 onwards) and that you should instead use $.on.
I suggest that you refer to this answer for an updated example.
First, live is deprecated. Second, refreshing isn't what you want. You just need to attach the click handler to the right source, in this case: the document.
When you do
$(document).on('click', <id or class of element>, <function>);
the click handler is attached to the document. When the page is loaded, the click handler is attached to a specific instance of an element. When the page is reloaded, that specific instance is gone so the handler isn't going to register any clicks. But the page remains so attach the click handler to the document. Simple and easy.
Here you go, using the more intuitive delegate API:
var holder = $('#holder'),
bucket = $('#bucket');
holder.delegate('*', 'click', function(e) {
$(this).remove();
bucket.append(this);
});
bucket.delegate('*', 'click', function(e) {
$(this).remove();
holder.append(this);
});
EDIT: don't use live, it be deprecated!
Take advantage of the fact that events bubble. Using .on():
var = function( el1, el2 ) {
var things = $('#holder, #bucket');
things.each(function( index ) {
// for every click on or in this element
things.eq(index).on('click', '> *', function() {
// append will remove the element
// Number( !0 ) => 1, Number( !1 ) => 0
things.eq( Number(!index) ).append( this );
});
});
any click on any element (existing at the time of bind or not) will bubble up (assuming you haven't manually captured the event and stopped propagation). Thus, you can use that event delegation to bind only two events, one on each container. Every click that passed the selector test of the 2nd argument (in this case, > *, will remove that element and then append it to the alternate container as accesesed by things.eq( Number(!index) )
Have you looked at jQuery's live function?
The most Efficient way (dont load all event for all elements) it:
//NORMAL FUNCTION
function myfunction_click(){
//custom action
}
$('id_or_class_of_element').on('click', myfunction_click);
//LOAD OR REFRESH EVENT
$(document).on('click', 'id_or_class_of_element', myfunction_click);

Categories