Ajax User Typing message for chat - javascript

I am trying to make a facebook style user typing system. But i have one question about keypress.
So my code is working fine but i want to change something else like keypress, keyup, paste ect.
I am using following javascript and ajax codes. In the following my ajax code is working like if ($.trim(updateval).length == 0) { send width notyping.php notyping.php posting 0 and the 0 is don't show typing message.
If if ($.trim(updateval).length > 13) { send with usertyping.php usertyping.php posting 1 and the 1 is show typing message.
The problem is here if user is stoped to wrire some message then it is everytime saying typing. What should I do to fix for it anyone can help me in this regard ?
All ajax and javascript code is here:
;
(function($) {
$.fn.extend({
donetyping: function(callback, timeout) {
timeout = timeout || 1000; // 1 second default timeout
var timeoutReference,
doneTyping = function(el) {
if (!timeoutReference) return;
timeoutReference = null;
callback.call(el);
};
return this.each(function(i, el) {
var $el = $(el);
// Chrome Fix (Use keyup over keypress to detect backspace)
// thank you #palerdot
$el.is(':input') && $el.is(':input') && $el.on('keyup keypress paste', function(e) {
// This catches the backspace button in chrome, but also prevents
// the event from triggering too premptively. Without this line,
// using tab/shift+tab will make the focused element fire the callback.
if (e.type == 'keypress' && e.keyCode != 8) return;
// Check if timeout has been set. If it has, "reset" the clock and
// start over again.
if (timeoutReference) clearTimeout(timeoutReference);
timeoutReference = setTimeout(function() {
// if we made it here, our timeout has elapsed. Fire the
// callback
doneTyping(el);
}, timeout);
}).on('blur', function() {
// If we can, fire the event since we're leaving the field
doneTyping(el);
});
});
}
});
})(jQuery);
Checking text value if is 0 then send data is 0 for user no typing
$('#chattextarea').donetyping(function() {
var typingval = $("#chattextarea").val();
var tpy = $('#tpy').val();
if ($.trim(typingval).length == 0) {
$.ajax({
type: "POST",
url: "/notyping.php",
data: {
tpy: tpy
},
success: function(data) {
}
});
}
Checking text value is >13 then send data is 1 for user typing.(Maybe need to change this if statement)
if ($.trim(typingval).length > 13) {
$.ajax({
type: "POST",
url: "/usertyping.php",
data: {
tpy: tpy
},
success: function(data) {
}
});
}
});
Check and show user typing:
function getTyping(){
setInterval(function(){
var tpy = $('#tpy').val();
$.ajax({
type: "POST",
url: "/getTyping.php",
data: { tpy: tpy },
success: function(data) {
$('#s').html(data);
}
});
},1000);
}
getTyping();
HTML
<textarea id="chattextarea"></textarea>
<div id="s"></div>

I have some remarks about your code and app :
At the first, and as mentioned by #rory-mccrossan, unless you have the infrastructure of facebook, google or microsoft, ..., I think it's really a bad idea to use Ajax instead of Websockets for a real time application like a chat.
Now about your code, I don't know what your PHP scripts are doing behind the scene, but I think that you don't need to send two requests to indicate that the user is typing or not, you can limit that to one request to be sent when the user is typing otherwise, he is surely not typing. Of course you can use some sort of a timeout in your getTyping.php script to limit the life time of a "typing" status (for example 5 seconds), so if a request is sent after that timeout, you can know that your user is not typing.
And about your current problem, I think that's because the "not typing" status is just fired when the textarea is empty, so of course, after stopping writing and the length of the current text is more that 13, so the "not typing" status will never be fired (sent), that's why you need a timeout as I told you in the 2nd point ...
Also, don't forget the cache problem when getting the status using the getTyping.php script which should be not cacheable (or at least for a very limited period) ...
Then, I don't see in your posted code any information(s) to identify the current user and the one which is converting with him ... maybe you haven't included that in the question, I don't know !
...
Hope that can help.

My suggestion here to have external setInterval which will each 3 seconds save current text in oldValue variable and compare currentText with oldValue if they are equal then user stopped writing then send ajax to notyping.php

your updated code is given below
i have created a getTyping function which will be call at every time 1 sec interval if user get start typing.
in get getTyping setinterval function i called a function check_which_function.
in function check_which_funciton i used your code by applying conditions on textarea value length which is in nested if else statement , so now
if user start typing but if content length is =0 than
$.trim(typingval).length == 0 will execute till length is not equal to 12
if length of content is greather equal to 13 than
$.trim(typingval).length > 13 will execute
by default getTyping2() function is executing in this function getTyping.php ajax call is going
<script>
(function ($) {
$.fn.extend({
donetyping: function (callback, timeout) {
timeout = timeout || 1000; // 1 second default timeout
var timeoutReference,
doneTyping = function (el) {
if (!timeoutReference)
return;
timeoutReference = null;
callback.call(el);
};
return this.each(function (i, el) {
var $el = $(el);
// Chrome Fix (Use keyup over keypress to detect backspace)
// thank you #palerdot
$el.is(':input') && $el.is(':input') && $el.on('keyup keypress paste', function (e) {
// This catches the backspace button in chrome, but also prevents
// the event from triggering too premptively. Without this line,
// using tab/shift+tab will make the focused element fire the callback.
if (e.type == 'keypress' && e.keyCode != 8)
return;
// Check if timeout has been set. If it has, "reset" the clock and
// start over again.
if (timeoutReference)
clearTimeout(timeoutReference);
timeoutReference = setTimeout(function () {
// if we made it here, our timeout has elapsed. Fire the
// callback
doneTyping(el);
}, timeout);
}).on('blur', function () {
// If we can, fire the event since we're leaving the field
doneTyping(el);
});
});
}
});
})(jQuery);
function getTyping2() {
var tpy = $('#tpy').val();
$.ajax({
type: "POST",
url: "/getTyping.php",
data: {tpy: tpy},
success: function (data) {
$('#s').html(data);
}
});
}
function check_which_action() {
$('#chattextarea').donetyping(function () {
var typingval = $("#chattextarea").val();
var tpy = $('#tpy').val();
if ($.trim(typingval).length == 0) {
$.ajax({
type: "POST",
url: "/notyping.php",
data: {
tpy: tpy
},
success: function (data) {
}
});
}
else if ($.trim(typingval).length > 13) {
$.ajax({
type: "POST",
url: "/usertyping.php",
data: {
tpy: tpy
},
success: function (data) {
}
});
}
else {
getTyping2() ;
}
});
}
function getTyping() {
setInterval(check_which_action, 1000);
}
getTyping();
</script>
<textarea id="chattextarea"></textarea>
<div id="s"></div>

Related

Limiting ajax call per input

I have a working ajax call that I've made which sends a value to an endpoint for every input change. SO if the user is typing, it sends the call per keystroke.
I put a setTimeout around it for 2 seconds, which delays the call just fine. But the problem is it still sends a call for every keystroke.
I want to get it to where, after 2 seconds, it sends a call for what's been typed so far. If the user starts typing again maybe it would set again.
I"m just trying to send fewer keystrokes and make it to where when the user stops typing there's just a slight delay and call.
Here's the call now:
$('#input').on('input', function() {
let _this = $(this);
if (_this.val() === '') {
return;
} else {
const searchResult = $(this).val();
console.log(searchResult);
//if I type "PLANT" the console shows "P" "PL" "PLA" "PLAN" "PLANT"
//after 2 seconds, send searchResult via ajax
setTimeout(function () {
$.ajax({ url: '/endpoint',
data: {
search_result:searchResult
},
"_token": "{{ csrf_token() }}",
type: "POST",
success: successHandler
});
}, 2000);
}
});
You should debounce the ajax call. The idea is that the timeout is cleared if the user enters another value. That way the ajax call will only be made once after the user has stopped typing for the given timeout period (2 seconds for your case). That would look something like this:
var timeout;
$('#input').on('input', function() {
let _this = $(this);
if (_this.val() === '') {
return;
} else {
const searchResult = $(this).val();
console.log(searchResult);
//if I type "PLANT" the console shows "P" "PL" "PLA" "PLAN" "PLANT"
if (timeout) {
clearTimeout(timeout);
}
//after 2 seconds, send searchResult via ajax
timeout = setTimeout(function () {
$.ajax({ url: '/endpoint',
data: {
search_result:searchResult
},
"_token": "{{ csrf_token() }}",
type: "POST",
success: successHandler
});
}, 2000);
}
});

Javascript- How to check if operation has been completed on this event

Is there any way to check if the event is completed and element is free to perform another action?
Like I want to do
$('#button-cancel').on('click', function() {
// send ajax call
});
/****************************************
extra code
*******************************************/
$('#button-cancel').on('click', function() {
if(ajax call is completed) {
//do some thing
}
});
I don't want to send ajax call in second onclick as it is already been sent, just want to check if it is done with ajax then do this
You can introduce a helper variable:
// introduce variable
var wasAjaxRun = false;
$('#button-cancel').on('click', function() {
// in ajax complete event you change the value of variable:
$.ajax({
url: "yoururl"
// other parameters
}).done(function() {
// your other handling logic
wasAjaxRun = true;
});
});
$('#button-cancel').on('click', function() {
if(wasAjaxRun === true) {
//do some thing
}
});
EDIT: I just noticed that you have event handlers attached to the same button. In that case my initial answer would not work, because first event hander would be executed every time you click the button.
It is not very clear from the description what you want to do with your first event hander. I assume you want to use some data, and if you already have this data, then you use it immediately (like in second handler), if you don't have it - you make the AJAX call to get the data (like in first handler).
For such scenario you could use single event handler with some conditions:
var isAjaxRunning = false; // true only if AJAX call is in progress
var dataYouNeed; // stores the data that you need
$('#button-cancel').on('click', function() {
if(isAjaxRunning){
return; // if AJAX is in progress there is nothing we can do
}
// check if you already have the data, this assumes you data cannot be falsey
if(dataYouNeed){
// You already have the data
// perform the logic you had in your second event handler
}
else { // no data, you need to get it using AJAX
isAjaxRunning = true; // set the flag to prevent multiple AJAX calls
$.ajax({
url: "yoururl"
}).done(function(result) {
dataYouNeed = result;
}).always(function(){
isAjaxRunning = false;
});
}
});
You should be able to provide handlers for AJAX return codes. e.g
$.ajax({
type: "post", url: "/SomeController/SomeAction",
success: function (data, text) {
//...
},
error: function (request, status, error) {
alert(request.responseText);
}
});
you can disable the button as soon as it enters in to the event and enable it back in ajax success or error method
$('#button-cancel').on('click', function() {
// Disable button
if(ajax call is completed) {
//do some thing
//enable it back
}
});
This is edited, more complete version of dotnetums's answer, which looks like will only work once..
// introduce variable
var ajaxIsRunning = false;
$('#button').on('click', function() {
// check state of variable, if running quit.
if(ajaxIsRunning) return al("please wait, ajax is running..");
// Else mark it to true
ajaxIsRunning = true;
// in ajax complete event you change the value of variable:
$.ajax({
url: "yoururl"
}).done(function() {
// Set it back to false so the button can be used again
ajaxIsRunning = false;
});
});
You just need to set a flag that indicates ajax call is underway, then clear it when ajax call returns.
var ajaxProcessing = false;
$('#button-cancel').on('click', function(){
processAjaxCall();
});
function processAjaxCall() {
if(ajaxProcessing) return;
ajaxProcessing = true; //set the flag
$.ajax({
url: 'http://stackoverflow.com/questions/36506931/javascript-how-to-check-if-operation-has-been-completed-on-this-event'
})
.done(function(resp){
//do something
alert('success');
})
.fail(function(){
//handle error
alert('error');
})
.always(function(){
ajaxprocessing = false; //clear the flag
})
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="button-cancel">Cancel</button>
What you can do is call a function at the end of an if statement like
if(ajax call is completed) {
checkDone();
}
function checkDone() {
alert("Done");
}

How to use mouse event to do AJAX call only if user is idle for X seconds

Apologies if this is a repost. I have seen many examples. But I can't seem to put together my needs.
I have a "today" page which displays all groups. Throughout the day more and more groups will appear. I want to be able to dynamically update these groups if the user has the page open and hasn't moved the mouse for X seconds. I have this chunk of code:
var timeout = null;
j$(document).on('mousemove', function() {
if (timeout !== null) {
clearTimeout(timeout);
}
timeout = setTimeout(function() {
timeout = null;
//calls another page to check if there's new data to display. if so, wipe existing data and update
j$.ajax({
url: "/include/new_Groups.php",
cache: false,
success: function(data){
j$( ".group_Container_Main" ).append( data ).fadeIn('slow');
}
})
.done(function( html ) {
});
}, 3000);
});
What this is doing is if the user hasn't moved the mouse after 3 seconds, do an AJAX call to update the group. This semi works. If you don't move the mouse, it will update. But it won't update again unless the mouse is moved and idle again for 3 seconds which is not good user experience.
I'm trying to find a way to just continually update the page every 3 seconds (for this example) if the user is idle. But if he's moving the mouse, there is to be no updating. Please ask questions if I'm unclear! Thanks in advance.
Should be straigh forward, use an interval and a function call instead
jQuery(function($) {
var timer;
$(window).on('mousemove', function() {
clearInterval(timer);
timer = setInterval(update, 3000);
}).trigger('mousemove');
function update() {
$.ajax({
url : "/include/new_Groups.php",
}).done(function (html) {
$(".group_Container_Main").append(html).fadeIn('slow')
});
}
});
FIDDLE
EDIT:
To solve the issue of stacking ajax requests if for some reason they take more than three seconds to complete, we can just check the state of the previous ajax call before starting a new one, if the state is pending it's still running.
jQuery(function($) {
var timer, xhr;
$(window).on('mousemove', function() {
clearInterval(timer);
timer = setInterval(update, 1000);
}).trigger('mousemove');
function update() {
if ( ! (xhr && xhr.state && xhr.state == 'pending' ) ) {
xhr = $.ajax({
url : "/include/new_Groups.php",
}).done(function (html) {
$(".group_Container_Main").append(data).fadeIn('slow')
});
}
}
});
On the AJAX parameter, use the complete option to trigger a mouse move :
j$(document).on('mousemove', function() {
if (timeout !== null) {
clearTimeout(timeout);
}
timeout = setTimeout(function() {
timeout = null;
//calls another page to check if there's new data to display. if so, wipe existing data and update
j$.ajax({
url: "/include/new_Groups.php",
cache: false,
success: function(data){
j$( ".group_Container_Main" ).append( data ).fadeIn('slow');
},
complete: function(data){
j$(document).trigger('mousemove');
}
})
.done(function( html ) {
});
}, 3000);
});
You can invert your timer idea to this logical connection...
Set a timer for 3 seconds after which you will do the AJAX call
If the mouse is moved, reset the timer for 3 seconds
You now have a three second timer running whether or not the mouse is moved and you reset it on mouse move to get the behaviour you want in respect of only updating on idle.
var timeout = setTimeout(update, 3000);
function update() {
clearTimeout(timeout);
//calls another page to check if there's new data to display. if so, wipe existing data and update
j$.ajax({
url: "/include/new_Groups.php",
cache: false,
success: function(data){
j$( ".group_Container_Main" ).append( data ).fadeIn('slow');
}
}).done(function(html) {
}).always(function() {
timeout = setTimeout(update, 3000);
});
}
j$(document).on('mousemove', function() {
clearTimeout(timeout);
timeout = setTimeout(update, 3000);
});
You should use setInterval() instead of setTimeout() to make a repeating event.
I would call setInterval() outside of your event handler code, and then make your event handler code update a lastTimeMouseMoved (or something) timestamp, which would be checked by the code passed to your setInterval() call.
So, your code might look like this:
const IDLE_TIME = 3000;
var lastTimeMouseMoved = Date.now();
timer = setInterval(function() {
if(Date.now() - lastTimeMouseMoved >= IDLE_TIME) {
//calls another page to check if there's new data to display. if so, wipe existing data and update
j$.ajax({
url: "/include/new_Groups.php",
cache: false,
success: function(data){
j$( ".group_Container_Main" ).append( data ).fadeIn('slow');
}
})
.done(function( html ) { });
} // end idle if
}, IDLE_TIME);
j$(document).on('mousemove', function() {
lastTimeMouseMoved = Date.now();
});

Multiple ajax Allow only latest call

I have an input box on which there is an ajax request on every key press. so if i enter word "name" there will be 4 successful request. So i actually want only the latest request of executed. so if i enter word "name" there will be only one request which will be the last one.
and i also have a solution for this (this is a simple example with click method)
JS script
var callid = 1;
function ajaxCall (checkval ){
if(checkval == callid){
$.ajax({
type: 'post',
url: baseurl + "test/call_ajax",
data: {
val: "1"
},
success: function(data) {
console.log(data)
}
});
}
}
function call(){
var send = callid+=1;
setTimeout( function(){ ajaxCall(send) } , 500);
}
html script
<a href="#" onclick="call()" > Call ajax </a>
This is working perfectly. But i was think if there is way to refine it a little bit more.
Any ideas :)
I am sure you are looking some better intent technique for event dispatching.
var eventDispatcher = null;
$('.textbox').keyup(function(){
if(eventDispatcher) clearTimeout(eventDispatcher);
eventDispatcher = setTimeout(function(){
$.ajax({ ... });
}, 300);
});
You could do your ajax inside of a setTimeout. So you don't need to declare and check an additional variable or write another function like call()
$(document).ready(function () {
var timer;
$('#fillMe').keypress(function () {
clearTimeout(timer);
timer = setTimeout(function () {
//replace this with your ajax call
var content = $('#fillMe').val();
$('#result').text('You will only see this if the user stopped typing: ' + content);
}, 1000); // waits 1s before getting executed
});
});
<input type="text" id="fillMe">
<div id="result"></div>
On every keypress event this clears the timeout and immediately creates a new timeout. This means the content of the setTimeout function only gets executed if the user stopped typing for at least 1 second.
Of course 1 second is just the value for the example purpose. You can change it to whatever you want or think is a good time (like 500ms)
See my jsfiddle
setTimeout returns an id that you can store and use to clear the previously set timer:
var timerId;
function call() {
if (timerId !== undefined) {
clearTimeout(timerId);
}
timerId = setTimeout( function() { ajaxCall(send) }, 500);
}
The result of this should be that the ajaxCall method will be called 500ms after the last letter is entered.

Jquery ajax live validation / timeout question

I'm still kindof new to jQuery, so there probably is an easy solution, but I can't find anything.
I've made this registration form, that checks if the username or email is taken as the user is typing in the username. Basically it just makes a json request that returns true or false depending on if the username / email is already taken.
The problem is, that now it makes a request on basically every keypress that the user makes while focused on the field if the input text is more than 3 characters long. For now, that works, but that's a lot of server requests. I'd like it to make a request only when the user has not typed for, say, a half second.
Any ideas on how I might be able to do that ?
$(document).ready(function() {
$("#user_username").keyup(function () {
var ln = $(this).val().length;
if (ln > 3) {
$.getJSON("/validate/username/",
{value:$(this).val()},
function(data){
if (data.reg == true) {
$("#status-for-username").html("Username already in use");
} else {
$("#status-for-username").html("Username available");
}
});
}
});
$("#user_email").keyup(function () {
var ln = $(this).val().length;
if (ln > 3) {
$.getJSON("/validate/email/",
{value:$(this).val()},
function(data){
if (data.reg == true) {
$("#status-for-email").html("E-mail already in use");
} else {
$("#status-for-email").html("");
}
});
}
});
});
For waiting an amount of time since the last keystroke, you could do something like the jQuery.typeWatch plugin does.
Here I post you a light implementation of the concept:
Usage:
$("#user_username").keyup(function () {
typewatch(function () {
// executed only 500 ms after the last keyup event.
}, 500);
Implementation:
var typewatch = function(){
var timer = 0; // store the timer id
return function(callback, ms){
clearTimeout (timer); // if the function is called before the timeout
timer = setTimeout(callback, ms); // clear the timer and start it over
}
}();
StackOverflow uses the plugin I mention, for syntax coloring the code on edition.
You can use window.setTimeout and window.clearTimeout. Basically trigger a function to invoke in x milliseconds and if another keypress event is fired beforehand then you clear that handler and start a new one.
//timeout var
var timer;
$('#username').keyUp( function(){
//clear any existing timer
window.clearTimeout( timer );
//invoke check password function in 0.5 seconds
timer = window.setTimeout( checkPasswordFunc, 500 );
});
function checkPasswordFunc(){
//ajax call goes here
}

Categories