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') );
});
});
Related
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() + '');
});
function test() {
$.getJSON("/Home/GetAp", function (result) {
$.each(result, function () {
if (this.is_disabled == "False") {
var a = $("#MainDiv")
.append('<div id="imagewrap"><img id="infobutton" src="/Content/information%20icon.png" /></div>')
.val(this.id);
} else if (this.is_disabled == "True") {
var a = $("#MainDiv")
.append('<div id="imagewrap"><img id="infobutton2" src="/Content/information%20icon.png" /></div>')
.val(this.id);
} else {
return null;
}
})
})
}
How would I nest and ajax function be able to POST the a.val() so that when a user clicks on any $("#infobutton") they will be able to use the val of that button which would be an id specific to that button
$("#infobutton").click(function () {
$.ajax({
type: "POST",
contentType: 'application/json; charset=utf-8',
url: "/Home/setID",
data: JSON.stringify({ id: this.id }),
success: function (result) {
}
});
});
Do not make your logic depend on duplicate ids of DOM elements, use class instead.
Use event delegation to register event handlers for elements that exist at the time of event registration and for elements that will be created later.
.append('<div id="imagewrap"><img class="infobutton" src="/Content/information%20icon.png" /></div>')
$(document).on("click",".infobutton",function () {
$.ajax({
...
});
});
No need to nest ajax call. Just ensure click events bind to new elements appended and get the id in click event handler. Similar example (without ajax call)
$(document).ready(function(){
$(document).on('click', '.info', function(e) { alert("clicked div # " + $(e.target).text()); });
setTimeout(function(){ $("#d1").append("<div class='info'>Click info 1.</div>"); }, 1000);
setTimeout(function(){ $("#d1").append("<div class='info'>Click info 2.</div>"); }, 2000);
setTimeout(function(){ $("#d1").append("<div class='info'>Click info 3.</div>"); }, 3000);
});
<div id="d1">
</div>
Let me know if you need more details or example with ajax call.
For id you can use
$(document).on('click', '.info', function(e) { alert("clicked div # " + e.target.id); });
I have basically a ajax call that invokes a REST API that gives me list of all names and I have another REST API that matches that. For example,
/list gives me: list1,list2,list3
and
/api/list1.json gives me: json of list1..
But I have my code where I loop through all the lists and invoke /api/list1.json
I want that JSON to be displayed in a div when a onclick event occurs by grabbing the href accordingly without page reload. But right now, since that is also a valid link browser just takes me there.
Here is my code:
$(function() {
$.ajax({
dataType: 'json'
url: '/lists',
success: function (data) {
if (data != null) {
var html = '<ul>';
$.each(data.apis, function (i, item) {
//click event
$('a').click(function(e) {
e.preventDefault();
});
html += '<li class="res">';
html += '<div class="hed"><h2>' + item + '</h2></div>';
html += '</li>';
});
html += '</ul>';
$('#exDiv').empty();
$('#exDiv').append(html);
}
},
error: function () {
alert('Error');
},
contentType: 'application/json'
});
$('a').click(function(e) {
e.preventDefault();
});
});
Apparently I also added e.preventDefault() but it still triggers the link to a new tab.
Link to e.preventDefault()
These are dynamically added anchor tags. They don't exist when you add the click event handler to the anchor tags. So when you click these anchors they are going to bypass your jquery event handlers and do what they normally do by default.(further explanation) You have the same code again inside the $.each function which might have worked if you had called it after your $('#exDiv').append(html); line. But again they still don't exist when you call it.
Depending on the version of jQuery you're using you should use either "on" or "live". If you are using a version 1.7 or higher use 'on'.
Try this:
$(function() {
$.ajax({
dataType: 'json'
url: '/lists',
success: function (data) {
if (data != null) {
var html = '<ul>';
$.each(data.apis, function (i, item) {
html += '<li class="res">';
html += '<div class="hed"><h2>' + item + '</h2></div>';
html += '</li>';
});
html += '</ul>';
$('#exDiv').empty();
$('#exDiv').append(html);
}
},
error: function () {
alert('Error');
},
contentType: 'application/json'
});
$(document).on('click', 'a', function(e) {
e.preventDefault();
});
});
If you're using 1.6 or ealier your click event handler should look like this:
$('a').live('click', function(e) {
e.preventDefault();
});
I am trying to create a dropdown menu that I dynamically insert into using jQuery. The objects I'm inserting are notifications, so I want to be able to mark them as read when I click them.
I have an AJAX call that refreshes the notifications every second from the Django backend.
Once it's been refreshed, I insert the notifications into the menu.
I keep an array of the notifications so that I don't create duplicate elements. I insert the elements by using .append(), then I use the .on() method to add a click event to the <li> element.
Once the click event is initiated, I call a function to .remove() the element and make an AJAX call to Django to mark the notification as read.
Now my problem:
The first AJAX call to mark a notification as read always works. But any call after that does not until I refresh the page. I keep a slug value to identify the different notifications.
Every call I make before the refresh uses the first slug value. I can't figure out why the slug value is tied to the first element I mark as read.
Also, if anyone has a better idea on how to approach this, please share.
Here's my code:
var seen = [];
function removeNotification(elem, urlDelete) {
elem.remove();
console.log("element removed");
$.ajax({
url: urlDelete,
type: 'get',
success: function(data) {
console.log("marked as read");
},
failure: function(data) {
console.log('failure to mark as read');
}
});
}
function insertNotifications(data) {
for (var i = 0; i < data.unread_list.length; i++) {
var slug = data.unread_list[i].slug
var urlDelete = data.unread_list[i].url_delete;
if (seen.indexOf(slug) === -1) {
var elem = $('#live-notify-list').append("<li id='notification" +
i + "' > " + data.unread_list[i].description + " </li>");
var parent = $('#notification' + i).wrap("<a href='#'></a>").parent();
seen.push(slug);
$( document ).ready(function() {
$( document ).on("click", "#notification" + i, function() {
console.log("onclick " + slug);
removeNotification(parent[0], urlDelete);
});
});
}
}
}
function refreshNotifications() {
$.ajax({
url: "{% url 'notifications:live_unread_notification_list' %}",
type: 'get',
success: function(data) {
console.log("success");
insertNotifications(data);
},
failure: function(data) {
console.log('failure');
}
});
}
setInterval(refreshNotifications, 1000);
I really don't know what do you mean with parent[0] in
removeNotification(parent[0], urlDelete);
I think you can simply try $(this)
removeNotification($(this), urlDelete);
but to be honest I find to put
$( document ).ready(function() {
$( document ).on("click", "#notification" + i, function() {
console.log("onclick " + slug);
removeNotification(parent[0], urlDelete);
});
});
inside a loop .. its bad thing try to put it outside a function and use it like
$( document ).ready(function() {
setInterval(refreshNotifications, 1000);
$( document ).on("click", "[id^='notification']", function() {
console.log("onclick " + slug);
removeNotification($(this), urlDelete);
});
});
and try to find a way to pass a urlDelete which I think it will be just one url
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