Repeated binding unbinding of click event on element - javascript

I'm kind of confused, I want to know binding and unbinding event on the same element is better or I should use a flag (something like 'inProgress').
I have a scenario where I have to prevent an operation or event from happening if one operation is already in process, for eg.
I have an anchor tag and I've bind an event to that anchor tag and that event handles some ajax functionality like fetching data and updating certain part of the page, what I want is to stop repeated click on the anchor tag from happening so that once the first click has happened on the anchor tag wait till the response comes from the server and the part of the page is updated, my confusion lies whether i should unbind the event once the click happens and bind the same handler again once the response is handled or should I setup a flag to check if any handler is in progress and set the flag false once the response is handled? which of the way would be efficient performance wise?
Any help/suggestion is much appreciated!
Thanks

use a flag!
it's better to use some boolean variable and check if you are allowed that action rather than calling bind and unbind (which is additional overhead).
if you use jQuery, you can use the data() to store data on that anchor.
like:
$('.testLink').on('click',function(){
//reference link
var link = $(this);
//check data
data = link.data('amIallowed');
//if no data existed yet
if(!data){
//set data and make it false to prevent further requests
link.data('amIallowed',{
allowRequest : false
});
//lets do ajax
doAjax();
}
else{ //if there was data
//and we were allowed
if(data.allowRequest){
doAjax(link);
}
}
});
//do ajax stuff here
function doAjax(link){
$.post('url',{param:val},function(){
//revert to true after request
link.data('amIallowed',{
allowRequest : true
});
});
}
if you don't use jQuery, you can still do the same feat using simple JS. jQuery uses "expando-properties" to bind data onto elements. if you can do with expando-props, use variables instead.

Related

How to check and remove the event if already exist with vanilla javascript or jquery

I am performing a task where i need to reload the function again but i do not want to add same event with same function so i need to listen the elements events first and if it is not exist i need to add it if event already exist i need to prevent it from happening.
My DOM i like this.
<a href='#clicked' id='toggle_bars' data-gonext='1'>next</next>
$('#toggle_bars').click(function(){
// some argument
})
// for page one
<a href='#clicked' id='toggle_bars_again' data-goback='1'>next</next>
$('#toggle_bars_again').click(function(){
// some argument
})
// for page one
i do not want to reload the page
when user click on #toggle_bars he need to go back and reload its function when i load the #toggle_bars_again the function repeat itself i want to listen its events and prevent it from happening.
i also use methods like return false event.preventDefault() event.stopPropogation
FYI : I know that this is may be a bad practice but this is a very old code-base and i do not want to redo it again.
"he need to go back and reload its function when I load the #toggle_bars_again the function repeat itself I want to listen its events and prevent it from happening." what are you trying to say its not clear.
if you want to prevent the page from reloading remove href and in here:
$('#toggle_bars').click(function(event){
event.preventDefault()
});
I don't know if it's clearly what you search, but if you need to connect the same event again on the same element, you can do something like that :
$("element").off("click").on("click", function() {})
And if it's on an other element, just do an off on the first and then connect your event to the second element
Jquery's one() method could be a solution too

Detect ul list content change jQuery

We have an unordered list with id #some-list. In our Backbone implementation, when certain data is returned, list entries are rendered and appended to the list and the list is displayed.
We want to detect when such change is completed using JQuery. We used $(#some-list).ready() and $(#some-list).load(), but it looks like they are not working.
What are some ways to capture such change? Could anyone shed some lights here?
Well you didn't post any code so it's really hard to see guess where you fail.
But in general what i would do is trigger a custom event on the ajax callback (you do use ajax to get the content and appending it to the list right?).
for example:
loadData(){
// invoke the ajax request
var def = $.get(...);
def.then(function(result){
// $(#ul) append(result) ...
// now trigger the custom event
$(document).trigger('listRendred');
});
}
Now on a different place or script you can listen to it:
$(document).on('listRendred', function(e){ // do what ever... })
Since you are using BackboneJS you could try to listen to its events.
To find out which events you could use, try following code (replace my * placeholders first) and have a look inside your browser's console.
*backboneobject*.on("all", function(e) {
console.log(e)
});
Afterwards just listen for the event by using
*backboneobject*.on("*yourevent*", function() {
doStuff();
});

Binding a click event to content loaded via AJAX without making it delegated?

I have a situation where I am using the data attribute named data-command in many instances throughout a specific section of a site and instead of binding tons of separate click events I decided to just use the one and use a switch such as:
$('[data-command]').on('click', function(event) {
// Prevent default click action
event.preventDefault();
// Get command
var command = $(event.target).data('command');
switch (command) {
// Do stuff...
}
// Prevent default click action (IE 8)
return false;
});
However it has just become an issue when trying to get it to work on data loaded via AJAX.
This obviously works..
$('#existing_element').on('click', '[data-command]', function(event) {
...but since it is supposed to work on many different pages in that section of the site the above wouldn't work on all pages.
I could just make sure to give a specific id to the parent wrapper where I load all my ajax data, but that would mean making two separate binding events with a bunch of the same code.
I also could do this to cover all bases..
$(document).on('click', '[data-command]', function(event) {
...but that's probably not such a wise idea binding an element to the document.
Edit: Html data is being loaded into the DOM via jQuery's html method.
Any clean way I can handle this or should I just create two different binding events to handle each situation?
Event delegation is the best approach to bind events on dynamically created elements. Since you don't want to use event delegation, use following approach to bind events.
$('[data-command]').off('click').on('click', clickHandler);
// Somewhere in the same scope
function clickHandler(e) {
// Handle click event here
}
Add this after the dynamically created elements are added using html().
off('click') will first unbind the click event handlers that are applied previously and then on('click', will bind the click handler on all the elements matching selector.
Edit
This seems to be repeating the same code again and again. Can't I keep it DRY?
Yes, you can keep the code DRY and clean by creating a function to bind events and call the same function when you want to bind event.
function clickHandler(e) {
// Handle click event here
}
function bindEvent() {
$('[data-command]').off('click').on('click', clickHandler);
}
$(document).ready(bindEvent);
...
$.ajax({
...
success: bindEvent
....

jQuery selector "memory"

I have a form with multiple fields, and each time the user changes a field the form is submitted (via hidden iframe), and the response is placed within an appropriate div on the page via a callback. The first time this works fine. But on each subsequent field change and submission, the response is shown in every div that has been filled with a response (so they all show the same thing, not the desired behavior).
Can anyone tell me why this is happening? It seems that there is some retention of the selectors that have been called before (since last page load)... but I'm not sure. Here's my code:
$(function ()
{
$('#ImageAddForm input').change(function (){
form = $('#ImageAddForm');
var fldDiv = $(this).parent().attr('id'); // eg Image11
var thDiv = fldDiv.replace('Image', 'Thumb'); // eg Thumb11
$(form).iframePostForm({
post : function (){
var msg = 'Uploading file...';
$("#" + thDiv).html(msg);
},
complete : function (response){
$("#" + thDiv).html(response);
$(':input', '#ImageAddForm').not(':hidden').val('');
}
});
form.submit();
});
});
I'm not familiar with that plug-in, but I have a suspicion about what might be causing your problem. You are attaching some functionality to your form with the plug-in inside of your change event. This means that on every change you are attaching again, which is likely to cause some problems. Two solutions suggest themselves:
1) If the plug-in has some kind of call to unbind or destroy itself, call that right before binding the plug-in to the form. This should prevent any weird behavior caused by multiple binding.
2) Better solution: bind the plug-in to the form outside your change event, and scope your variables (fldDiv, tdDiv) such that they will be accessible to both your change event (so that they can be modified based on what changed) and the functions used by the plug-in (for post and complete). This way you will only bind the plug-in once, but can still pass and receive different data based on what field changed.

How to get dojo.query to reutrn values for a dijit.Dialog

I have some code in which I am creating an dijit.Dialog with an Ajax call(href property) to populate the contents.
I what to parse the returned content to dojo.connect a click event to the links in the returned content.
But when I do a dojo.query("a",this.current_popup.domNode) I get an empty array back
Does anybody know how can get can attach a onclick to all the returned content?
Paul
It is less expensive to just bind an event handler to the DOM node of the Dialog widget, and use event delegation to capture any "a" clicks. This way, you can avoid any event handler cleanup, particularly if the contents of the Dialog change frequently. You can avoid the event handler cleanup if you use the widget's connect method to do the work.
So, if you are doing the connect inside a method in the dijit.Dialog, you could use something like:
this.connect("onclick", function(evt){
var node = evt.target;
if("a" == node.nodeName.toLowerCase()){
//node is an a tag, do what you want with it,
//for example, read node.href to get the URL attached to it.
//If you want to prevent following that URL and prevent further
//event bubbling, stop the event:
dojo.stopEvent(evt);
}
});
If you are doing this connection work outside the widget instance, instead of using this.connect, use widgetInstance.connect(), assuming widgetInstance is a variable that refers to the dijit.Dialog instance.
By using that version of connect, the widget will automatically unregister the event handler when the Dialog widget is destroyed, keeping the memory profile in check.
One way I found to do this was to add a delayed connect to the widget
dojo.connect(this.current_popup, "onDownloadEnd", function(){
dojo.query("a.popup",this.current_popup).forEach(function(node) {
// add your function add here
});
});
This runs after the ajax call is complete so you can now find the objects in the DOM

Categories

Resources