MySQL / AJAX / jQuery Autocomplete - javascript

I am attempting to make a search bar on the top of my website which will search through a table with relatively low stringency. Basically, the user types a key word corresponding to one of the three columns below and they will send an AJAX request and a link to the corresponding page will pop up in my div.
For some reason, no matter what I try, I can't get the "5gooper" entry to show up. When I search "a" or "aa", the other two show up but no combination of letters will return the 5gooper entry. Here is my code:
PHP
$searchquery = $_POST['searchquery'];
$searchquery2 = "%$searchquery%";
$query = "SELECT * FROM data WHERE
name LIKE '$searchquery2'
OR author LIKE '$searchquery2'
OR project LIKE '$searchquery2'
OR protocol LIKE '$searchquery2'
ORDER BY DATE DESC LIMIT 20";
AJAX
$('#sbar').keyup(function(){
var query = $(this).val();
$.ajax
({
url: "autocomplete.php",
data: {searchquery: query},
type: 'POST',
success: function(data){
$('#acd').html(data); //acd stands for auto complete div
}
});
});
Any idea as to why the search isn't entirely working? Even with flanking '%'s, it won't find the gooper entry, no matter what I type.
Thanks

This is how I would do it:
$('#search-input input[type=text]').on('keyup', function(){
var input = $('#search-input input[type=text]').val();
var $name = $.trim(input);
if($name.length > 3 && $name.length < 25) {
delay(function() {
var url = encodeURI("search/" + $name);
$.ajax({
url: url,
type: "get",
dataType: 'json',
success: function(data) {
console.log(data);
}
});
}, 500);
}
});
and my delay function
var delay = (function() {
var timer = 0;
return function(callback, ms){
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
})();
This is for GET and can easily be changed to POST. It's equipped with spam protection by executing the ajax call every 500 ms and the character range can be adjusted to work after x characters but no more than x characters.

Related

Insert data into MySQL Databse with PHP/AJAX, execute success option AFTER it's inserted (Callback)

I've been trying to make a simple site, and I can't quite wrap my head around some of the things said here, some of which are also unrelated to my situation.
The site has a form with 3 input boxes, a button, and a list. The info is submitted through a separate PHP file to a MySQL database, once the submit button is clicked. I'm supposed to make the list (it's inside a div) update once the info is successfully sent and updated in the database. So far I've made it work with async:false but I'm not supposed to, because of society.
Without this (bad) option, the list doesn't load after submitting the info, because (I assume) the method is executed past it, since it doesn't wait for it to finish.
What do I exactly have to do in "success:" to make it work? (Or, I've read something about .done() within the $.ajax clause, but I'm not sure how to make it work.)
What's the callback supposed to be like? I've never done it before and I can get really disoriented with the results here because each case is slightly different.
function save() {
var name = document.getElementById('name');
var email = document.getElementById('email');
var telephone = document.getElementById('telephone');
$.ajax({
url: "save.php",
method: "POST",
data: { name: name.value, email: email.value, telephone: telephone.value },
success: $("List").load(" List")
});
}
Thank you in advanced and if I need include further info don't hesitate to ask.
From this comment
as far as i know the success function will be called on success you should use complete, A function to be called when the request finishes (after success and error callbacks are executed). isnt that what you want ? – Muhammad Omer Aslam
I managed to solve the issue simply moving the $.load clause from the success: option to a complete: option. (I think they're called options)
I haven't managed error handling yet, even inside my head but at least it works as it should if everything is entered properly.
Thanks!
(Won't let me mark as answered until 2 days)
I would first create an AJAX call inside a function which runs when the page loads to populate the list.
window.onload = populatelist();
function populatelist() {
$.ajax({
type: "POST",
url: "list.php",
data: {function: 'populate'},
success: function(data) { $("#list").html("data"); }
});
}
Note: #list refers to <div id="list> and your list should be inside this.
I would then have another AJAX call inside a different function which updates the database when the form is submitted. Upon success, it will run the populatelist function.
function save() {
var name = document.getElementById('name');
var email = document.getElementById('email');
var telephone = document.getElementById('telephone');
$.ajax({
type: "POST",
url: "list.php",
data: {function: 'update', name: name.value, email: email.value, telephone: telephone.value },
success: function() { populatelist(); }
});
}
list.php should look like this:
<?php
if($_POST['function'] == "populate") {
// your code to get the content from the database and put it in a list
}
if($_POST['function'] == "update") {
// your code to update the database
}
?>
I will show you piece of solution that I use in my project. I cannot say it is optimal or best practices, but it works for me and can work for you:
PHP:
function doLoadMails(){
//initialize empty variable
$mails;
$conn = new mysqli($_POST['ip'], $_POST['login'], $_POST['pass'], $_POST['db']);
// Check connection
if ($conn->connect_error) {
die("");
}
//some select, insert, whatever
$sql = "SELECT ... ... ... ";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
// output data of each row, j is counter for rows
$j =0;
while($row_a = $result->fetch_assoc()) {
//for each row, fill array
$mails[$j][0] = $row_a["name"] ;
$mails[$j][1] = $row_a["mail"] ;
$mails[$j][2] = $row_a["language"] ;
$j++;
}
}
//if $mails has results (we added something into it)
if(isset($mails)){
echo json_encode($mails);/return json*/ }
else{
//some error message you can handle in JS
echo"[null]";}
}
and then in JS
function doLoadMails() {
$.ajax({
data: { /*pass parameters*/ },
type: "post",
url: "dataFunnel.php",
success: function(data) { /*data is a dummy variable for everything your PHP echoes/returns*/
console.log(data); //you can check what you get
if (data != "[null]") { /*some error handling ..., in my case if it matches what I have declared as error state in PHP - !(isset($mails))*/ }
}
});
Keep in mind, that you can echo/return directly the result of your SQL request and put it into JS in some more raw format, and handle further processing here.
In your solution, you will probably need to echo the return code of the INSERT request.

Ajax Requests Slow in Django

I have the following ajax request in my django template:
$('#subjects').on('change', function() {
var subject = $('#subjects').find(":selected").text();
$.ajax({
type: "GET",
url: "/classes/" + term + "/" + subject , // or just url: "/my-url/path/"
dataType: "html",
success: function(data) {
$('#classes').html(data);
}
});
//remove courses
//remove overview
//get courses for specified subject
//put them under course
});
The "subject" id is for a select form like this:
<select size="7" class="form-control" id="subjects">
{% for subject in subjects %}
<option>{{ subject }}</option>
{% endfor %}
</select>
So, when a subject is changed, I send an ajax request to the server so that I can get the classes for that subject from the database (as there are thousands of classes). However, this takes ~1 second. If a user simply arrows down my list of subjects, then tens of ajax requests will be fired off in a second, causing a backup and slowing down the data being displayed properly.
I tried aborting all previous ajax requests before sending another one, but the problem is the server will still process these, so it did not fix the problem.
Is there any way to speed this up, and somehow only take 1 second any time a user scrolls down to a subject? Or, is there another method that anyone would recommend?
Follow up question. Another way I just thought of would be to only send the ajax request if an option is selected for longer than 1 second. this would make it take 2 seconds which is fine. Is there a way to do this?
Answering to your follow up question, here is a jQuery function that allow to delay the callback of an event a given amount of milliseconds:
(function ($) {
$.fn.delayOnEvent = function(onevent, callback, ms){
$(this).on(onevent, function( event ){
var srcEl = event.currentTarget;
if( srcEl.delayTimer )
clearTimeout ( srcEl.delayTimer );
srcEl.delayTimer = setTimeout(function(){ callback( $(srcEl) ); }, ms);
});
return $(this);
};
})(jQuery);
You can call it this way in your case:
$('#subjects').delayOnEvent('change', function() {
...
}, 1000); // one second delay
Do something like this enable/disable
$('#subjects').on('change', function() {
var subject = $('#subjects').find(":selected").text();
document.getElementById('subjects').disabled=true
$.ajax({
type: "GET",
url: "/classes/" + term + "/" + subject , // or just url: "/my-url/path/"
dataType: "html",
success: function(data) {
$('#classes').html(data);
document.getElementById('subjects').disabled=false
}
});
#rest of code

JS AJAX typeahead result ordering / race condition

I'm encountering an issue with AJAX typeahead / live-update as-you-type views which are returning results out of order. Does anyone have any experience with methods of dealing with this?
The problem:
Type in a query, such as "search term".
Even with some debouncing, it's likely to fire off a few AJAX calls as you type, say "sea", and "search term".
The search result set for sea is larger than the one for search term, and so its AJAX request actually completes after the newer query.
The resulting problem: You type in search term, but the correct results blip across the screen for a second only to be replaced by the results for sea.
Bare-bones jQuery pseudocode:
$('body').on('keyup', '#searchBox', function(){
query = $("#searchBox").val();
$.ajax({
type: 'GET',
url: '/endpoint.php?query=' + query,
success: function (response) {
// Update view here
$("#view").html(response.text);
}
});
});
Angular pseudocode:
// HTML
<input ng-keyup = "search()" ng-model="searchBox" placeholder = "Search">
{{results}}
// JS
$scope.search = function(){
$http({
method: 'GET',
url: '/endpoint.php?query=' + $scope.searchBox
}).then(function successCallback(response) {
$scope.results = response.data;
}, function errorCallback(response) {
console.log(response);
});
}
Top stop the race condition you can keep a reference to the last AJAX request you made and then abort() it when a new key is pressed. It would also be worthwhile putting a delay before making the request so that you don't send a request for every key pressed, but for when typing ends. Try this:
var previousRequest, previousTimer;
$('body').on('keyup', '#searchBox', function() {
previousRequest && previousRequest.abort();
clearTimeout(previousTimer);
previousTimer = setTimeout(function() {
previousRequest = $.ajax({
type: 'GET',
url: '/endpoint.php',
data: {
query: $("#searchBox").val()
},
success: function (response) {
// Update view here
$("#view").html(response.text);
}
});
}, 200);
});
200ms between keystrokes is plenty, but you can shorten if you want to increase the responsiveness of the requests.

Set a delay in a repeating jQuery / Ajax function

I am trying to add a delay to a repeatable query.
I found out that .delay is not the one to use here. Instead, I should go with setInterval or setTimeout. I tried both, without any luck.
Here's my code:
<?php
include("includes/dbconf.php");
$strSQL = mysql_query("SELECT workerID FROM workers ORDER BY workerID ASC");
while($row = mysql_fetch_assoc($strSQL)) {
?>
<script id="source" language="javascript" type="text/javascript">
$(setInterval(function ()
{
$.ajax({
cache: false,
url: 'ajax2.php',
data: "workerID=<?=$row['workerID'];?>",
dataType: 'json',
success: function(data)
{
var id = data[0]; //get id
var vname = data[1]; //get name
//--------------------------------------------------------------------
// 3) Update html content
//--------------------------------------------------------------------
$('#output').html("<b>id: </b>"+id+"<b> name: </b>"+vname);
}
});
}),800);
</script>
<?php
}
?>
<div id="output"></div>
The code works fine, it outputs the result as asked. It's just loads without the delay. The timout and / or interval doesn't seem to work.
Anybody knows what I am doing wrong?
I've never understood why people always add their AJAX requests in intervals rather than letting the successful AJAX calls just call themselves, all the while risking severe server load through multiple requests and not just making another call once you had a successful one come back.
In this light, I like to write solutions where the AJAX calls just call themselves on completion, something like:
// set your delay here, 2 seconds as an example...
var my_delay = 2000;
// call your ajax function when the document is ready...
$(function() {
callAjax();
});
// function that processes your ajax calls...
function callAjax() {
$.ajax({
// ajax parameters here...
// ...
success: function() {
setTimeout(callAjax, my_delay);
}
});
}
I hope this makes sense! :)
Update:
After reviewing this again, it's been brought to my attention that there was also a problem in the PHP code in the original question that I needed to clarify and address.
Although the script above will work great in creating a delay between AJAX calls, when added to the PHP code in the original post the script will just be echo'd out as many times as the number of rows the SQL query selects, creating multiple functions with the same name and possibly making all AJAX calls simultaneously...not very cool at all...
With that in mind, I propose the following additional solution - create an array with the PHP script that may be digested by the JavaScript one element at a time to achieve the desired result. First, the PHP to build the JavaScript array string...
<?php
include("includes/configuratie.php");
$strSQL = mysql_query("SELECT workerID FROM tWorkers ORDER BY workerID ASC");
// build the array for the JavaScript, needs to be a string...
$javascript_array = '[';
$delimiter = '';
while($row = mysql_fetch_assoc($strSQL))
{
$javascript_array .= $delimiter . '"'. $row['workerID'] .'"'; // with quotes
$delimiter = ',';
}
$javascript_array .= ']';
// should create an array string, something like:
// ["1","2","3"]
?>
Next, the JavaScript to digest and process the array we just created...
// set your delay here, 2 seconds as an example...
var my_delay = 2000;
// add your JavaScript array here too...
var my_row_ids = <?php echo $javascript_array; ?>;
// call your ajax function when the document is ready...
$(function() {
callAjax();
});
// function that processes your ajax calls...
function callAjax() {
// check to see if there are id's remaining...
if (my_row_ids.length > 0)
{
// get the next id, and remove it from the array...
var next_id = my_row_ids[0];
my_row_ids.shift();
$.ajax({
cache : false,
url : 'ajax2.php',
data : "workerID=" + next_id, // next ID here!
dataType : 'json',
success : function(data) {
// do necessary things here...
// call your AJAX function again, with delay...
setTimeout(callAjax, my_delay);
}
});
}
}
Note: Chris Kempen's answer (above) is better. Please use that one. He uses this technique inside the AJAX routine. See this answer for why using setTimeout is preferable over setInterval.
//Global var
is_expired = 0;
$(function (){
var timer = setInterval(doAjax, 800);
//At some point in future, you may wish to stop this repeating command, thus:
if (is_expired > 0) {
clearInterval(timer);
}
}); //END document.ready
function doAjax() {
$.ajax({
cache: false,
url: 'ajax2.php',
data: "workerID=<?=$row['workerID'];?>",
dataType: 'json',
success: function(data) {
var id = data[0]; //get id
var vname = data[1]; //get name
//--------------------------------------------------------------------
// 3) Update html content
//--------------------------------------------------------------------
$('#output').html("<b>id: </b>"+id+"<b> name: </b>"+vname);
}
}); //END ajax code block
} //END fn doAjax()
I've devised a a wrapper method which adds a custom delay on-top of the default $.ajax method. This is a way to have (on all jQuery ajax calls) a delay, throughout your entire app.
Very handy in simulating real-life random latency.
(function(){
$._ajaxDelayBk = $.ajax; // save reference to the "real" ajax method
// override the method with a wrapper
$.ajax = function(){
var def = new $.Deferred(),
delay = typeof $.ajax.delay == 'undefined' ? 500 : $.ajax.delay,
delayTimeout,
args = arguments[0];
// set simulated delay (random) duration
delayTimeout = setTimeout(function(){
$._ajaxDelayBk(args)
.always(def.resolve)
.done(def.resolve)
.fail(def.reject)
}, delay);
def.abort = function(){
clearTimeout(delayTimeout);
};
return def;
}
})();
USE EXAMPLE:
// optional: set a random delay to all `ajax` calls (between 1s-5s)
$.ajax.delay = Math.floor(Math.random() * 5000) + 1000;
var myAjax = $.ajax({url:'http://whatever.com/API/1', timeout:5000})
.done(function(){ console.log('done', arguments) })
.fail(function(){ console.log('fail', arguments) })
.always(function(){ console.log('always', arguments) })
// Can abort the ajax call
// myAjax.abort();
var takeInput=true;
$('#searchDrug').on('input',function() {
if(!takeInput){return false;}
takeInput=false;
var timer = setTimeout(function() {
$.ajax({
type: 'POST',
url: "{{route('AjaxSearchDrug')}}",
data: {
_token: '<?php echo csrf_token() ?>',
'searchkeyword': searchkeyword,
},
success: function (data) {
//do some logic then let keys be effective once more
takeInput=true;
}
});
}, 700);

Multiple ajax content requests in a loop

I'm trying to load some ajax content into a table, unfortunately it's only loading the last row multiple times instead of loading each new rows.
This is the code I'm using:
function periodicRefresh()
{
$.ajax({
type: 'GET',
url: 'include/ajaxActions.php',
data: "action=displayLastEvent",
success: function(msg){
var newid = msg;
current = $("#list tr:first").get(0).id;
if(newid != current){
while (current<newid)
{
current++;
addToList(current);
}
}
}
});
}
function addToList(x)
{
$.ajax({
type: 'GET',
url: 'include/ajaxActions.php',
data: "action=displayRow&row="+x,
success: function(msg){
$("#list").prepend(msg);
$("#list tr:first").highlightFade({
speed:3000
});
lastrow = x-20;
$('#'+lastrow).remove();
}
});
}
displayLastEvent returns the id of the last row.
displayRow returns the last row
You need to push your xmlHttps into an array or abstract data type, which you can then attach events handlers. Seems jquery doesn't do that for you.
I would address this issue by encouraging you to change your approach since it looks like you're likely making more AJAX requests than necessary whenever more rows need to be added to the list (2+ instead of just 2).
I would update include/ajaxActions.php?action=displayRow to accept a CSV of ids (or whatever it is you're passing in), and returning a set of row data, instead of data for just one row.
I think that:
current = $("#list tr:first").get(0).id;
return always the same result as jQuery remember only the page when it was first loaded.
For example, if you have a single tr[id=0]:
pass 1 : current = 0; msg = 1 -> 1 tr prepended with id = 1;
pass 2 : current is always 0 (not 1); msg = 1 -> 1 tr prepended with id = 1;
...
what you should do, is make jQuery recognize your page structure after adding your messages, or store the last index in a different way: using hidden input for example:
HTML:
<input type="hidden" value="0" id="lastId"/>
script:
initialize #lastId value when the page is loaded:
$(document).ready(function(){
$("#lastId").val(0);//or by using your displayLastEvent action
});
modify periodicRefresh to read #lastId value:
function periodicRefresh()
{
$.ajax({
type: 'GET',
url: 'include/ajaxActions.php',
data: "action=displayLastEvent",
success: function(msg){
var newid = msg;
var current = $("#lastId").val();
if(current<newid) $("#lastId").val(newid);
if(newid != current){
while (current<newid)
{
current++;
addToList(current);
}
}
}
});
}

Categories

Resources