I am working with jQuery and doing some prototyping.
In my app, I use jQuery.ajax() to get some HTML from the server, then it needs to be inserted into a DIV in the page.
Here are the relevant parts of my code:
SONGS_UPLOADER.prototype.FileSelectHandler = function(e) {
this.FileDragHover(e);
var files = e.target.files || e.dataTransfer.files;
var target = this.target;
var artist_id = this.artist_id;
var album_id = this.album_id;
var onComplete = this.onSongUploaded;
for ($x = 0; $x < files.length; $x ++) {
var file = files[$x];
jQuery.ajax({
type: 'post',
dataType : 'html',
url: ajaxurl,
data: {action: 'add_new_song', artist_id: artist_id, album_id: album_id, title:file.name},
success: function(DATA)
{
onComplete(DATA);
}
});
}
}
SONGS_UPLOADER.prototype.files;
SONGS_UPLOADER.prototype.onComplete;
SONGS_UPLOADER.prototype.album_id;
SONGS_UPLOADER.prototype.artist_id;
SONGS_UPLOADER.prototype.target;
SONGS_UPLOADER.prototype.onSongUploaded = function(DATA){
var song = jQuery(DATA);
//console.log(target.find('.songs_list'));
this.target.find('.songs_list').append(song);
new SONGS_MANAGER(song, file);
}
In the AJAX complete function I have tried the following:
onComplete(DATA) - this calls the onSOngUploaded function, but the 'this.target' in onSongUploaded is undefined.
this.onSongUploaded and onSongUploaded - got an error that onSongUploaded does not exist.
jQuery.proxy(this.onSongUploaded (and) onSongUploaded, this) - got an error that onSOngUploaded does not exist.
I know it probably has something to do with the scope when using the jQuery.ajax() function, but I just can't figure out how to resolve it.
How can I adjust my code so the onSongUploaded function is called and respects the 'this' keyword on the SONGS_UPLOADER object?
Related
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 2 years ago.
I have two functions main function which JQuery , and the other one in Javascript.
jQuery :
$(document).ready(function () {
$('#ProvisionLink').click(function () {
var queryTargetList = [ "Item1","Item2","Item3","Item4"]
var data = ["Data1","Data2","Data3","Data4" ]
event.preventDefault();
var i;
for(i = 0; i < queryTargetList.length; ++i) {
var dataItem = data[i];
var QueryItems = queryTargetList[i];
console.log("Before Launching the Javascript : " +QueryItems)
$.ajax({
url: '/operation',
data: {DataType: dataItem,},
type: 'POST',
success: function (response){ getInventory(response,QueryItems) },
error: function (error) {console.log(error);}
});
}
});
});
Java script :
function getInventory(data,queryTarget){
console.log("In Get Inventory Function in javascript ... " +queryTarget)
var queryTarget = "#"+queryTarget
// get the query id
const SelectBoxQuery = document.querySelector(queryTarget)
console.log(SelectBoxQuery)
// resetting the values to enter all the new one.
SelectBoxQuery.options.length = 0; // reset the values
// making a loop to reach each element item in the list
for (var i = 0; i < data.length; ++i) {
// add new element which is option to the targeted ID
var SelectBoxQuery_Addition = document.createElement('option');
// adding a text to that option
SelectBoxQuery_Addition.text = data[i];
// apply the adding .
SelectBoxQuery.add(SelectBoxQuery_Addition)
}}
The problem is, after i get response from python FLASK to Jquery function. in success part it should launch the javascript function with the same i of the queryTargetList.
for example if i pass data[1], i expect to have queryTargetList[1] also.
but in javascript console.log function. that does not happen. it printing the last item of the queryTargetList list.
Print:
Before Launching the Javascript : Item1
JQueryTests.js:11 Before Launching the Javascript : Item2
JQueryTests.js:11 Before Launching the Javascript : Item3
JQueryTests.js:11 Before Launching the Javascript : Item4
operationJavaScript.js:115 In Get Inventory Function in javascript ... Item4
In Get Inventory Function in javascript ... Item4
In Get Inventory Function in javascript ... Item4
In Get Inventory Function in javascript ... Item4
I do not know what am doing wrong :(
Since the ajax call is an async operation, the loop variable i would have changed by the time the success method gets called. There is no guarantee that the i would have reached the end.
You would need to wrap the variables, in a closure so that it success methods gets the correct item.
Sample code not tested.
$(document).ready(function () {
$('#ProvisionLink').click(function () {
var queryTargetList = [ "Item1","Item2","Item3","Item4"]
var data = ["Data1","Data2","Data3","Data4" ]
event.preventDefault();
var i;
for(i = 0; i < queryTargetList.length; ++i) {
var dataItem = data[i];
var QueryItems = queryTargetList[i];
console.log("Before Launching the Javascript : " +QueryItems)
(data,queryItem)=>{
$.ajax({
url: '/operation',
data: {DataType: data,},
type: 'POST',
success: function (response){ getInventory(response,queryItem) },
error: function (error) {console.log(error);}
});
})(dataItem,QueryItems);
}
});
});
set the async option to false:
$.ajax({
url: '/operation',
data: {DataType: dataItem,},
async: false,
type: 'POST',
success: function (response){ getInventory(response,QueryItems) },
error: function (error) {console.log(error);}
});
Another way: send queryTargetList[i] value to server and response get from server..
You must consider the issue of synchronization and non-synchronization, because you did not set the async attribute, so the default will be true. The easiest way is to set the async attribute to false
Like my example below, for detailed usage, you can refer to here
$.ajax({
url: '/operation',
data: {DataType: dataItem,},
type: 'POST',
async: false,
success: function (response){ getInventory(response,QueryItems) },
error: function (error) {console.log(error);}
});
I am running a loop function with an AJAX request inside it, and the success function on the AJAX need to access a counter variable outside of the loop function, but it wont access it.
var updateCount = 10;
var runCount = 0;
$('#main-table .changed').not("[value='0']").closest('tr').each(function(e){
if($(this).closest('tr').find('.changed').val() == 1){
var row = $(this).closest('tr');
var notes = row.find('input[name="notes"]').val();
var category = row.find('select[name="category"]').val();
var fileId = row.find('select[name="file"]').val();
var fileRow = row.find('.file-id').val();
var quarter_id = row.find('.quarter-id').val();
$.ajax({
url: '/myurl',
type: "POST",
data: {_token: CSRF_TOKEN, 'file_row' : fileRow, 'files' : fileId, 'notes': notes, 'category' : category, 'type' : type, 'quarter': quarter_id, 'row_count':updateCount},
success: function(data){
if(data == 0){
console.log("yes");
//I need to increment the runcount here, but it wont increment
runCount++;
}
}
});
//If i increment the run count here outside the AJAX request, it works
runCount++;
if(runCount == updateCount){
console.log("Done");
}
};
});
As stated in the notes, i need to access the runCount variable inside the ajax success function, but I cant. It works fine if I access it just outside of the AJAX request.
Just to confirm, the ajax request is working, as it is console logging yes for each time, so I cant see why it wouldn't increment?
there is likely a better way to do it, but one sure-fire way is to make another function (in javascript) and update it with that, like:
function bumpRunCount(){
runCount++;
}
then call that function from the ajax result. That of course is dependent on the scope of runCount. I only mention that because you mention a function, and I dont see one, so it is possible that you are only showing a part of the function. If that is the case, you will need to make sure var runCount is part of the global namespace; or at least accessible.
To avoid this scope problem try this, try parsing the variable inside the loop function
var runCount = 0;
$('#main-table .changed').not("
[value='0']").closest('tr').each((runCount)=>{
if($(this).closest('tr').find('.changed').val() == 1){
var row = $(this).closest('tr');
var notes = row.find('input[name="notes"]').val();
var category = row.find('select[name="category"]').val();
var fileId = row.find('select[name="file"]').val();
var fileRow = row.find('.file-id').val();
var quarter_id = row.find('.quarter-id').val();
$.ajax({
url: '/myurl',
type: "POST",
data: {_token: CSRF_TOKEN, 'file_row' : fileRow, 'files' :
fileId, 'notes': notes, 'category' : category, 'type' :
type,
'quarter': quarter_id, 'row_count':updateCount},
success: function(data){
if(data == 0){
console.log("yes");
//I need to increment the runcount here, but it wont increment
runCount++;
}
}
});
//If i increment the run count here outside the AJAX request, it
works
//runCount++;
};
});
I'm writing something to get all the layers names from my GeoServer. This is my code:
function getData() {
return $.ajax({
url: "http://localhost:8080/geoserver/ows?service=wms&version=1.1.0&request=GetCapabilities",
type: 'GET'
});
}
function onComplete(data) {
var parser = new ol.format.WMSCapabilities();
var result = parser.read(data.responseText);
var layersArray = result.Capability.Layer.Layer;
layersNameArray = [];
for(i=0;i<layersArray.length;i++){
layersNameArray.push(layersArray[i].Name)
}
return layersNameArray
}
getData().done(onComplete)
I'm far from an expert with asynchronous calls, but I think this one is supposed to work. If I stock the getData() result in a variable and run the onComplete() function line by line, the code works. But when I run the code with getData().done(onComplete), it always fails at the var result = parser.read(data.responseText);line with Assertion error: Failure.
Any idea why this isn't working ?
Edit:
This code works, but nothing is returned. I want the function to output the layersNameArrayvariable. How should I proceed ?
function getData() {
$.ajax({
url: "http://localhost:8080/geoserver/ows?service=wms&version=1.1.0&request=GetCapabilities",
type: 'GET',
success: function(response) {
var parser = new ol.format.WMSCapabilities();
var result = parser.read(response);
var layersArray = result.Capability.Layer.Layer;
layersNameArray = [];
for(i=0;i<layersArray.length;i++){
layersNameArray.push(layersArray[i].Name)
}
return layersNameArray
}
});
}
You can make use of the Jquery callback feature,
make a call to your function this way,
getData(function(responsefromAjax){
alert('the response from ajax is :' +responsefromAjax);
// what ever logic that needs to run using this ajax data
});
And the make change to your method this way.
function getData(callback) { // passing the function as parameter
$.ajax({
url: "http://localhost:8080/geoserver/ows?service=wms&version=1.1.0&request=GetCapabilities",
type: 'GET',
success: function(response) {
var parser = new ol.format.WMSCapabilities();
var result = parser.read(response);
var layersArray = result.Capability.Layer.Layer;
layersNameArray = [];
for(i=0;i<layersArray.length;i++){
layersNameArray.push(layersArray[i].Name)
}
callback(layersNameArray); //this will execute your function defined during the function call. As you have passed the function as parameter.
}
});
}
Let me know if this helps
i have a simple XML file which is loaded on page by a script posted below. It converts from a string to a XML file without any problems, but what complicates everything is the fact, that I can't get to a child's child.
I'd like to know why my code doesn't work and what should I do to get the tag name.
function load_xml() {
$.ajax({
type: "GET",
url: "file.xml",
dataType: "xml",
success: function (xmlData) {
var $first_child = $(xmlData).children()[0];
var first_name = $first_child.nodeName; // returns a proper name of a node
var $second_child = $first_child.children()[0]; // doesn't work
var $second_name = $second_child.nodeName; // returns nothing (don't know why)
},
error: function () {
alert("Could not retrieve XML file.");
}
});
}
In your case $first_child is not a jQuery collection. You need to wrap it with $(). Here is a corrected version.
var first_child = $(xmlData).children()[0]; // [0] actually returns the first "raw" node
var first_name = first_child.nodeName;
var $first_child = $(first_child);
var second_child = $first_child.children()[0];
var second_name = second_child.nodeName;
I'm using JQuery's implementation of AJAX to access multiple JSON and different URLS. I have an array of names that each URL corresponds to, and would like to be able to reference the corresponding name that goes with the corresponding JSON file in the callback funciton of the AJAX request.
I've written a sample of my code so far for testing:
var nameList = ['Tom', 'Neil', 'Jane'];
for(var i = 0; i < nameList.length; i++){
var currentName = nameList[i];
var newURL = urlFromName(currentName)
$.ajax({
type: 'GET',
url: newURL,
dataype: 'jsonp'
}).always(function(data,status, error){
console.log(currentName);
console.log(data);
});
}
The code outputs:
- Neil
- Object
- Neil
- Object
- Neil
- Object
I am looking for each Object to be printed out with the corresponding name from the nameList that I have supplied it. How would I go about doing this?
Try this:
var nameList = ['Tom', 'Neil', 'Jane'];
for(var i = 0; i < nameList.length; i++){
var currentName = nameList[i];
var newURL = urlFromName(currentName)
$.ajax({
type: 'GET',
url: newURL,
dataype: 'jsonp',
currentName: currentName // <-- Add this here
}).always(function(data,status, error){
console.log(this.currentName); // <-- Use the 'this' to get it
console.log(data);
});
}