Using a form in a dialog box I am using Dojo in jsp to save the form in my database. After that request is completed using dojo.xhrPost() I am sending in another request to update a dropdown box that should include the added form object that was just saved, but for some reason the request to update the dropdown is executed before saving the form in the database even though the form save is called first. Using Firebug I can see that the getLocations() request is completed before the sendForm() request. This is the code:
<button type="button" id="submitAddTeamButton" dojoType="dijit.form.Button">Add Team
<script type="dojo/method" event="onClick" args="evt">
sendForm("ajaxResult1", "addTeamForm");
dijit.byId("addTeamDialog").hide();
getLocations("locationsTeam");
</script>
function sendForm(target, form){
var targetNode = dojo.byId(target);
var xhrArgs = {
form: form,
url: "ajax",
handleAs: "text",
load: function(data) {
targetNode.innerHTML = data;
},
error: function(error) {
targetNode.innerHTML = "An unexpected error occurred: " + error;
}
}
//Call the asynchronous xhrGet
var deferred = dojo.xhrPost(xhrArgs);
}
function getLocations(id) {
var targetNode = dojo.byId(id);
var xhrArgs = {
url: "ajax",
handleAs: "text",
content: {
location: "yes"
},
load: function(data) {
targetNode.innerHTML = data;
},
error: function(error) {
targetNode.innerHTML = "An unexpected error occurred: " + error;
}
}
//Call the asynchronous xhrGet
var deferred = dojo.xhrGet(xhrArgs);
}
Why is this happening? Is there way to make the first request complete first before the second executes?
To reduce the possibilities of why this is happening I tried setting the cache property in xhrGet to false but the result is still the same.
Please help!
As Alex said, asynchronous requests are just that - their order is not guaranteed. If you want to guarantee their order, you can make them synchronous if you like. There is an option sync: true I think that you can send with the request args. This causes the browser to freeze up until the request gets back, so it's not recommended unless you have no other option, and the request is very quick.
You can also submit whatever data you need along with the data of the current request. For example, suppose dropdown A's value determines the list choices available in dropdown B. Rather than submitting a change when dropdown A is changed, then refreshing dropdown B's choices, what you can do is submit A's value at the time when dropdown B is opened, and process it in the server logic that determine's B's choices. (This assumes you have a drop-down widget with choices generated by the server, rather than a standard tag.)
The first A in Ajax stands for "asynchronous", which means things occur "at their own pace": most likely the requests are sent in the order you expect, but they complete the other way around simply because the second one is faster. Yes, of course you can wait to even start (send) the second request until the first one completes -- most simply, you can just put the starting of the second request in the callback function of the first.
Related
I have a form that has a set of drill-downs so one drop down will fill in another. I have a script set up to remember the form values and reset them for that page. My issue comes in when I execute on the trigger for the element, I can't figure out any way to wait on the other dropdown to refresh and then setting its value. Is there any way I can wait for the success result of a function that's kicked off by trigger('change') (or similar function) besides listening for the ajax request. My fall back plan is to do this with cookies and then fill in the form server side. Which might look better anyway, I'm just wondering if it can be done.
I have it saving the values from each drop down and loading them when I get back, I'm wondering if there's some way I can
listen for the ajax call in dropdown_a to finish if I load the value from session storage and call $('#dropdown_a').trigger('change')
the more I think about it I'd probably have to store some sort of value in the program that tracks any request made so I can await them
which would defeat the purposes of the self contained script I have for this
$('#dropdown_a').on('change', function() {
//Ajax call I want to wait for
$.ajax({
url: 'someendpoint',
data: 1,
success: function(response) {
util.fillsInSelectBox(response, $('#dropdown_b'));
},
error: function() {
showErrorModal();
}
});
});
$('#dropdown_b').on('change', function() {
$('#table').bootstrapTable('refresh');
});
I am currently working on a web based time tracking software. I'm developing in grails, but this question is solely related to javascript and asynchronous requests.
The time tracking tool shall enable users to choose a day for the current month, create one or multiple activities for each day and save the entire day. Each activity must be assigned to a project and a contract.
Upon choosing "save", the partial day is saved to the database, the hours are calculated and a table is updated at the bottom of the page, showing an overview of the user's worked hours per month.
Now to my issue: There may be a lot of AJAX request. Patient users might only click the "create activity" button just once and wait until it is created. Others, however, might just keep clicking until something happens.
The main issue here is updating the view, although i also recognized some failed calls because of concurrent database transaction (especially when choosing "save" and "delete" sequentially). Any feedback on that issue -- requests not "waiting" for the same row to be ready again -- will be apreciated as well, yet this is not my question.
I have an updateTemplate(data, day) function, which is invoked onSuccess of respective ajax calls in either of my functions saveRecord(), deleteRecord(), pasteRecords(), makeEditable() (undo save). Here is the example AJAX call in jquery:
$.ajax({
type: "POST",
url: "${g.createLink(controller:"controller", action:"action")}",
data: requestJson,
contentType:"application/json; charset=utf-8",
async: true,
success: function(data, textstatus) {updateTemplate(data["template"], tag); updateTable(data["table"]);},
});
In the controller action, a JSON object is rendered as a response, containing the keys template and table. Each key has a template rendered as a String assigned to it, using g.render.
Now, what happens when I click on create repeatedly in very short intervalls, due to the asynchronous calls, some create (or other) actions are executed concurrently. The issue is that updateTemplate just renders data from the repsonse; the data to render is collected in the create controller action. But the "last" request action only finds the objects created by itself. I think this is because create actions are run concurrently
I figure there is something I'm either overcomplicating or doing something essentially wrong working with a page that refreshs dynamically. The only thing I found that helps are synchronous calls, which works, but the user experience was awful. What options do I have to make this work? Is this really it or am I just looking for the wrong approach? How can I make this all more robust, so that impatient users are not able to break my code?
*********EDIT:********
I know that I could block buttons or keyboard shortcuts, use synchronous calls or similar things to avoid those issues. However, I want to know if it is possible to solve it with multiple AJAX requests being submitted. So the user should be able to keep adding new activities, although they won't appear immediately. There is a spinner for feedback anyway. I just want to somehow make sure that before the "last" AJAX request gets fired, the database is up to date so that the controller action will respond with the up-to-date gsp template with the right objects.
With help of this Stackoverflow answer, I found a way to ensure that the ajax call -- in the javascript function executed lastly -- always responds with an up-to-date model. Basically, I put the javascript functions containing AJAX calls in a waiting queue if a "critical" AJAX request has been initiated before but not completed yet.
For that I define the function doCallAjaxBusyAwareFunction(callable) that checks if the global variable Global.busy is 'true' prior to executing the callable function. If it's true, the function will be executed again until Global.busy is false, to finally execute the function -- collecting the data from the DOM -- and fire the AJAX request.
Definition of the global Variable:
var Global = {
ajaxIsBusy = false//,
//additional Global scope variables
};
Definition of the function doCallAjaxBusyAwareFunction:
function doCallAjaxBusyAwareFunction(callable) {
if(Global.busy == true){
console.log("Global.busy = " + Global.busy + ". Timout set! Try again in 100ms!!");
setTimeout(function(){doCallAjaxBusyAwareFunction(callable);}, 100);
}
else{
console.log("Global.busy = " + Global.busy + ". Call function!!");
callable();
}
}
To flag a function containing ajax as critical, I let it set Global.busy = true at the very start and Global.busy = false on AJAX complete. Example call:
function xyz (){
Global.busy = true;
//collect ajax request parameters from DOM
$.ajax({
//desired ajax settings
complete: function(data, status){ Global.busy = false; }
}
Since Global.busy is set to true at the very beginning, the DOM cannot be manipulated -- e.g. by deletes while the function xyz collects DOM data. But when the function was executed, there is still Global.busy === true until the ajax call completes.
Fire an ajax call from a "busy-aware" function:
doCallAjaxBusyAwareFunction(function(){
//collect DOM data
$.ajax({/*AJAX settings*/});
});
....or fire an ajax call from a "busy-aware" function that is also marked critical itself (basically what I mainly use it for):
doCallAjaxBusyAwareFunction(function(){
Global.busy = true;
//collect DOM data
$.ajax({
//AJAX SETTINGS
complete: function(data, status){ Global.busy = false; }
});
});
Feedback is welcome and other options too, especially if this approach is bad practice. I really hope somebody finds this post and evaluates it, since I don't know if it should be done like that at all. I will leave this question unanswered for now.
I am building a messaging system for my site. The mailbox is flat, i.e. accessing the inbox, or sending a new message does not move to another page, it just toggles divs. When a user clicks a message, an AJAX call replaces the inbox div with the chosen thread. Inside the thread view, there is a form to reply to the message.
A few problems:
From inside this thread_view, which sends an AJAX response to a div nested inside the entire mailbox div, I don't have access to document objects outside of it. So, I can't manipulate divs outside of this view, such as the one that receives the AJAX beforeSend and Success messages. I think this may be accomplished with some kind of .load(), though I'm not sure exactly how.
My AJAX doesn't fire. I am using the Ajax.Form() plugin. I think this problem might be related to the first, but I can't say for certain. I'm not sure how to begin troubleshooting the Ajax request because I get no errors in the console.
I wonder if the problem has to do with the fact that I am trying to send an ajaxRequest from a view that is itself a response from a previous ajaxRequest, i.e. the entire view for the thread is a result of the following, in the same js file as the next request:
// compose a message function
$('#send_message').on("click", function(e) {
var send_message_options = {
type: 'post',
url: "/users/new_message",
beforeSend: function() {
//Display a loading message while waiting for the ajax call to complete
$('#message').html("Sending message...");
},
// Hide form and display results
success: function(response) {
$('#message').html(response);
}
};
$('#message_form').ajaxForm(send_message_options);
});
My new AJAX request, which does nothing:
$('#reply_in_thread').on("submit", function(e) {
e.preventDefault();
console.log("trying for reply");
var reply_options = {
type: 'post',
url: "/users/reply",
beforeSend: function() {
//Display a loading message while waiting for the ajax call to complete
$('#reply_message').html("Sending message...");
},
// Hide form and display results
success: function(response) {
$('#reply_message').html(response);
}
};
$('#reply_in_thread').ajaxForm(reply_options);
});
I couldn't say why the ajaxForm() plugin failed, but a jquery $.post was successful. The code that worked below:
$('#reply_in_thread').on("submit", function(e) {
e.preventDefault();
var data = $(this).serialize();
$.post('/users/reply',data,function(response){
$('#reply_message').html(response);
})
});
I have links in a JQuery DataTable that use JQuery UI's tooltip feature. Each link has a tooltip that is populated by an Ajax call. I would like to limit the number of Ajax calls to as few as possible. The DataTable uses server-side processing, and the results are paginated, so there will never be more than ten links on the page at any one time.
The data that is returned by the Ajax call will never change and thus can be safely cached. In my testing, I have seen that the browser does cache the result of each Ajax call, so that it only makes one call per link, and then uses the cache thereafter. My concern is that some user might have their browser configured in such a way that it doesn't use the cache for some reason, and they will be firing off one Ajax call after another, every time they mouse over a link.
Here is the JavaScript for the tooltip:
$('.jobId').tooltip({
content: function(callback) {
var jobId = $(this).text();
$.ajax({
url: 'myUrl',
data: {jobId: jobId},
dataType: 'json',
success: function(data) {
var html = formatResults(data);
callback(html);
},
error: function() {
callback('An error has occurred.');
}
});
}
});
I considered storing the result of each Ajax call in a JavaScript object declared at global scope, and then checking that before making the Ajax call, but I have the vague sense that this might cause a memory leak somehow.
var gJobs = new Object();
$('.jobId').tooltip({
content: function(callback) {
var jobId = $(this).text();
if (gJobs[jobId]) {
callback(gJobs[jobId]);
} else {
$.ajax({
url: 'myUrl',
data: {jobId: jobId},
dataType: 'json',
success: function(data) {
var html = formatResults(data);
gJobs[jobId] = html;
callback(html);
},
error: function() {
callback('An error has occurred.');
}
});
}
}
});
I am also concerned that if the table has a large number of rows, the gJobs object could end up using a lot of memory. To prevent the gJobs object from growing indefinitely, every time the user goes to the next or previous page of results in the DataTable, I use the fnDrawCallback function to reinitialize gJobs:
$('#jobsTable').dataTable({
...
"fnDrawCallback": function() {
gJobs = new Object();
}
});
I should mention that since the data returned by each Ajax call doesn't change, I could also just store the data in the JSP as static text, and populate the tooltips that way instead of using Ajax. However, I have to make a separate web service call to get the data for each link, and rather than make ten web service calls every time the user pages forward or back, I would rather load the data on demand via Ajax.
Is there anything wrong with this approach? Is there any way this can cause a memory leak? Should I explicitly delete all the properties of gJobs before reinitializing it? Thanks for your help.
I have a background script that is responsible for getting and setting data to a localStorage database. My content scripts must communicate with the background script to send and receive data.
Right now I send a JSON object to a function that contains the command and the data. So if I'm trying to add an object to the database Ill create JSON that has a command attribute that is addObject and another object that is the data. Once this is completed the background scripts sends a response back stating that it was successful.
Another use case of the function would be to ask for data in which case it would send an object back rather than a success/fail.
The code gets kind of hacky once I start trying to retrieve the returned object from the background script.
It seems like there is probably a simple design problem to follow here that I'm not familiar with. Some people have suggested future/promise design problems but I haven't found a very good example.
Content Script
function sendCommand(cmdJson){
chrome.extension.sendRequest(cmdJson, function(response){
//figure out what to do with response
});
}
Background script
if (request.command == "addObject"){
db[request.id]= JSON.stringify(request.data);
sendResponse("success");
}
else if(request.command == "getKeystroke"){
var keystroke = db[request.id];
sendResponse(keystroke);
}
Your system looks OK and here are some minor improvements.
For each remote command send back the same type of object (with possibly empty fields):
var response = {
success: true, // or false
data: {},
errors: [],
callback: ''
}
Also, if you have multiple different commands which send back data, you may replace if-else with an object lookup:
var commands = {
addObject: function () { /* ... */ },
getKeystroke: function (request, response) {
response.data = db[request.id]
}
}
Then if you have any data to response with, just add it to the object. And send the same object for any command:
var fn = commands[request.commands]
fn(request, response)
As for figuring out what to do with response, I'd pass a callback into the sendCommand function and let the content scripts request and process the response data as they see fit:
function sendCommand(cmdJson, callback){
chrome.extension.sendRequest(cmdJson, callback)
}