Jquery onclick function runs multiple time increasingly - javascript

I have interesting problem and i can't figure it out why it's happening like that. I have dataTables and data comes after selection change on a select, with jquery ajax post. And i have onclick function for multiple selection. (It must be run when click at table and it changes rows style etc.) I noticed that (with debug); when i click on row after first load onclick works one time as expected. But click after second load (selection changed) it runs 2 time and click after third load it runs 3 time i don't understand what's going on. So need some help.
Here is selection change function that loads the table;
// in doc.ready
$('#groupSelect').change(function() {
var group = $('#groupSelect').val();
if (!$.fn.DataTable.isDataTable('#questTable')) //this is for first load
{
GetQuestions(group);
} else //this is for after first load
{
var table = $('#questTable').DataTable();
table.destroy();
table.clear().draw();
GetQuestions(group);
}
});
And this is GetQuestions() function that gets data;
// out of doc ready
function GetQuestions(questGroup) {
$.ajax({
type: 'POST',
dataType: 'json',
contentType: 'application/json',
url: 'SetAudit.aspx/Questions',
data: '{"q_group":"' + questGroup + '"}',
success: function(result) {
$('#questTable').DataTable({
data: result.d,
columns: [{
data: 'q_id'
}, {
data: 'q_text'
}]
});
//this click function runs multiple time at 1 click
$('#questTable tbody').on('click', 'tr', function() {
var table = $('#questTable').DataTable();
var count = table.rows('.selected').count();
$(this).toggleClass('selected');
$('#selectedCount').text('' + table.rows('.selected').count() + '');
});
}
});
}
I don't if it is ok that i created it in ajax success func but it doesn't work anywhere else. Thanks in advance.

The issue is because every time a change event occurs on #groupSelect you fire an AJAX request, and in the success handler of that AJAX request you attach another click event handler to the tr of the table. Hence they duplicate.
To fix this I'd suggest you move the tr event handler outside the success handler and only run it once on load of the DOM. Try this:
function GetQuestions(questGroup) {
$.ajax({
type: 'POST',
dataType: 'json',
contentType: 'application/json',
url: 'SetAudit.aspx/Questions',
data: { q_group: questGroup },
success: function (result) {
$('#questTable').DataTable({
data: result.d,
columns: [
{ data: 'q_id' },
{ data: 'q_text' }
]
});
}
});
}
// do this on load *only*
$('#questTable tbody').on('click', 'tr', function () {
var table = $('#questTable').DataTable();
var count = table.rows('.selected').count();
$(this).toggleClass('selected');
$('#selectedCount').text(table.rows('.selected').count());
});

This should work
//this click function runs multiple time at 1 click
$('#questTable tbody').off().on('click', 'tr', function() {
var table = $('#questTable').DataTable();
var count = table.rows('.selected').count();
$(this).toggleClass('selected');
$('#selectedCount').text('' + table.rows('.selected').count() + '');
});
There are multiple ways you can solve the issue.
Removing and Adding the table DOM element: It depends on the way you construct data table. If you are constructing your datatable only from JS then you can go with this approach.
// in doc.ready
$('#groupSelect').change(function() {
var group = $('#groupSelect').val();
if (!$.fn.DataTable.isDataTable('#questTable')) {// this is for first load
GetQuestions(group);
} else {//this is for after first load
var table = $('#questTable').DataTable();
table.destroy();
table.clear().draw();
// empty the table which will eventually clear all the event handlers
$('#questTable').empty();
GetQuestions(group);
}
});
Using drawCallback event of datatable along with jQuery off: You can place the row highlighting function in drawCallback
//out of doc ready
function GetQuestions(questGroup) {
$.ajax({
type: 'POST',
dataType: 'json',
contentType: 'application/json',
url: 'SetAudit.aspx/Questions',
data: '{"q_group":"' + questGroup + '"}',
success: function(result) {
$('#questTable').DataTable({
data: result.d,
columns: [{
data: 'q_id'
}, {
data: 'q_text'
}],
drawCallback: function(settings) {
//this click function runs multiple time at 1 click
$('#questTable tbody').off().on('click', 'tr', function() {
var table = $('#questTable').DataTable();
var count = table.rows('.selected').count();
$(this).toggleClass('selected');
$('#selectedCount').text('' + table.rows('.selected').count() + '');
});
}
});
}
});
}

You're adding the binding to the click event inside your .change() function. This way you add a new binding everytime, hence the increasing number of calls to the function.
The proper way to do so is moving $('#questTable tbody').on('click', 'tr', function () { outside of GetQuestions.

Every time you call $('selector').on('click', ...), you're registering a new callback to execute when an element matching your selector is clicked. So in this case, every time that ajax call completes, you will register another click handler. So if your ajax call executes three times, you will have registered three identical click handlers, and all of them will execute.
You should make sure your $('#questTable tbody').on('click', 'tr', ...) is only executed once.

You have add new event listener after every ajax request,
move click event from ajax callback
//out of doc ready
function GetQuestions(questGroup) {
$.ajax({
type:'POST',
dataType:'json',
contentType:'application/json',
url:'SetAudit.aspx/Questions',
data: '{"q_group":"' + questGroup + '"}',
success: function (result) {
$('#questTable').DataTable({
data: result.d,
columns: [
{ data: 'q_id' },
{ data: 'q_text' }
]
});
}
});
}
//this click function runs multiple time at 1 click
$('#questTable tbody').on('click', 'tr', function () {
var table = $('#questTable').DataTable();
var count = table.rows('.selected').count();
$(this).toggleClass('selected');
$('#selectedCount').text('' + table.rows('.selected').count() + '');
});

Related

Binding an each statement

If I wanted to bind each statement to the #container div how would I go about this?
Here is an example of the each statement im trying to code:
$.each($(".product-comment"), function (key, value) {
var showmoreHtml = $(this).html();
var showlessHtml = showmoreHtml.substr(0, 400);
if (showmoreHtml.length > 400) {
$(this).html(showlessHtml).append("<a href='' class='product-comment-more'> (...Show More)</a>");
}
$(this).on("click", ".product-comment-more", function (event) {
event.preventDefault();
$(this).parent(".product-comment").html(showmoreHtml).append("<a href='' class='product-comment-less'> (Show less)</a>");
});
$.ajax({
method: 'POST',
url: urlCreateReview,
data: form_data,
cache: false,
processData: false,
contentType: false,
success: function(data) {
$(".tab-comment-holder").load(" .tab-comment-holder");
},
You can call the jquery function on your selector, call .each() and pass a function:
$("#container div").each(function() {
//do something
console.log($(this));
});
EDIT:
Apparently the div is "reloaded" in the callback of an AJAX. The solution is to make sure its items are properly initialized inside the callback. There is an .each() for this purpose, but it uses commands such as
$(this).on("click", ".product-comment-more", function (event) {
//...
}
which creates a click handler for every tag having the class of product-comment-more each time, this means that if there are n such tags and a user happens to click on one of those, the click handler will be executed n times. It's better to create a single handler for each of them. showmoreHtml is not well defined.

Jquery Ajax : auto-refresh

In my Ajax success function i created button and on click i am calling a function.
The problem:
The page reloads based on the timer in set interval but when i click the button it will call the function based on the number of times the page reloaded.
For example:
If page reloads 5 times and then i call a function on clicking that button-it will call that function 5 times.
if it reloads 10 times then function call is for 10 times.
Please advice what i am doing wrong?
Here is the code:
$(document).ready(
function() {
setInterval(function() {
$.ajax({
type: 'GET',
url: 'Refresh',
success: function(data) {
var trHTML = '';
$.each(data, function(i, item) {
var buttonVar = ('<button id="bt21" class="btn121">' + "STOP" + '</button>');
trHTML += '<tr><td>'+buttonVar+'</td></tr>'
});
$('#test1').append(trHTML);
$(document).on('click','#bt21', function(event) {
var rownum1 = $(this).closest('tr').index();
stopTest(data[rownum1].process_id);
});
}
});
}, 5000);
});
You have set the AJAX call to be made every 5 seconds. Each time time this function is called, you are also attaching the click event on the button you append. So there will be multiple event handlers attached to the same element. You need to clear any existing event handlers on that element before you attach another if you want to stick to your current code. Here's how to do it:
$(document).off('click', '#bt21');
$(document).on('click','#bt21', function(event) {
var rownum1 = $(this).closest('tr').index();
stopTest(data[rownum1].process_id);
});
Each time the page is refreshed from your ajax call a new event listener is bound to the button in memory. You need to clear the event listeners then create a new one.
$(some element).unbind().on(...........);
I always unbind event listeners created in an ajax call if anything to keep the browser memory from being over loaded or to prevent the issue you are having.
$(document).ready(
function() {
setInterval(function() {
$.ajax({
type: 'GET',
url: 'Refresh',
success: function(data) {
var trHTML = '';
$.each(data, function(i, item) {
var buttonVar = ('<button id="bt21" class="btn121">' + "STOP" + '</button>');
trHTML += '<tr><td>'+buttonVar+'</td></tr>'
});
$('#test1').append(trHTML);
$(document).unbind().on('click','#bt21', function(event) {
var rownum1 = $(this).closest('tr').index();
stopTest(data[rownum1].process_id);
});
}
});
}, 5000);
});
First you are appending buttons on refresh that have the same id attribute so that's going to cause you issues at some point.
What you need to do is move your click event outside of the interval function and ajax callback. Add the process id to the button in a data attribute and delegate a click event to the button so it will work even though the elements haven't been created in the DOM when the page loads.
Here's an example although I'm not sure if it works (can't really simulate this easily):
$(document).ready(function() {
setInterval(function() {
$.ajax({
type: 'GET',
url: 'Refresh',
success: function(data) {
var trHTML = '';
$.each(data, function(i, item) {
var buttonVar = '<button class="btn" data-process-id="' + item.process_id + '">' + "STOP" + '</button>');
trHTML += '<tr><td>'+buttonVar+'</td></tr>'
});
$('#test1').append(trHTML);
}
});
}, 5000);
$('#test1').on('click', '.btn', function() {
stopTest( $(this).data('process_id') );
});
});

Why function is executed 1 + n times when it should be executed once on click?

I'm adding eventListener like this:
var runSingleTest = document.getElementById('runSingleTest');
runSingleTest.addEventListener('click', sendSingeleTestCase);
When user click that button in my form following code is executed 1 + n times, where n is number of click on that button before.
function sendSingeleTestCase(){
var frm = $('#scriptCodeForm');
var btn = $('#runSingleTest');
saveScriptToLocalStorage();
frm.submit(function (ev){
$.ajax({
type: frm.attr('method'),
url: btn.attr('formaction'),
data: frm.serialize(),
success: function (data) {
console.log("Test would run once.");
}
});
ev.preventDefault();
});
}
It doesn't behaves as expected (executed many times when it should be only executed once).
Could you help me to understand possible reasons why it's not working as supposed?
Thanks!
You are connecting the submit handler inside a click handler. Separate those so that you only register the submit handler once.
e.g. something like:
function sendSingeleTestCase(){
saveScriptToLocalStorage();
}
var frm = $('#scriptCodeForm');
var btn = $('#runSingleTest');
frm.submit(function (ev){
$.ajax({
type: frm.attr('method'),
url: btn.attr('formaction'),
data: frm.serialize(),
success: function (data) {
console.log("Test would run once.");
}
});
ev.preventDefault();
});
Also note: As you are using jQuery, please convert your click handler to just this:
$('#runSingleTest').click(sendSingeleTestCase);
or place the handler code inside an anoymous function:
$('#runSingleTest').click(function(){
saveScriptToLocalStorage();
// Do other stuff
});

jquery onclick runs twice

I have the following javascript when my script is loaded:
var current_selected_note = $('#new_note');
current_selected_note.addClass('hover active');
$('#note-item-lists').on('click', '.list-group-item', function () {
//removes the hover color from the previous selected
current_selected_note.removeClass('hover active');
// sets the currently selected equal to the selected note
current_selected_note = $(this);
// adds the hover active to the currently selected
current_selected_note.addClass('hover active');
//adds the title of the currently selected to the title input field
$('#txt_new_note_title').val($(this).find('Strong').text());
selected_note_id = $(this).get(0).id;
getNote(selected_note_id);
load_comments(selected_note_id);
});
$( "#note-item-lists").find('li').first().trigger( "click" );
Now AFTER this is loaded i click one of my buttons which has the following javascript:
$('#note-item-lists').on('click','.close',function(){
var r = confirm('Are you sure you wish to delete "'+$(this).next('div').find('.new_note_title').text()+'" ?')
if(r == true){
deleteNote($(this));
$( "#note-item-lists").find('li').first().click();
}
})
function deleteNote(button){
var id = button.closest('li').get(0).id;
$.ajax({
type: 'POST',
url: '/solo/ajax_delete',
dataType: 'json',
data: {
id: id
},
success: function (data) {
}
});
button.closest('li').remove();
}
When this happens (i debug it) and the event function is called first 1 time (adding the class correctly) but is then happens immediatly again.
Anyone tried this before?
Try this, It will call one time.
$('#note-item-lists .close').on('click',function(){
alert("Hello");
});
Try using .off()
$('#note-item-lists').on('click', '.list-group-item', function () {
$(this).off(); //add this here

Trouble with jquery ajax and datatables

I am trying to use jquery ajax to get data from a php file. This php file prints a table made from a db query. Once the table is returned to the html page, I wanted to apply datatables styling to the table, but this will not work.
It maybe that I should just use datatables ajax functionality, instead of jquery ajax. I just have three links that a user can click on to call ajax, where not all the links return a printed table.
I suspect it it because of javascript timing, where all the js loads before the table has been output.
I tried using jquery.on(), but could not get it to work with datatables.
I appreciate any help. Sorry if this is confusing.
<script type="text/javascript">
$(document).ready(function() {
// EVENT LISTENER FOR CLICKS
var option_action = "fridge";
var using = "pantry";
$.post("./backend.php", { option: option_action, action: using }, function(data) {
$("#content").html(data);
load_table();
});
// EVENT LISTENER FOR CLICKS
$(".pantry_menu li").click(function() {
alert("CLICK");
//getting data from the html
var option_action = $( this ).attr("name");
var using = "pantry";
$.post("./backend.php", { option: option_action, action: using }, function(data) {
$("#content").html(data);
});
return false;
});
//Mouse action listeners for side bar
$(".pantry_menu li").mouseover(function() {
$(this).css("border-bottom" , "2px solid black");
});
$(".pantry_menu li").mouseout(function() {
$(this).css("border-bottom" , "2px dotted black");
});
$(".fridge_table1").change(function(){
alert("CHANGE");
});
});
function load_table()
{
$('.fridge_table1').dataTable( {
"aaSorting": [[ 4, "desc" ]]
,"bJQueryUI": true
});
}
</script>
In your ajax success function, you can reapply dataTable to the table. For example:
$.ajax({
type: "POST",
url: "ajax.php",
data: {
request: 'something'
},
async: false,
success: function(output)
{
$('#myTableDiv').html(output); //the table is put on screen
$('#myTable').dataTable();
}
});
EDIT due to your update
You need to change the "EVENT LISTENER FOR CLICKS" to call your function that applies dataTables. Change:
$.post("./backend.php", { option: option_action, action: using }, function(data) {
$("#content").html(data);
});
to
$.post("./backend.php", { option: option_action, action: using }, function(data) {
$("#content").html(data);
load_table();
});
You should put the .dataTables() part in the callback of your ajax function
$.ajax{
url: yoururl,
...
success: function(data){
//append the table to the DOm
$('#result').html(data.table)
//call datatables on the new table
$('#newtable').dataTables()
}
otherwise you are trying to transforma table that doesn't exist yet in the DOM

Categories