Reloading Ajax function with setTimeout doesnt clear previous timeout first - javascript

I am trying to load a chat box when a contact name is clicked. On initial load it displays the inbox. All functionality works ok until I try and click the contact name a second time. It loads the new contacts chat but also displays the original contact chat even though I set clearTimeout().
Here is the JS file -
$(document).ready(function(){
var contactTimeout;
var inboxTimeout;
function contact() {
var fromName = $('#from').val();
var toName = $("#to").val();
$(".chat-title").replaceWith("<div class='chat-title'>" + toName + "</div>");
$(".chat-form").fadeIn(100);
$.ajax('chat/get-chat.php', {
data: ({ to: toName,from: fromName}),
type: "POST",
success: function(data) {
$(".chat-body").replaceWith("<div class='chat-body'>" + data + "</div>");
contactTimeout = setTimeout(contact, 2000);
}
});
}
function inbox() {
var user = $('#from').val();
$.ajax('chat/get-chat-inbox.php', {
data: ({ user: user}),
type: "POST",
success: function(data) {
$(".chat-body").replaceWith("<div class='chat-body'>" + data + "</div>");
inboxTimeout = setTimeout(inbox, 2000);
}
});
}
// Load inbox when chat box is opened
$(".chat-arrow").click(function(){
clearTimeout(contactTimeout);
inbox();
});
// Load chat from contact name
$(".contact-name").click(function() {
clearTimeout(contactTimeout); // Here I try and kill previous timeout
clearTimeout(inboxTimeout);
var contactName = $(this).attr('id');
$("#to").val(contactName);
contact();
});
});
Why would it just add more timeout functions rather than replace them when a new contact name is clicked?

First i would suggest you instead of using replace each time, you could easily use .html(data) to put new data in existing content of chat-body.
And explanation is you call your function on ajax success (there's wait time to server respond to your request) and if you click in meanwhile on your another call, you will have two calls instead of one, because you can't clear timer that's not started yet.
Well one of the solutions would be, let timer works only through it's default state, and when you need some fast data, you can call your contact without calling the next timer.
$(document).ready(function(){
var contactTimeout;
var inboxTimeout;
/* add parameter which will mean will we call timer or not */
function contact(dotimer) {
var fromName = $('#from').val();
var toName = $("#to").val();
$(".chat-title").replaceWith("<div class='chat-title'>" + toName + "</div>");
$(".chat-form").fadeIn(100);
$.ajax('chat/get-chat.php', {
data: ({ to: toName,from: fromName}),
type: "POST",
success: function(data) {
$(".chat-body").replaceWith("<div class='chat-body'>" + data + "</div>");
/* default calling of timer with repeating */
if (dotimer) { contactTimeout = setTimeout(function(){ contact(true); }, 2000); }
}
});
}
function inbox() {
var user = $('#from').val();
$.ajax('chat/get-chat-inbox.php', {
data: ({ user: user}),
type: "POST",
success: function(data) {
$(".chat-body").replaceWith("<div class='chat-body'>" + data + "</div>");
inboxTimeout = setTimeout(inbox, 2000);
}
});
}
// Load inbox when chat box is opened
$(".chat-arrow").click(function(){
clearTimeout(contactTimeout);
inbox();
});
// Load chat from contact name
$(".contact-name").click(function() {
clearTimeout(inboxTimeout);
var contactName = $(this).attr('id');
$("#to").val(contactName);
/* call function without TIMER, default one will work as it works */
contact(false);
});
});

Related

Ajax call won't navigate to a new view

I've created an application using codeigniter 3 that gets quizzes stored in the SQL database using a model and populate in the view using ajax and jquery.
Below is the code for populating data inside a div.
$(document).ready(function() {
$.ajax({
url: "/CW2/ASSWDCW2/cw2app/index.php/Leaderboard/quiz",
method: "GET",
dataType: "json"
}).done(function(data) {
$('#modtable tr').remove(); // clear table for new result
var quizzes = data.allQuizzes;
alert(quizzes.length);
var i;
for (i = 0; i < quizzes.length; i++) {
quiz = quizzes[i];
var block = ' <div id="quizMainBox"><h1>' + quiz.quizName + '</h1><br/><h3>' + quiz.creatorName + '<button onclick="myFunction(\''+quiz.quizId+'\')">Try it</button>'+'</h3></div>'
$('#allQuizBox').append(block);
}
});
return false;
// });
});
Below are 3 quizzes populated in the view.
What I want to do is when the user clicks on the "try it " button, I want the user to be directed to the "single_quiz_view" using the quiz id. So I wrote this ajax function (myFunction) below the above code.
function myFunction(quizId) {
// console.log("heyyyy");
// document.getElementById("demo").innerHTML = "Welcome"+quizId ;
$.ajax({
url: "/CW2/ASSWDCW2/cw2app/index.php/Quiz/loadQuiz/",
method: "POST",
}).done(function(data) {
alert("heyyy")
});
return false;
}
where Quiz is the controller name and loadQuiz is the function calling the "single_quiz_view"
//Quiz Controller
public function loadQuiz()
{
// $quizId = $this->uri->segment(3);
$this->load->view('quiz/single_quiz_view');
}
My problem is,
When I click on the "try it button", I get the alertBox inside the done function. I get the status code as 200 but still wont navigate to "single_quiz_view".Console wont give any errors.Please help

How To Refresh Chat using ajax

I'm implementing text chat based on twilio api ,I have functions do the following loads the chat on click ,send message,get last message (setting interval to 1sec to update in real time) and i will add check if the data is unset do nothing else fetch last message,
I need to get the data value of the current clicked item
here is the script and the logs
[![<script type="text/javascript">
$(document).ready(function(){
loadContacts();
displayChatOnclick();
setInterval(getlastmsg,1000);
}
);
//when the user clicks on contacts div fetch the chat history
function displayChatOnclick(){
$('#contacts').on('click','li',function() {
var channel = $(this).closest('li').attr('data-channel');
var name=$(this).closest('li').attr('data-name');
console.log(channel);
fetchChat(channel,name);
sendmsg();
//check if new msg is sent
});
}
function fetchChat(channel,name){
$.ajax({
url: 'loadchat.php',
type: 'POST',
data: { channel:channel,name:name },
success: function(msg) {
console.log(name);
$('#conversation').html(msg);
}
});
}
function loadContacts(){
$.ajax({
url: 'loadcontacts.php',
type: 'POST',
success: function(msg) {
$('#contacts').html(msg);
}
});
}
//function to get the last msg
function getlastmsg(){
var channel = $('#contacts li').data('data-channel');
var name=$('#contacts li').data('data-name');
//check if channel and name is null do nothing else fetch last message
console.log(name);
}
//function to send a msg
function sendmsg(){
$("#send").click(function() {
var channel=$(this).data('ch');
var message=$("#msg").val();
$('#msg').val('');
console.log(msg);
$.ajax({
type: "POST",
url: "sendmsg.php",
data: {
msg: message,
channel:channel,
},
success: function(result) {
console.log("sent");
$('#b').append(result);
}
});
});
}
</script>][1]][1]
what you are doing is a pull method: setInterval is not the best idea because it keeps calling your server with or without a change, imagine if you have 1000 users each one of them will send a request to the server every second.
I advise you to use a push method such as SignalR. here is a demo for chat that you can do with small number of lines
try this
var $container = $("#contacts li");
$container.load("rss-feed-data.php");
var refreshId = setInterval(function()
{
$container.load('rss-feed-data.php');
}, 9000);

Append the last message once

Hello guys i am trying to build a chat with Jquery , php , ajax and mysql
the problem that i am facing since few days is that when i get the value of the last message its keep getting append to the div what i want is to append the last message only once , and append again if there is a new message here is my ajax call
var chat = "";
$.ajax({
url: "php/gt_user.php",
type: "get",
success: function (result) {
var gtUser = $.parseJSON(result);
$.each(gtUser, function (idx, obj) {
var usrApp = "<span><i class='fa fa-user-circle-o' aria-hidden='true'></i>";
usrApp += "<p class='usr-name'>" + obj.Tables_in_chat + "</p></span>";
$('.userarea').append(usrApp);
}); // here i get all the username who sent a message and print them on a div
$('.userarea span').on('click', function () {
$('.msgarea').html("");
var usrName = $(this).text();
$('#usrname').text(usrName);
setInterval(function () {
$.ajax({
url: "php/admin_msg.php",
type: "post",
data: {
name: usrName
},
success: function (result) {
var lastmsg = result;
function appedn() {
var usrMsg = "<div class='usr-msg'><i class='fa fa-user-circle-o' aria-hidden='true'></i>";
usrMsg += "<span><p>" + lastmsg + "</p></span></div>";
$('.msgarea').append(usrMsg);
}
if (chat !== result) {
appedn();
} else {
chat = result;
}
}
});
}, 2000);
});
}
});
the respanse from php/admin_msg.php is working and i got the last message sucessfully the problem is that this script keep adding the same message to the message area , and what i want is to added the message only once if there is a new one
You need to somehow identify last message that is already appended to your html the best would be some id sent from server. So your message div should containt some data-id attribute, and then when you ask for next message get last children of $('.msgarea') element, read it data-id and compare with current one.
Another thing I would recommend to moving to some view library or framework, react, angular, vue or whatever. It gets complicated when you want to manage such features with pure jQuery.
i was finally able to fix the problem after 1 day of struggle so will post the answear here just in case it will help some one else facing the same issue
the part where i had to get all the username table from database i move it to my HTML and used a few line of php to echo the result like this(each user name has his own table)
// show all the user name that sent a message
$result = $con->query("show tables from chat");
while($row = mysqli_fetch_assoc($result)){
echo "<span><i class='fa fa-user-circle-o' aria-hidden='true'></i><p class='usr-name'>".$row['Tables_in_chat']."</p></span>";
}
then on my jquery script i moved the function that check for the last message every 2sec outside the click event so my Jquery script look more cleaner now
/* get the user name and added it to the header of the message box */
$('.userarea span').on('click', function () {
$('.msgarea').html("");
var usrName = $(this).text();
$('#usrname').text(usrName);
});
var chatdata = "";
/* check for new message and append the message area if there is a new one */
setInterval(function () {
var usrName = $('#usrname').text();
$.ajax({
url: "php/admin_msg.php",
type: "post",
data: {
name: usrName
},
success: function (result) {
function appedn() {
var usrMsg = "<div class='usr-msg'><i class='fa fa-user-circle-o' aria-hidden='true'></i>";
usrMsg += "<span><p>" + result + "</p></span></div>";
$('.msgarea').append(usrMsg);
}
if (chatdata !== result) {
appedn();
chatdata = result;
}
}
});
}, 2000);

Multiple AJAX calls and show div on finish

I have a JS script doing multiple AJAX requests. First I'm requesting a product by ID and then I'm requesting every single variant of this product. I can't do any form of backend coding since the environment I'm working in is closed.
My requests works fine, but right now I'm appending every single variant to a div, and my client don't really like this, so I was thinking is it possible to load all data into a variable and then fade in the parent div of all variants at the very end?
My script looks like this:
var variants = $('.single_product-variant-images');
$.ajax({
url: productMasterURL,
success: function (data) {
$(data).find('Combinations Combination').each(function () {
var variantID = $(this).attr('ProductNumber');
$.ajax({
url: "/api.asp?id=" + escape(variantID),
dataType: "json",
async: true,
cache: true,
success: function (data) {
variants.append('<div class="variant"><img src="' + data.pictureLink + '" alt=""/></div>');
variants.find('.variant').fadeIn(300);
}
});
});
}
});
Some fast and dirty solution, but idea and concept of solution is clear. It is bad solution, but works for you in your case when you have no access to backend code.
var all_load_interval;
var is_all_data_ready = false;
var all_data_count = 0;
var variants = $('.single_product-variant-images');
$.ajax({
url: productMasterURL,
success: function (data) {
var data_count = $(data).find('Combinations Combination').length;
$(data).find('Combinations Combination').each(function () {
var variantID = $(this).attr('ProductNumber');
$.ajax({
url: "/api.asp?id=" + escape(variantID),
dataType: "json",
async: true,
cache: true,
success: function (data) {
// make div with class variant hidden
variants.append('<div class="variant"><img src="' + data.pictureLink + '" alt=""/></div>');
// count every variant
all_data_count += 1
if (all_data_count == data_count) {
// when all data got and created, lets trigger our interval - all_load_interval
is_all_data_ready = true;
}
}
});
});
}
all_load_interval = setInterval(function() {
// Check does all data load every second
if (is_all_data_ready) {
// show all div.variant
variants.find('.variant').fadeIn(300);
clearInterval(all_load_interval);
}
}, 1000);
});

How to display a progress bar during an ajax request (jquery/php)

I have an ajax request, whereby I am installing a magento shop automatically, and when the process is done, it would redirect the user to the newly created shop. Here are my codes:
function postSuccessFormData() {
var targetUrl = '/index.php/install/wizard/successPost';
jQuery('.form-button').addClass('loading');
setInterval(installStatus(),4000);
jQuery.ajax({
url: targetUrl,
global: false,
type: 'POST',
data: ({
finish: 1,
password_key: jQuery('#password_key').val()
}),
async: true,
dataType: 'json',
error: function() {
alert("An error has occurred. Please try again.");
},
success: function(data) {
window.location.href = '/';
}
});
function installStatus() {
var installerUpdatesUrl = '/index.php/install/wizard/installerStatus';
//showProgressBar();
jQuery.ajax({
url: installerUpdatesUrl,
// global: false,
type: 'GET',
async: true,
dataType: 'json',
error: function (data) {
// alert(data.result);
},
success: function (data) {
handle data.result
var dataKeys = Object.keys(data);
var lastElementKey = dataKeys[dataKeys.length - 1];
var lastMessage = data[lastElementKey]['message'];
if(data[lastElementKey]['progress'] == '') {
updateProgressBar(data[dataKeys[dataKeys.length - 2]]['progress'],100);
}
setting message
jQuery("#message").html(lastMessage);
if (data[lastElementKey]['state'] == 'Failure') {
var stepStr = lastElementKey.split('_');
var stepString = stepStr[0].toUpperCase() + ' ' + stepStr[1] + ':';
alert(stepString + "\n" + data[lastElementKey]['message']);
//hideProgressBar();
jQuery('.form-button').removeClass('loading');
return false;
} else if (data[lastElementKey]['state'] == 'Finish') {
alert(data[lastElementKey]['message']);
//hideProgressBar();
jQuery('.form-button').removeClass('loading');
//window.location.href = '/';
} else {
// installStatus();
}
},
complete: function () {
installStatus();
jQuery('.form-button').removeClass('loading');
}
});
}
The way this is done:
After every 4 seconds the function installStatus is run, which will output the current progress in JSON format. My problem is, this function needs to be executed simultaneously with the function post().
This is not happening, the installStatus is only run after the first function has been completed.
What is wrong?
You are executing installStatus when you define it. So this:
setInterval(installStatus(),4000);
needs to be
setInterval(installStatus, 4000);
The new XMLHttpRequest has a nice progress event you can listen to show the user the upload progress.
Here's the spec with a nice demo: https://developer.mozilla.org/en/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Monitoring_progress
Initially you should call installStatus() only once and then inside the method inside ajax success you should update the procent in the progress bar and call it recursively the same method. On the server side you can save the current procent in a cookie and with every recursive call you can update the cookie and return the procent.

Categories