Javascript jquery - How do I build a delay into the search entry - javascript

I have an ajax search box that goes to the server on every key stroke and returns the result of the search.
When the user types quickly, I want to search only on the last entry and not on every key stroke. Otherwise the individual results flash annoyingly and the whole process is slowed.
For example: if the user types "statue of liberty" quickly, I don't want to search on "sta", "stat", "statu" etc.
the basics of my jQuery code is:
$('#searchbox').keyup(function(){
if (this.value.length > 2) {
$.post("remote.php",{'partial':this.value},function(data){
$("#gen_results").html(data);
});
}
});
<input id="searchbox" />
<div id="gen_results"></div>

use setTimeout or jQuery's autocomplete plugin
var timer;
$('#searchbox').keyup(function(){
if (this.value.length > 2) {
if (timer){
clearTimeout(timer);
}
timer = setTimeout(function(){
$.post("remote.php",{'partial':this.value},function(data){
$("#gen_results").html(data);
});
}, 1000);
}
});

You need to use a timeout, this one is set to 500ms, but you might want to go quicker.
$('#searchbox').keyup(function(){
window.clearTimeout(window.timeOutId);
window.timeOutId = window.setTimeout(function() {
if (this.value.length > 2) {
$.post("remote.php",{'partial':this.value},function(data){
$("#gen_results").html(data);
});
}
},500);
});
Hope that works for you!

Try this
var inProgress = false;
$('#searchbox').keyup(function(){
if (this.value.length > 2 && !inProgress) {
inProgress = true;
$.post("remote.php",{'partial':this.value},function(data){
$("#gen_results").html(data);
inProgress = false;
});
}
});
This way you dont have to maintain a timer, just another call if the previous call is complete and by that time user has typed something more.

function getResults(value) {
return function() {
$.post("remote.php",{'partial':value},function(data){
$("#gen_results").html(data);
});
};
}
var timerId;
$('#searchbox').keyup(function(){
if (this.value.length > 2) {
clearTimeout(timerId);
timerId = setTimout(getResults(this.value), 1000);
}
});

I did something similar once. What I did was set a timer each 500ms, and when the timer is called it does the AJAX request. The trick is that whenever the user typed something, I would reset the timer.

You could have a global variable holding the timestamp of the last keystroke. When the keyup method is called, take a timestamp reading and compare it to the previous value. If it is over a certain time frame, make your call, otherwise, reset the global value and exit.

Instead of building this yourself have a look at the jQuery Autocomplete plugin.
Using this you can set a delay option so that requests wait for a given period after a keystroke.
The delay in milliseconds the Autocomplete waits after a keystroke to
activate itself. A zero-delay makes sense for local data (more
responsive), but can produce a lot of load for remote data, while
being less responsive.

Related

onkeyup activates many ajax requests

In an entry I use the onkeyup function so that every time I type it, I activate a javascript function, which makes requests to the server using ajax, the problem arises when the user types quickly, so with each key that he / she touches, activates an ajax request which causes me many requests, and also brings me bad results.
I do not know if it is understood, I hope someone can give me an idea of ​​how to change this.
Thank you
This kind of ajax call is not good idea.
Anyhow,
You should do ajax call when user has typed at least 3-4 letters.
You can also add some a check to see if user has typed something and stopped writing then do the ajax.
If you still want to do ajax on each character then try to do very light ajax means get very small data from server.
Check if input length is > 3:
var userInput = $('#inputFiled').val(); // get user input and save into js variable
if(userInput.length > 3){ //if user input is at least 3 characters
//do ajax here
}
To check if user has stopped writing
To do so you will have to use underscore.js
$('#userInout').keyup(_.debounce(yourAjaxCallFunctionHere , 500));
underscorejs.org/#debounce
You can also achieve this using jQuery
var delayInAjaxCall = (function(){
var timer = 0;
return function(callback, milliseconds){
clearTimeout (timer);
timer = setTimeout(callback, milliseconds);
};
})();
Usage Of Above Function
$('input').keyup(function() {
delayInAjaxCall(function(){
alert('Hi, func called');
}, 1000 );
});
You can utilize the below JS code and achieve with few lines of codes,
let timer = null;
on_key_up(){
//if input length < 3 return it
if(timer){
window.clearTimeout(timer);
timer = null;
}
timer = window.setTimeout( ()=>{
FireMyEvent()
}, 1000);
}

Continual counter regardless of page refresh

I have this piece of jQuery that currently increments a number by one every 5 seconds. The problem I have is that its client side, therefore it resets every time you refresh the page.
Instead I'd like the counter to continue even if you are away from the site and regardless of how many times you refresh the page, which is why I thought a server side script such as PHP would be better suited to my use case. If not please suggest otherwise.
I've setup a working fiddle of what I currently have with jQuery: http://jsfiddle.net/f354bzy5/
What would be the PHP to recreate this affect that include my requirements above?
Here's the Jquery I'm using:
//Counter
var counter = 22000000000;
$(".count").html(counter);
setInterval(function () {
$(".count").html(counter);
++counter;
}, 5000);
Check this DEMO
//Counter
var counter=22000000000;
if(typeof(localStorage.getItem('counts'))!='object')
{
counter=parseInt(localStorage.getItem('counts'));
}
setInterval(function () {
$(".count").html(counter);
++counter;
localStorage.setItem('counts',counter);
}, 1000);
Highlight on localStorage
localStorage is an implementation of the Storage Interface. It stores
data with no expiration date, and gets cleared only through
JavaScript, or clearing the Browser Cache / Locally Stored Data -
unlike cookie expiry.
Can you store counter in cookie.
document.cookie = counter.
so you can get last value from cookie, if user refresh the page.
It comes down to two simple choices for you. Just choose the right one which better fits your requirement:
Choose Cookie : If you want the server side to access the counter. Remember cookies are sent along with the requests by default.
Choose Local Storage : If you don't want to send the counter along with requests every time, you are supposed to go for local storage.
You could do it with localStorage. Here's how I am doing it. You can tweak it as you need.
//detecting support for localStorage.
if (window.localStorage) {
//counterValue already exists in localStorage? Let's use that or set to zero.
var counterValue = localStorage.counterValue || 0;
setInterval(function() {
//increment the counter and store updated vale in localStorage as well.
localStorage.counterValue = ++counterValue;
//put it in your HTML if you might
$(".count").html(counterValue);
}, 5000);
}
How about using localStorage with some utility functions? Bear in mind that this is a client side solution and the item would be wiped off when the user deletes the browser cache/local data etc.
function isLocalStorage() {
try {
return 'localStorage' in window && window['localStorage'] !== null;
} catch(e) {
return false;
}
}
function setCounter(key, val) {
localStorage.setItem(key, val);
}
function getCounter(key) {
return parseInt(localStorage.getItem(key), 10);
}
(function() {
var key = "myCounter";
var counter = isLocalStorage() && getCounter(key) || 1;
var $placeholder = $(".count");
$placeholder.html(counter);
setInterval(function () {
counter++;
$placeholder.html(counter);
isLocalStorage() && setCounter(key, counter);
}, 2000);
}());
-- Demo --

Alert Bar rather than alert box

I now have a script that prevents users from entering anything but a state abbreviation in the state field of my form. Thanks to gideon
I modified the script just a little to include an alert message when an invalid state is entered. But I don't really like it. I am going for an alert bar that flashes on the top of the page or maybe right below the field. Something that appears automatically when an incorrect abbreviation is entered and flash to grab the users attention and disappear after a few seconds. Any ideas or thoughts would be welcome! I am VERY open to suggestions! Thanks once again!
I am starting to think you guy's are not understanding me. This is the code I have:
<script>
function validateState(el) {
//put all states in this array.
var states = ["AK","AL","AR","AS","AZ","CA","CO","CT","DC","DE",
"FL","GA","GU","HI","IA",
"ID","IL","IN","KS","KY","LA","MA","MD","ME","MH","MI","MN","MO","MS","MT",
"NC","ND","NE","NH","NJ","NM","NV","NY","OH","OK","OR","PA","PR","PW","RI",
"SC","SD","TN","TX","UT","VA","VI","VT","WA","WI","WV","WY"];
for(var i=0;i< states.length;i++) {
if(el.value.toUpperCase() == states[i]) {
return true;
}
}
//clear element if it doesn't match a state
el.value = ""; //you could maybe do something else here.
alert('Invalid State Abbreviation, You must fix this before continuing')
document.getElementById("state").focus();
return false;
}
</script>
I am wanting to have a bar run across the screen if the statement returns false.
You can simple create an element that with be positioned above the view of the user (top: -100px etc). Once an invalid state has been entered you can use a Library like jQuery to animate it to top position 0. You can make it flash with a simple conditional statement inside of a setInterval();
I'm not sure if you are wanting to use jQuery but if you do then your code would look something like this:
//if the input is not what you expect..
if(input != state){
//drop the bar down
$("#bar").animate({
top: 0
}, 1500);//drop it in 1500 milliseconds.
//this is a lot like a loop that runs every 400 milliseconds..
setInterval(function () { <-------------------------------|
if ($("#bar").css("display") == 'none') { |
//if the bar is HIDDEN show it.. |
$("#bar").show(); |
} else { |
//else hide it. |
$("#bar").hide(); |
} |
}, 400);//<< EVERY 400 milli-seconds go here >-------------^
}
Of course this is just an example and can easily be translated back to traditional JavaScript.
Check out the jsFiddle.
I hope this is what you are looking for.
Adapting #Shawn's code, you'll need a function to show the bar and hide the bar, I've removed the code that makes the bar blink:
function ShowError(txt)
{
$("#bar").show();
$("#bar").text(txt);
$("#bar").animate({
top: 0
}, 1500);
}
function ClearError()
{
$("#bar").hide();
}
Then later on you will just do:
if(el.value.toUpperCase() == states[i]) {
ClearError();
return true;
} else {
ShowError("Please Enter a valid state");
}
See the whole code running here: http://jsfiddle.net/grFT7/8/
To make the bar disappear at some point you would do:
setInterval(function () { $("#bar").hide(); }, 5000);
//hide the bar every 5 secs (5000 milliseconds).
Use BootStrap's Alert. It is easy to use and looks cool.

I need a new way to detect if there has been a change to an elements HTML

Right now im trying to find a way to detect when an elements HTML has changed.
I'm currently trying:
var a, b;
setInterval(function() {
a = $('#chat').text();
}, 150);
setInterval(function() {
b = $('#chat').text();
if (a !== b) {
alert("There has been a new message.");
}
}, 200);​
What I do is every 150 milliseconds I check for the HTML of #chat and then every 200 seconds I check the HTML again and then check if variable a does not equal to variable b them in the future I will so something with that but for right now I just alert something.
You can see it live here: http://jsfiddle.net/MT47W/
Obviously this way is not working and is not very accurate at all.
Is there a better/different to do/achieve this?
Thanks for any help, I've been trying to figure out how to do this a better for about a week now but I just can't find a fix for this and i'm hoping I posted this problem at the right place, and at the right time.
Use a var to store the element's current text then check against it in a setInverval and update the var to store the current text after checking:
var a = $('#chat').text();
setInterval(function() {
if (a !== $('#chat').text()) { //checks the stored text against the current
alert("There has been a new message."); //do your stuff
}
a = $('#chat').text(); //updates the global var to store the current text
}, 150); //define your interval time, every 0.15 seconds in this case
Fiddle
You may as well store the value in the .data() of the element to avoid using globals.
Example using .data():
$('#chat').data('curr_text', $('#chat').text());
setInterval(function() {
if ($('#chat').data('curr_text') !== $('#chat').text()) {
alert("There has been a new message.");
}
$('#chat').data('curr_text', $('#chat').text());
}, 150);
Fiddle
Another approach, to save client's memory, you can just store the number of child divs your #chat element has:
$('#chat').data('n_msgs', $('#chat').children().length);
setInterval(function() {
if ($('#chat').data('n_msgs') !== $('#chat').children().length) {
alert("There has been a new message.");
}
$('#chat').data('n_msgs', $('#chat').children().length);
}, 150);
Fiddle
EDIT: Here's my very final addition, with a DOM mutation event listener:
$('#chat').on('DOMNodeInserted', function() {
alert("There has been a new message.");
});
Fiddle (not tested in IE < 8)
Note: As noted in the comments, even though mutation events are still supported they're classed as deprecated by W3C due to the performance loss and some incompatibilities across different browsers, therefore it's suggested to use one of the solutions above and only use DOM Mutation events when there's no other way around.
Just checking the last chat would improve efficiency and also do what you want. The only way that it would not work is if the same person sends the same message twice - which most likely will not happen.
I hope this would work:
var lastMessage = $('#chat .body').last().text();
function checkMessages(){
var newLastMessage = $('#chat .body').last().text();
if(lastMessage !== newLastMessage && $('#chat .body').last().length > 0){
//message has changed
alert("There has been a new message.");
lastMessage = $('#chat .body').last().text();
}
setTimeout(function(){checkMessages();},1000);
}
checkMessages();
Js Fiddle
Use crc32 or md5 hashing to check whether data has changed. Just get the html content of the div that you want to check, hash it as a string with either crc32 or md5 and you'll get a string that will represent that content. Use a hidden timestamp etc to be sure that multiple messages by one user get a different hash. If you do this in a setInterval callback, you should be good.
Although it is not highly recommended, it is also possible to use Paul Irish's Duck punching method to tie into jQuery's append function - if you know for sure that the append function is how content is being added (demo):
(function($) {
// store original reference to the method
var _old = $.fn.append;
$.fn.append = function(arg) {
// append as usual
_old.apply(this, arguments);
// do your own checking here
// "this" is a jQuery object
if (this[0].id === "chat") {
alert('there is a new message!');
}
return this;
};
})(jQuery);
With this method, no timing loops are needed.

jQuery event only every time interval

$(document).ready(function() {
$('#domain').change(function() {
//
});
});
The code inside the change function will basically send ajax request to run a PHP script. The #domain is a text input field. So basically what I want to do is to send ajax requests as user types in some text inside the text field (for example search suggestions).
However, I would like to set a time interval in order to lessen the load of PHP server. Because if jQuery sends AJAX request every time user adds another letter to the text field it would consume lots of bandwidth.
So I would like to set let's say 2 seconds as an interval. The AJAX request will be fired every time the user types a letter but with maximum frequency of 2 seconds.
How can I do that?
$(function() {
var timer = 0;
$("#domain").change(function() {
clearTimeout(timer);
timer = setTimeout(function(){
// Do stuff here
}, 2000);
});
});
$(document).ready(function() {
var ajaxQueue;
$('#domain').change(function() {
if(!ajaxQueue) {
ajaxQueue = setTimeout(function() {
/* your stuff */
ajaxQueue = null;
}, 2000);
}
});
});
What you really want to do is check how long since the last change event so you keep track of the number of milliseconds between events rather than make a call every 2 seconds.
$(document).ready(function() {
var lastreq = 0; //0 means there were never any requests sent
$('#domain').change(function() {
var d = new Date();
var currenttime = d.getTime(); //get the time of this change event
var interval = currenttime - lastreq; //how many milliseconds since the last request
if(interval >= 2000){ //more than 2 seconds
lastreq = currenttime; //set lastreq for next change event
//perform AJAX call
}
});
});
Off the top of my head without trying this in a browser. Something like this:
$('#domain').change(function() {
if (!this.sendToServer) { // some expando property I made up
var that = this;
this.sendToServer = setTimeout(function(that) {
// use "that" as a reference to your element that fired the onchange.
// Do your AJAX call here
that.sendToServer = undefined;
}, yourTimeoutTimeInMillis)
}
else {
clearTimeout(this.sendToServer);
}
});
two variables, charBuffer, sendFlag
Use a setTimeout to have a function be called every two seconds.
This function checks if the buffer has stuff in it.
If it does, it sends/empties the stuff and clears the sent flag (to false).
and It should also clear the timeout, and set it again
else it sets the flag (to true).
Everytime the user hits a key, store it in the buffer.
if the sent flag is clear (it's false), do nothing.
else (it's true) send/empty the stuff currently in the buffer and clear the flag (to false),
and It should also clear the timeout, and set it again
This will make it so that the first time you press a key, it is sent, and a minimum of 2 seconds must pass before it can send again.
Could use some tweaking, but i use this setup to do something similar.
I am coming across this problem more and more (the more i do UI ajax stuff) so i packaged this up into a plugin available here

Categories

Resources