I am rendering a few elements with an Ajax call in rails, however another function of mine needs to reference those elements. The issue I am facing now is that the function can not grab these elements, unless the Ajax request has actually finished. Is there some way of running a javascript function in Rails after the ajax call?
For example:
fetch_cards.js.erb
var cards = $('.cards'); // only fetches previous cards, not the new ones
my_function( cards );
cards_controller.rb
def fetch_cards
respond_to do |format|
format.js
end
end
I'm not sure what you mean, but javascript offers you the ability to listen for an ajax call to be completed. Since you already use jQuery, you can do the following:
$.ajax('your/resources.json',
complete: function(jqXHR, status){
// this will be executed once the server has completed your request
my_function(cards);
}
);
You probably want to extend this function with more specific callback functions (success, error), you can find more info on the jQuery API docs.
Related
Suppose I have a page called form.php. I then clicked a button called "add button". This button triggers an event that got detected by a jquery function. The jquery function makes an ajax call to add.php.
Inside add.php, there is code that checks if a particular record exist in the database. If it does find that the record exists, I want to do the following.
Send a response string "exist" to ajax.
The ajax, inside the .done() function, will execute a prompt that says "This record already exist, do you wish to overright"?
If the user canceled the prompt, nothing more should happened and the ajax call should be done.
If the user clicks "ok", I would like the php script to be notified of this and execute an update statement using the data from form.php.
I suspect this is impossible because after receiving a response from php, AFAIK there is no way for ajax to respond back to the php script that is currently executing.
Am I correct or there is a way to do this?
You have to add a parameter to your ajax request, like override with true and false. By default/first request you set it to false. Then the add.php does it's default and returns exists.
The the user makes his decision. If he want to override, you send the ajax request again with the override parameter to true. Your add.php will notice the parameter and does whatever it has to do.
Wrap your ajax handler in an own function with a done callback. So you can reuse the request as often as you want. Pretty easy, no double code needed as well ...
The .done() function of your first ajax call executes when the ajax call has finished successfully, so when your php script has finished completely.
If you want to do something else, you would need to make a new ajax request. That could be to the same or another script, sending in different / new / additional parameters.
Note that you have to make sure that the second script cannot be called without the first one finishing, for example by setting and checking an expiring session variable.
you can do something like this.
$.post('add.php',$(this).serialize())
.done(function(result){
var r = confirm("This record already exist, do you wish to overright");
if(result == 'exist'){
if (r == true) {
$.post('update.php',$(this).serialize()).done(function(r){
console.log(r);
});
} else {
return false;
}
}else{
console.log(result)
}
});
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.
This is my "link":
%span{:id => "car_#{car.id}", :onclick => "add_car(#{car.id}"} Add
that leads on to here:
function add_trending(car_id) {
jQuery.ajax({
url: "/cars/add_car",
type: "GET",
data: {"car_id" : car_id},
dataType: "html"
});
}
in controller:
def add_car
#car = Car.find(params[:car_id])
...
respond_to do |format|
format.js
end
end
and add_car.js.erb:
alert("YES");
But the alert window is not popped up. When I take a look at logs, I see there following:
Rendered cars/add_car.js.erb (0.0ms)
The javascript is just rendered, not executed based on logs. How is that possible?
Thanks
If your ajax request returns javascript you must set the dataType : script or use $.getScript function.
In this case you haven't any success callback function.
Have you looked at your network traffic client-side? I'm guessing that you're sending this down to the client, but it doesn't know what to do with this result. In fact, if that's your entire handler in jQuery, then it won't do anything with the response. You need a success and/or failure handler in the options object passed to jQuery.ajax, or you need to attach one to the promise it returns. In other words, you're probably getting the data back but not doing anything with it.
This question already has answers here:
Sequencing ajax requests
(10 answers)
Closed 9 years ago.
I am working a script, I need to loop an array of AJAX requests:
$('#fetchPosts').click(function(){
for(var i=0; i < link_array.length; i++) {
settings = {
// some object not relevant
}
var status = main_ajaxCall(settings, i); // ajax call
}
});
function main_ajaxCall(settings, i) {
$.ajax({
type: "POST",
url: "../model/insert.php",
data:{obj_settings: settings},
dataType: "json",
cache: false,
success: function (data) {
// some handeling here
return 0;
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
return 1;
},
};
Why does the AJAX requests fire instantly? It does not seem to wait for a response from model/insert.php, is there any way to force it to wait for a response before firing the next AJAX request?
EDIT 1:
It seems I wasnt clear, sorry, I dont want it to wait, I want to queue up the calls.
I cant make the call in one request, this is impossible in my current situation.
Set async to false if you want to wait for a response (default: true)
$.ajax({
async: false,
...
http://api.jquery.com/jQuery.ajax/
If you do not want blocking, you can set a success handler function using .ajaxComplete(), and you have to keep track of active AJAX connections if you want to wait for all to complete - How to know when all ajax calls are complete
The best solution would be to minimize the number of AJAX requests to one. If you have to make a loop of AJAX requests, the logic could be simplified somewhere (put that in the server perhaps?)
EDIT 1: (In response to OP edit)
If you want to queue the AJAX requests, this question has been answered before here:
Sequencing ajax requests
Queue ajax requests using jQuery.queue()
You could also use these libraries (all you needed to do was Google):
https://code.google.com/p/jquery-ajaxq/
http://codecanyon.net/item/ajax-queue-jquery/full_screen_preview/4903957
http://schneimi.wordpress.com/2008/03/10/multiple-ajax-requests-problems-and-ajaxqueue-as-solution/
It fires instantly and doesn't wait around because that's what AJAX does best (The first A stands for asynchronous).
The request to a server could take a long time to respond, and in most cases, don't want user's browser's freezing up or stopping them from doing anything else. If you do, you could probably just use a normal request.
This is the reason you give it functions for success error, so it can call them when the server responds.
If you want nothing to be able to happen in the browser while you're calling insert.php, you could drop an overlay (eg. dark div) over everything with a loading image and remove it on success.
Maybe replace the $('#fetchPosts') element with "loading..." text and then reverse it when done. Hiding visibility of the fetchPosts element and adding a different "loading.." element is a nice way.
Your AJAX call will wait for a response from the server, but wil do so asynchronously. That is, your script will continue to execute rather than block the browser while the server responds. When the server responds (or when the request times out - usually several seconds) your success: or error: functions will then execute.
The effect of your code here is to create several concurrent requests based on the link_array length.
You could specify async:false in your AJAX call, but this would freeze the browser while all the AJAX calls are made.
You should rewrite your code to execute all the handling as part of your success: function. I'd recommend you rewrite your code to assemble all your request into one, and make one AJAX call rather than several, and have the server return all the responses as one block. I can't suggest exactly how you do that - it's implementation dependent.
EDITED:
In response to your clarification, if you want them to be called in order, you'll need the success function to call the next one. You'll then have a chain of success calls the next, whose success calls the next, whose success calls the next.. etc until the last one which does the final processing. One way would be to pass the call number to the success function.
Is there any way to intercept an ajax request being made via jquery, to insert additional variables into it?
I know that .ajaxStart() lets you register a callback which triggers an event whenever an ajax request begins, but what I'm looking for is a way to cancel that ajax request if it meets certain criteria (e.g url), insert some more variables into its content, and then submit it.
This is for a plugin for a 3rd party software whose own code can't be changed directly.
Edit: Seems like .ajaxSetup() lets you set some global variables related to ajaxRequests. If I registered a beforeSend function, would that function be able to cancel the request to make a different one on meeting certain criteria?
Figured it out, this was the code I used:
jQuery(document).ready(function()
{
var func = function(e, data)
{
//data.data is a string with &seperated values, e.g a=b&c=d&.. .
//Append additional variables to it and they'll be submitted with the request:
data.data += "&id=3&d=f&z=y";
return true;
};
jQuery.ajaxSetup( {beforeSend: func} );
jQuery.post('example.php', {a : 'b'}, 'json');
} );
To cancel the request, returning false from func seemed to work.