I cant understand what I'm doing wrong on this one. I've got a while loop running an AJAX function to get data from a PHP file for the amount of people selected from a dropdown.
$(document).on('change', '#attendingCount', function() {
$(".person-container").html("");
var amount = $(this).val();
var i = 0;
while (i < amount) {
getPerson(i);
i++;
}
});
getPerson(0);
function getPerson(e) {
$.ajax({
type: 'post',
url: './person.php',
data: {
"amount": e
},
success: function(data) {
$(".person-container").append(data);
},
error: function() {
console.log('error');
}
});
}
When the result gets pumped out though, the order of them is completely random.
What is it exactly I'm doing wrong?!
AJAX works in an asynchronous way, not necessarily the first request you send is going to return data first, that's the problem here. Doing an AJAX call in a while loop is not the best solution.
Related
I want to download and cache multiple mustache-templates and the only real way I know to do this is by downloading them via the jQuery.ajax()-method.
So my straightforward preload-init code looks a little ... ugly!
function getAllTemplatesUglyAndNotPerformant() {
//this is no longer valid, stays just for reference; look at the bottom for the solution
//easy - preload the template and execute it to the data
$.ajax({
url: 'fragments/employee.mustache',
success: function (employeeTpl) {
//uh-oh async process-handling forces me into digging this deeper
$.ajax({
url: 'fragments/employee_day.mustache',
success: function (dayTpl) {
//third level - now i am puzzled already
$.ajax({
url: 'fragments/employee_day_regular.mustache',
success: function (protodayTplRegular) {
//monologue: am i doing this right?
$.ajax({
url: 'fragments/employee_day_deleted.mustache',
success: function (protodayTplDeleted) {
//most probably not
var cachedTemplates = {
employee: employeeTpl,
day: dayTpl,
protoday: {
regular: protodayTplRegular,
deleted: protodayTplDeleted
}
};
//shoot, i also cannot return cachedTemplates, better bury my init-method in this!
init(cachedTemplates);
}
});
}
});
}
});
}
});
}
//initializes downloading and parsing data to what will be seen
function init(cachedTemplates) {
//get the data
$.ajax(
url: '_get_data.php',
success: function (data) {
if (data.success) {
$.each(data.employees, function (iEmployee, vEmployee) {
//this goes through a custom rendering for an employee and his sub-nodes stored in arrays (all rendered in Mustache)
var employee = parseEmployee(vEmployee);
var html_employee = employee.render(cachedTemplates);
$('#data-position').append(html_employee);
});
}
//ignore what may else happen for now
}
)
}
Is there a better way for downloading multiple files for caching in JS?
EDIT:
my rewrite of getAllTemplates() looks now more like this and is finally "more-understandable" and performant for the next one to touch "Peters Legacy":
function getAllTemplates() {
$.when(
$.get('fragments/employee.mustache'),
$.get('fragments/employee_day.mustache'),
$.get('fragments/employee_day_regular.mustache'),
$.get('fragments/employee_day_deleted.mustache')
)
.done(function (employeeTpl, acquisitionTpl, protodayTplRegular, protodayTplDeleted) {
var cachedTemplates = {
employee: employeeTpl[0],
acquisition: acquisitionTpl[0],
protoday: {
regular: protodayTplRegular[0],
deleted: protodayTplDeleted[0]
}
};
init(cachedTemplates);
});
}
You don't specify which version of jQuery you're using, so here's assuming you're using a somewhat current build;
You can use $.when() which is in jQuery 1.5+.
$.when() allows you to bundle (essentially) a bunch of async methods (ajax in this case) and wait until all of them have completed. In your example you are firign one request, waiting for the response and then firing another. With $.when(); if your connection allows it they can all fire simultaneously, saving a lot of time in your example!
something like:
$.when(
$.ajax( "fragments/employee.mustache" ),
$.ajax( "fragments/employee_day.mustache" ),
$.ajax( "..." )
)
.done(function( employeeRes, dayRes ) {
// the first item in array should be the data
var employeeTpl = employeeRes[0];
var dayTpl = dayRes [0];
// ...
});
There's loads of good examples at the jQuery Website
I am trying to make search function based on Ajax/Jquery.
My web app shows the data of service requests from the database. I want to make searchbar for my app as follows:
show all service request on the table initially.
If something is typed on the searchbar, it searches data and load those data to the table.
Finally if user deletes anyword from searchbar it will show all data as stated on No.1
I managed doing second and third function but I am having issues with the first one.
$(document).ready(function(){
$('#search_text').keyup(function(){
var txt = $(this).val();
if(txt != '') {
$.ajax({
url:"ajax/fetchRequests.php",
method:"post",
data:{search:txt},
dataType:"text",
success:function(data) {
$('#result').html(data);
}
});
}
else if(txt == '') {
$.get("ajax/readRequests.php", {}, function (data, status) {
$("#result").html(data);
});
}
});
});
Here is another script that i have worked on trying:
$(document).ready(function(){
var txt = $('#search_text').val();
if(txt != ''){
$.ajax({
url:"ajax/fetchRequests.php",
method:"post",
data:{search:txt},
dataType:"text",
success:function(data) {
$('#result').html(data);
}
});
}
else if(txt == '') {
$.get("ajax/readRequests.php", {}, function (data, status) {
$("#result").html(data);
});
}
});
All my features are working except for the search functions. Any tips or critics are welcome, thank you very much in advance.
I suggest you do two things, 1) use the suggested .on() and 2) use only one ajax function to simplify things. The idea is to funnel your calls through one function so that you know if something fails, it's not because you messed up the ajax part of the script:
// Create a generic ajax function so you can easily re-use it
function fetchResults($,path,method,data,func)
{
$.ajax({
url: path,
type: method,
data: data,
success:function(response) {
func(response);
}
});
}
// Create a simple function to return your proper path
function getDefaultPath(type)
{
return 'ajax/'+type+'Requests.php';
}
$(document).ready(function(){
// When the document is ready, run the read ajax
fetchResults($, getDefaultPath('read'), 'post', false, function(response) {
$('#result').html(response);
});
// On keyup
$(this).on('keyup','#search_text',function(){
// Get the value either way
var getText = $(this).val();
// If empty, use "read" else use "fetch"
var setPath = (!getText)? 'read' : 'fetch';
// Choose method, though I think post would be better to use in both instances...
var type = (!getText)? 'post' : 'get';
// Run the keyup function, this time with dynamic arguments
fetchResults($, getDefaultPath(setPath), type, { search: getText },function(response) {
$('#result').html(response);
});
});
});
To get initial results hook onto jQuery's document ready event.
var xhr;
var searchTypingTimer;
$(document).ready(function(){
// initial load of results
fetchResults([put your own params here]);
// apply on change event
$('#search_text').on('input', function() {
clearTimeout(typingTimer);
searchTypingTimer = setTimeout(fetchResults, 300);
});
});
function fetchResults($,path,method,data,func)
{
if (xhr && xhr.readyState != 4){
xhr.abort();
}
xhr = $.ajax({
url: path,
type: method,
data: data,
success:function(response) {
func(response);
}
});
}
As Rasclatt mentions you should use jQuery's on method to catch any changes.
Secondly I'd recommend disposing of previous requests when you make new ones, since if you are sending a new one on each character change then for one word many requests will be made. They won't necessarily arrive back in the order you send them. So for example as you type 'search term', the result for 'search ter' may arrive after and replace 'search term'. (welcome to async).
Thirdly since you will send many requests in quick succession I'd only call your fetchResults function after a short time out, so for example if a user types a five character word it doesn't fire until 300ms after the last character is typed. This will prevent 4 unnecessary requests that would just be ignored but put strain on your backend.
I seem to struggle to find out how to use the when function in my code. What I wish to achieve is a window.location.reload when all the ajax requests are done.
If I put the window.location.reload after the "each" loop then all my AJAX requests are just aborted.
$('.removeSelected').click(function() {
if (confirm('Are you sure you will continue?')) {
$('.container-fluid :input:checked').each(function () {
var recordId = $(this).data("id");
// Jquery remove it
$.ajax({
method: "GET",
url: "/controllers/lines.asp",
data: { recordId: recordId }
}).done(function() {
console.log('done');
});
});
// window location reload here
}
});
The order of your logic seems to be flawed. What I think you want to do is collect all of your records and then send in one request. When the request is done, then you reload.
$('.removeSelected').click(function() {
if (confirm('Are you sure you will continue?')) {
//prepare an array for records
var records = [];
$('.container-fluid input:checked').each(function () {
//add the id
records.push($(this).data("id"));
});
//make the request
$.ajax({
method: "GET",
url: "/controllers/lines.asp",
data: records
}).done(function() {
//when successful, reload the page
window.location.reload();
});
});
};
});
I'm not sure if you want to reload just on success or on complete (which will reload on fail also).
Get the number of elements to delete with
$('.container-fluid :input:checked').size();
Each time done is called, increment a separate total. When the total matches the count, reload the page.
I agree with fauxserious that sending all at once instead of making a request per record would be more efficient.
However, if for any reason you don't want to change your server side code, what you need to do is identify when all requests have been completed. You can achieve this using promises.
If you don't have much experience with this, code below should give you an idea on how to achieve the expected behavior without using promises:
$('.removeSelected').click(function() {
if (confirm('Are you sure you will continue?')) {
var $containerFluidElements = $('.container-fluid :input:checked');
var numberOfRequestsPending = $containerFluidElements.length;
$containerFluidElements.each(function () {
var recordId = $(this).data("id");
$.ajax({
method: "GET",
url: "/controllers/lines.asp",
data: { recordId: recordId }
}).done(function() {
numberOfRequestsPending -= 1;
if(numberOfRequestsPending == 0)
{
window.location.reload();
}
});
});
}
});
You need to pass all the promises to "when" so that it can wait for all of them to be resolved.
To do that you can put all the promises returned by $.ajax in an array and pass it to $.when:
$('.removeSelected').click(function() {
if (confirm('Are you sure you will continue?')) {
var promises = [];
$('.container-fluid :input:checked').each(function () {
var recordId = $(this).data("id");
// Jquery remove it
promises.push($.ajax({
method: "GET",
url: "/controllers/lines.asp",
data: { recordId: recordId }
})
.done(function() {
console.log('done');
}));
});
// use apply to pass an array instead list of parameters
$.when.apply($, promises).then(function() {
// all the promises have been resolved
window.location.reload();
}
});
I have two separate AJAX calls. One that gets a list of items from a txt file and creates an HTML table out of them and one that talks to a database to find how much each item costs and then lists this in the corresponding table cell for each item (I know this may sound like a strange approach, but it's a good option in our case...).
The issue is that the price is not getting written to the table since the table is created (or to be precise, the rows of the table are created) after the page loads. I'm not sure how to fix this.
$(document).ready(function() {
makeItemTable();
listPrices();
...
});
function makeItemTable() {
$.ajax({
url: 'products.php',
type: 'GET'
})
.done(function(response) {
$('.price-table > tbody').html(response);
})
}
function listPrices() {
.ajax({
url: 'prices.php',
type: 'GET'
})
.done(function(response) {
priceData = $.parseJSON(response);
$('.price-table tr').each(function() {
var item = $(this).find('td:nth-child(1)').text();
if (priceData[item]) {
var price = priceData[item];
$(this).find('td:nth-child(2)').text(price);
}
})
}
You can try
Using setTimeout to check request to 'products.php' execute callback done (inside callback for request to 'prices.php')
Another way
var jqxhr1 = $.ajax("products.php");
var jqxhr2 = $.ajax("prices.php");
$.when(jqxhr1, jqxhr2).done(function(jqxhr1, jqxhr2) {
// Handle both XHR objects
alert("all complete");
});
Call function listPrices() inside callback request to 'products.php'
Hope to help
I'm writing a javascript function that should change the view of a postcard depending on which case is selected.
My problem is that the old values of the object "m_case" is getting used. If I press the button with class "case-btn" twice I get the right case selected in my postcard view. But I want it to be triggered when I press the button once.
I guess I have to do something like a callback function in the m_case.setCase() function call, but I can't get it working,
$('.case-btn').on('click', function() {
remove_active_state_from_cases();
m_case.setCase($(this).data('case'));
// Changes the view of the postcard
m_postcard.changeBackground(m_case.getPhoto());
m_postcard.changeMessage(m_case.getMessageText());
m_postcard.changeFullName(m_case.getFullName());
m_postcard.changeCountry(m_case.getCountry());
$(this).toggleClass('active');
});
The setCase() function
this.setCase = function(id) {
// Set ID
this.setID(id);
var that = this;
$.ajax({
url: 'get_case_by_id.php',
type: 'get',
dataType: 'json',
data: {id: that.getID() },
success: function(data) {
if(data.success) {
that.setFirstName(data.first_name);
that.setFullName(data.full_name);
that.setAdress(data.adress);
that.setCountry(data.country);
that.setStamp(data.stamp);
that.setPhoto(data.photo);
that.setSummary(data.summary);
that.setStory(data.story);
that.setMessageText(data.message_text);
that.setDefaultMessageText(data.default_message_text);
that.setMessageImg(data.message_img);
} else {
console.log('failure');
}
}
EDIT The problem might be in my AJAX call, I have to wait till the ajax have been called. but how do I continue the first flow when my Ajax is done and not before?
SOLUTION
I made it working by adding a callback parameter and calling that function in the ajaxs complete function.
$('.case-btn').on('click', function() {
remove_active_state_from_cases();
var that = this;
m_case.setCase($(this).data('case'), function() {
m_postcard.changeBackground(m_case.getPhoto());
m_postcard.changeMessage(m_case.getMessageText());
m_postcard.changeFullName(m_case.getFullName());
m_postcard.changeCountry(m_case.getCountry());
$(that).toggleClass('active');
});
});
// Sets the whole case from an id.
this.setCase = function(id, callback) {
// Set ID
this.setID(id);
var that = this;
$.ajax({
url: 'get_case_by_id.php',
type: 'get',
dataType: 'json',
data: {id: that.getID() },
success: function(data) {
if(data.success) {
that.setFirstName(data.first_name);
that.setFullName(data.full_name);
that.setAdress(data.adress);
that.setCountry(data.country);
that.setStamp(data.stamp);
that.setPhoto(data.photo);
that.setSummary(data.summary);
that.setStory(data.story);
that.setMessageText(data.message_text);
that.setDefaultMessageText(data.default_message_text);
that.setMessageImg(data.message_img);
} else {
console.log('fail big time');
}
},
complete: function() {
callback();
}
});
}
Your m_postcard.changeBackground and other calls should be in the success callback, or in another function that is called from the success callback, as those values aren't set till the async ajax call is done.
With the way your code is now the m_postcard.changeBackground and other calls are called immediately after your setCase function is done executing. This means your methods are executed before the data has arrived from the server
While the ajax is processing you probably should show a loading message on the screen to let the user know they have to wait till the processing is done. Show the message before calling the .ajax call and hide it in the success/error callbacks.
Any changes to the site content should be done from the success callback, ie changing active states, changing content, etc.