I'm having an issue with the inherent asynchronous-ness of AJAX with what I'm trying to accomplish...
Using a file upload form, I'm trying to send a set of data to my LAMP server which then loops through each subset of the data and generates a PDF for each subset. This takes a good 2 minutes or so to process all of the PDFs since there are so many (like 100) being generated for each subset of data.
I am hoping to use JavaScript/jQuery to segment the data into subsets that I will post to the server one at a time, and as each PDF is generated, get a response from the server and increment a progress bar, then send the next request.
How would you accomplish this in a loop? What's below doesn't work because jQuery doesn't care about the state of the server and sends all requests asynchronously.
var i = 0;
$.each(data_stuff, function(key, value) {
$.post( window.location.href, {
stuff: key,
data: value
}).done(function( data ) {
if (data == 1) {
$('div#counter').text(i);
}
});
$i++;
});
Thanks!
Assuming data_stuff is an Object, you can try this:
var i = 0;
// We need an array (not object) to loop trough all the posts.
// This saves all keys that are in the object:
var keys = Object.keys(data_stuff);
function postNext() {
// For every POST request, we want to get the key and the value:
var key = keys[i];
var value = data_stuff[key];
$.post( window.location.href, {
stuff: key,
data: value
}).done(function( data ) {
if (data == 1) {
$('div#counter').text(i);
}
// Increment i for the next post
i++;
// If it's the last post, run postsDone
if(i == keys.length) {
postsDone();
}
// Else, run the function again:
else {
postNext();
}
});
});
postNext();
function postsDone() {
// All data was posted
}
This will only post the next bit of data_stuff after the previous $.post was done.
Related
Hi all I'm pretty new to PHP and AJAX and all that good stuff and I'm a little stumped on how to proceed from here in my code.
I have a form that is getting sent and I have an array (subcategories) which contains the form labels to retrieve the values of the fields. The fields and values are getting created dynamically based on a textfile that the user uploads so I don't have any way of knowing what they are.
var arrayLength = subcategories.length;
for (var i = 0; i < arrayLength; i++) {
var eachfield = subcategories[i];
//Do something
//#C: selector is working fine, cleaning input
var eachfield = $('#' + eachfield).val().trim();
//push the appropriate values with the fixed stuff to a new array
values.push(eachfield);
}
What I'm trying to do is now to set these variables to some name and send them through $data using AJAX and POST.
Something like the following if I was setting everything statically.
var data = {
dimitypedata: dimitype,
densitydata: density,
velocitydata: velocity,
temperaturedata: temperature,
submitbtnclicked: "submitted"
};
//using the data and sending it through a post with promise handling
$.ajax({
type: 'POST',
url: "controller.php",
data: data,
success: function(response) {
//alert("worked");
//console.log(response);
alert(response);
},
error: function() {
alert("There was an error submitting the information");
}
});
I'm not quite sure how to mix these two and it may be partially because of getting a confused and not yet being that great with POST and AJAX calls.
EDIT: It looks like my question was a bit unclear (sorry first post lol) I'm trying to dynamically push values that I take out of an HTML form field. The problem is that the form is generated depending on what the user chooses to upload to the site (so both the fields and the forms. My ultimate goal is to enable the user to edit the dynamically generated form based on a text file that they upload and be able to generate a new text file after editing it on the GUI after clicking on the submit button. I can do this if its static but I'm having trouble figuring out how to do the same if I don't know what the form will contain.
I'm trying to to my data object so I can use it in my AJAX call. Here's a little bit of the PHP code that I would use in the next step if the variables were static:
if(isset($_POST['submitbtnclicked']) && $_POST['submitbtnclicked'] == 'submitted') {
//new instance of model for use
$model = new model();
$dimitypedata = $_POST['dimitypedata'];
$densitydata = $_POST['densitydata'];
$velocitydata = $_POST['velocitydata'];
$temperaturedata = $_POST['temperaturedata'];
For an exact answer, we need to see what the "subcategories" array look like.
If I understood correctly, you would like to put the values in an object instead of an array (values). So the first part would look like:
var data = {};
var arrayLength = subcategories.length;
for (var i = 0; i < arrayLength; i++) {
//notice that now field name and field value go in separate variables
var fieldName = subcategories[i];
//#C: selector is working fine, cleaning input
var fieldValue = $('#'+eachfield).val().trim();
//push the appropriate values with the fixed stuff to a data object
data[fieldName] = fieldValue;
}
//and then you send your gathered data
//using the data and sending it through a post with promise handling
$.ajax({
type: 'POST',
url: "controller.php",
data: data,
success: function(response) {
//alert("worked");
//console.log(response);
alert(response);
},
error: function() {
alert("There was an error submitting the information");
}
});
If you want to generate your 'data' object using 'values' variable, you can do the next:
values = []; // here your values collected previously
var data = {};
for (var key in values){
data[key] = values[key];
}
//now you can use your data in AJAX
I am using Express and Node to build an app.
I have a route called '/new-poll' and '/poll-create'
//The poll-create route will give the user the option of creating a poll
app.route('/poll-create')
.get(function(req, res) {
res.sendFile(path + '/public/pollcreation.html');
});
//This is the route for creating a new poll by authenticated users. Authentication still needs to be added.
app.route('/poll-create')
.post(function(req, res) {
console.log('inside poll-create post request');
console.log(req.body);
serverHandler.newPoll(req, res, db, function(id) {
console.log('It worked');
req.session.poll_id = id;
res.json(id);
});
});
//The above response will redirect to this route, and here is where the poll data will be served up
app.route('/new-poll')
.get(function(req, res) {
console.log('Inside get request for new poll');
console.log(req.session.poll_id);
res.sendFile(path + '/public/pollvisualization.html');
});
//This is the route for making a post request to the same URL. Specifically to obtain the document inserted previously through creating a new poll
app.route('/new-poll')
.post(function(req, res) {
console.log('Inside new poll post');
serverHandler.check(db, req.session.poll_id, function(err, doc) {
if (err) {
console.log('There is an error');
throw err;
}
if (doc) {
res.json(doc); //send the json document generated by the poll creation by mongoDb to pollvisualizationClient.js through ajax-functions.js
}
});
});
Now, I have 2 controllers, controllerData and controllerNonData.
controllerData passes in data to the above POST request using an AJAX call. controllerNonData needs to access the data passed to the POST request by controllerData.
How can I do this in the simplest possible manner? Essentially, my question boils down to what is the easiest way to pass data between view controllers in Express and Node?
The way I'm doing it right now is, I make a POST request with data from controllerData and then make a POST request without data from controllerNonData and then try to differentiate between the two calls in the POST request. But, it seems like a giant pain!
NOTE: I am not using AngularJS in my app. Mentioning this because all the answers I have seen on StackOverflow mention ways to do this in AngularJS.
EDIT:
Code for controllerData
(function() {
$(document).ready(function() {
if (typeof FB !== 'undefined' && FB !== null) { //this if statement is to ensure FB object loads before doing anything else
FB.Event.subscribe('auth.authResponseChange', function() {
FB.getLoginStatus(function(response) {
var data = {}; //setting up the data object to fill with objects
$('.submit-butt').on('click', function() {
data.formData = $('form').serializeArray(); //this is the form data from the form
data.facebookData = response.authResponse; //facebook object data
console.log(data);
data = JSON.stringify(data); //this is done to pass the data and parse it through body parser. Not sure why it works this way.
ajaxFunctions.ready(ajaxFunctions.ajaxRequest('POST', appUrl + '/poll-create', data, function() {
window.open('https://fcc-votingapp-redixhumayun.c9users.io/new-poll', '_self');
}));
return false; //setting this statement to false ensures that the form data does not automatically submit independent of the AJAX call
});
});
});
}
else {
location.reload(); //reloads the page in case the if statement is not satisfied.
}
});
})();
Code for controllerNonData
(function() {
var value; //variable to store the value of the radio option selected
var custom_flag = false; //flag variable to check whether Custom radio button was selected
//This is where the AJAX request is initialized
ajaxFunctions.ready(ajaxFunctions.ajaxRequest('POST', appUrl + '/new-poll', null, function(data) {
//Parsing the data into JSON format below
$(document).ready(function() {
//this is the form data that has been provided via the AJAX request
data = JSON.parse(data);
console.log(data);
var options_count = data[0].options_counter; //this variable stores the options_counter, that is the number of options
var options_array = getSeperatedOptions(data[0].options);
var options_length = Object.keys(options_count).length; //finding out the length of the options_counter object in this line
//updating the header element
$('h1').html(data[0].title);
//Invoking the function that will create all of the options required by the user
createOptions(options_length, options_array);
//This method here checks to see if the user has selected Custom as their option
$('.radio-options').on('click', function() {
var entered_value = getEnteredOption(options_length); //calling this function to check if Custom has been chosen.
if (entered_value == options_length) { //parseInt of entered_value will return a NaN. Use this to check against the number that is returned for parseInt of the other radio buttons
$('.custom-div').show();
custom_flag = true; //set the custom flag to true here because Custom radio button was selected
}
});
$('.btn-danger').on('click', function() {
ajaxFunctions.ready(ajaxFunctions.ajaxRequest('POST', appUrl + '/new-poll/delete-poll', data[0]._id, function(data) {
console.log('This is data: '+data); //data contains the number of documents deleted
}));
});
//Submit button event click handler
$('.submit-butt').on('click', function() {
//if statement decides whether the radio button selected was the Custom radio button
if (custom_flag == true) {
var entered_value = $('.custom-text').val();
value = entered_value; //assigning the local entered_value to a global value variable to use in the next AJAX function
}
//else if statement decides whether a radio option button is checked or not! Fires only if Custom not selected
else if ($('.radio-options').is(':checked')) {
var entered_value = getEnteredOption(options_length); //Function call to get option entered by user. Returns the value of the radio button
value = entered_value; //assigning the local entered_value to a global value variable to use in the next AJAX function
}
//Fire this else statement if no option is selected but Submit button is clicked
else {
window.alert('You need to choose an option before trying to submit');
}
if (value.length > 0) {
var dataToPass = {}; //defining this object to pass data as JSON
dataToPass.value = value;
dataToPass = JSON.stringify(dataToPass); //stringify data to pass it through without error
ajaxFunctions.ready(ajaxFunctions.ajaxRequest('POST', appUrl + '/new-poll/option-entered', dataToPass, function(data) {
//This object contains the returned value from the above AJAX call
data = JSON.parse(data);
var optionsArray = getSeperatedOptions(data.value.options); //Keep the difference between optionsArray and options_array in mind AT ALL TIMES!
//This function is used to convert the options_counter object to an array so that it can be used to render the chart using ChartJS
var options_counterArray = convertOptionsCounterToArray(data.value.options_counter);
//call to function to create chart here
createChart(optionsArray, options_counterArray);
}));
}
else {
window.alert('Hi!');
}
});
});
}));
})();
EDIT: I have also updated my routes to use sessions.
So I am assuming that your Controllers are on the client side. http is a stateless protocol. So in order to pass data between states, you need to implement some kind of caching mechanism. There are a few ways to do this:
Use HTML5 localStorage or sessionStorage API directly, based on the length of time you want to save the data. Make sure you clear the storage once you're done with the data, to prevent hitting the 5MB limit. Using localStorage will allow you to use the data till it is manually cleared. sessionStorage will live as long as the tab is open.
Use some other kind of client side storage like Web SQL
If you want to store data within a page reload cycle (i.e. you will lose data once you reload the page), you can create a Javscript singleton function and inject it into both of your AJAX calls as a dependency, and store your response in that object. This is similar to what happens in AngularJS's Service providers. This is cleaner than the other two approaches, but is of course, shorter lived (unless used on conjunction with one of the above Storage APIs)
Creating singletons in Javascript
var UserStore = (function(){
var _data = [];
function add(item){
_data.push(item);
}
function get(id){
return _data.find((d) => {
return d.id === id;
});
}
return {
add: add,
get: get
};
}());
I am using Python cherrypy and Jinja to serve my web pages. I have two Python files: Main.py (handle web pages) and search.py (server-side functions).
I create a dynamic dropdown list (using JavaScript) based on a local JSON file called component.json(created by function componentSelectBar inside search.py).
I want to ask how can my JavaScript retrieve JSON data without physically storing the JSON data into my local website root's folder and still fulfil the function of dynamic dropdown list.
The componentSelectBar function inside search.py:
def componentSelectBar(self, brand, category):
args = [brand, category]
self.myCursor.callproc('findComponent', args)
for result in self.myCursor.stored_results():
component = result.fetchall()
if (len(component) == 0):
print "component not found"
return "no"
components = []
for com in component:
t = unicodedata.normalize('NFKD', com[0]).encode('ascii', 'ignore')
components.append(t)
j = json.dumps(components)
rowarraysFile = 'public/json/component.json'
f = open(rowarraysFile, 'w')
print >> f, j
print "finish component bar"
return "ok"
The selectBar.js:
$.getJSON("static/json/component.json", function (result) {
console.log("retrieve component list");
console.log("where am i");
$.each(result, function (i, word) {
$("#component").append("<option>"+word+"</option>");
});
});
store results from componentSelectBar into database
expose new api to get results from database and return json to browser
demo here:
#cherrypy.expose
def codeSearch(self, modelNumber, category, brand):
...
result = self.search.componentSelectBar(cherrypy.session['brand'], cherrypy.session['category'])
# here store result into a database, for example, brand_category_search_result
...
#cherrypy.expose
#cherrypy.tools.json_out()
def getSearchResult(self, category, brand):
# load json from that database, here is brand_category_search_result
a_json = loadSearchResult(category, brand)
return a_json
document on CherryPy, hope helps:
Encoding response
In your broswer, you need to GET /getSearchResult for json:
$.getJSON("/getSearchResult/<arguments here>", function (result) {
console.log("retrieve component list");
console.log("where am i");
$.each(result, function (i, word) {
$("#component").append("<option>"+word+"</option>");
});
});
To use that json data directly into javascript you can use
var response = JSON.parse(component);
console.log(component); //prints
OR
You already created json file.If that file is in right format then you can read json data from that file using jQuery jQuery.getJSON() For more: http://api.jquery.com/jQuery.getJSON/
You are rendering a HTML and sending it as response. If you wish to do with JSON, this has to change. You should return JSON in your main.py, whereas you will send a HTML(GET or POST) from Javascript and render it back.
def componentSelectBar(self, brand, category):
/* Your code goes here */
j = json.dumps(components)
// Code to add a persistent store here
rowarraysFile = 'public/json/component.json'
f = open(rowarraysFile, 'w')
print >> f, j
// Better to use append mode and append the contents to the file in python
return j //Instead of string ok
#cherrypy.expose
def codeSearch(self):
json_request = cherrypy.request.body.read()
import json # This should go to the top of the file
input_dict = json.loads(json_request)
modelNumber = input_dict.get("modelNumber", "")
category = input_dict.get("category", "")
brand = input_dict.get("brand", "")
/* Your code goes here */
json_response = self.search.componentSelectBar(cherrypy.session['brand'], cherrypy.session['category'])
return json_response
Here, I added only for the successful scenario. However, you should manage the failure scenarios(a JSON error response that could give as much detail as possible) in the componentSelectBar function. That will help you keep the codeSearch function as plain as possible and help in a long run(read maintaining the code).
And I would suggest you to read PEP 8 and apply it to the code as it is kind of norm for all python programmers and help any one else who touches your code.
EDIT: This is a sample javascript function that will make a post request and get the JSON response:
searchResponse: function(){
$.ajax({
url: 'http://localhost:8080/codeSearch', // Add your URL here
data: {"brand" : "Levis", "category" : "pants"}
async: False,
success: function(search_response) {
response_json = JSON.parse(search_response)
alert(response_json)
// Do what you have to do here;
// In this specific case, you have to generate table or any structure based on the response received
}
})
}
I have pass a collection of objects through http post in angular js.
The code is as follows:
$scope.selectedContent = function () {
var contents = $filter('filter')($scope.data.ContentId, { Selected: true }); // I could able to get all the selected objects here, No problem with it
var jsonData = angular.toJson(contents); //It is not able to convert to Json if there are more than 5 records
var promise = $http.post('/webapi/cmsApi/CmsPublishApprovedContent?jsonData=' + jsonData, {});
promise.success(function () {
window.location.reload();
});
[ReferrerFilterAttribute]
[HttpPost]
[System.Web.Http.ActionName("CmsPublishApprovedContent")]
public void CmsPublishApprovedContent(string jsonData)
{
var contents = JsonConvert.DeserializeObject<List<ContentNodeInWorkFlow>>(jsonData);
foreach (var content in contents)
{
_contentService.PublishContent(content.ContentId, userId);
}
}
}
The above code works fine if there are 5 records or less. If there are more records, I could able to get all the selected record
objects in the variable 'contents'. But the problem is occuring when converting to Json for all those objects. I
have about 500 records to pass through. How can do I it?
There is no specific reason to convert to JSON data. I just need to extract the ids of all the selected items. I have modified the above code as below:
$scope.selectedContent = function () {
var contents = $filter('filter')($scope.data, { Selected: true });
var abc = [];
angular.forEach(contents, function(content)
{
abc.push(content.ContentId); // got all the ids in the array now
});
var promise = $http.post('/webapi/cmsApi/CmsPublishApprovedContent' ,{contents : abc});
promise.success(function () {
window.location.reload();
});
}
I have just took an array and pushed all the content ids into it. I could able to see all the ids in the array now. I tried to pass the array as above.
How to retrieve those array in the code behind.
[ReferrerFilterAttribute]
[HttpPost]
[System.Web.Http.ActionName("CmsPublishApprovedContent")]
public void CmsPublishApprovedContent(int[] abc)
{}
I do not see any values obtained under int[] abc. What will be the datatype for the parameter in the method call above.
You need second argument of $http.post method. You have to send such data by POST requests, not in query of url. You can put some data into body of the post request.
You need this:
var postBodyWithHugeAmountOFData = {data: [1,2,3,4,5...500]};
$http.post(url, postBodyWithHugeAmountOFData).success(function () {});
Also, you must be ready to handle this request in your backend.
is there any specific reason u want to pass this data as a JSON?.
if u r using Web API in that case u can pass the object as it is but only make sure that collection in web API method contains all the property in javascript collection
Thank you for all your posts. It's working fine without converting to Json. The code is as below.
$scope.selectedContent = function () {
var contents = $filter('filter')($scope.data, { Selected: true });
var promise = $http.post('/webapi/cmsApi/CmsPublishApprovedContent' ,contents);
promise.success(function () {
window.location.reload();
});
}
and the signature would be
public void CmsPublishApprovedContent(List<ContentNodeInWorkFlow> abc)
{
}
I have working on a webpage that displays json data in a html hierarchical structure, using the jQuery plugin json2html.
Currently the json data is entered into a text area and a button is pressed to run the conversion. This is the current function that gets the json from the text area and starts the conversion.
$('#btnVisualize').click(function() {
//Get the value from the input field
var json_string = $('#inputJSON').val();
try
{
//json
//var json = JSON.parse(json_string);
eval("var json=" + json_string);
visualize(json);
}
catch (e)
{
alert("Sorry error in json string, please correct and try again: " + e.message);
}
});
The api that the data is comming from needs a lot of authentication, so I have a seperate javascript file that generates the authenticaton and creates the full url to load the api.
function generateUrl(itemkey) {
var orig = "http://explorerapi.barratthomes.co.uk/v2.0/development/getbyitemkey?ItemKey="+itemkey+"&";
Auth.Auth = createAuth();
var var_pairs = [
{name: "Auth.Utc", val: encodeURI(Auth.Auth.Utc)},
{name: "Auth.RequestId", val: Auth.Auth.RequestId},
{name: "Auth.DeviceId", val: Auth.Auth.DeviceId},
{name: "Auth.Hash", val: Auth.Auth.Hash}];
for(var i=0; i<var_pairs.length; i++) {
orig += (i==0?"":"&")+var_pairs[i].name+"="+var_pairs[i].val;
}
var var_names = ["BrandCode", "ApplicationId", "ApplicationVersion", "LanguageCode", "IsPublished", "MarketingSuiteDevelopmentId", "UserLocation", "Os", "ScreenResolution", "Hierarchical"];
for(var j=0; j<var_names.length; j++) {
orig += "&"+var_names[j]+"="+Auth[var_names[j]];
}
return orig;
}
This is the function that generates the url.
I need to take the url from that function and connect to the api and pass the data directly to the json2html function, so I no longer have to paste the json data into the text area.
I have been looking at $.getJson and $.parseJSON but having no luck, I'm not sure where to go next?
Try this Jsonp to do the fetching the data from the url
function insertIntoTextArea(content) {
document.getElementById('output').innerHTML = content;
}
// create script element
var script = document.createElement('script');
// assing src with callback name
script.src = 'your proper url?callback=insertIntoTextArea';
// insert script to document and load content
document.body.appendChild(script);
You should be able to use $.getJSON like this
$.ajax({
dataType: "json",
url: url,
data: data,
success: success
});
And then just pass the data object to json2html. However, check with the API that you're connecting to http://explorerapi.barratthomes.co.uk/v2.0/development/getbyitemkey as they might require JSONP (which pretty much just performs a callback function to get around CORS).
See http://api.jquery.com/jquery.getjson/
If the URL includes the string "callback=?" (or similar, as defined by the >server-side API), the request is treated as JSONP instead. See the discussion >of the jsonp data type in $.ajax() for more details.