Problem with scope when inserting results of ajax call into page code - ajax

I have data returned from an Ajax call, but need to pass variables into or out of the Ajax onSuccess function to insert the results into my page. I'm pretty sure this is a scope problem.
I posted a complicated question here yesterday, mostly about the Ajax part of this, and that part is now working - I'm getting the results back correctly. I could insert it into my page code in two ways, but one involves getting a variable value out of the onSuccess function; the other needs to get a variable value into it! I can't make either of them work. Here's a stripped-down version of the code:
var base = 'http://10.0.1.2:90/~dvds/';
// initialization routines
document.observe ('dom:loaded', function() {
// set up handler for variable numbers of selects
var addselects = $$('.addselect');
for (var i = 0; i < addselects.length; i++) {
var addselect = addselects[i];
addselect.onchange = newSelect;
}
});
// handler for adding new field to array
function newSelect() {
var thisid = this.id;
var newhtml;
var url = base + 'ajaxtest';
// send request to do the business
var myAjax = new Ajax.Request (url, {
method: 'post',
onSuccess: function (req) {
var xml = req.responseXML;
var id = xml.getElementsByTagName('id')[0].firstChild.nodeValue;
if (id) {
newhtml = '\t\t<li>\r\t\t\t<select class="addselect" name="newlist" id="newlist" />\r\t\t\t\t<option value="" selected="selected"></option>\r';
// loop
var newid, newname;
var ids = xml.getElementsByTagName('id');
var names = xml.getElementsByTagName('name');
for (var i = 0; i < ids.length; i++) {
newid = ids[i].firstChild.nodeValue;
newname = names[i].firstChild.nodeValue;
newhtml += '\t\t\t\t<option value="' + newid + '">' + newname + '</option>\r';
}
newhtml += '\t\t\t</select>\r\t\t</li>\r';
// alert (thisid);
$('thisid').up('ul').insert (newhtml);
}
else {
alert (’ng');
newhtml = '<li>No good.</li>';
}
},
onFailure: function() {
alert ('Script failure.');
newhtml = '<li>No good.</li>';
}
});
// alert (newhtml);
// if (newhtml) {
// this.up('ul').insert (newhtml);
// }
}
Having established the variable thisid as this.id, I don't understand why $('thisid') doesn't work in the line $('thisid').up('ul').insert (newhtml); - especially as the value of thisid does show up correctly in the alert I've put in for testing (commented out). Why is this? If I put newhtml into that alert instead it's also correct.
And given that that seems not to work, I tried the alternative of passing the value of newhtml out (having declared it at the top) and inserting it in the page in the last block of code that's commented out - but that doesn’t work either.
Where am I going wrong?

Related

Submitting data to google sheet with multiple tab sheets

I'm referencing this article "How to Submit an HTML Form to Google Sheets…without Google Forms", it worked perfectly for me for only a Google Sheet with one tab.
Need help how to dynamically select what sheet tab the data should be written in the case the google sheet has multiple tabs. I'm using Ajax to submit google sheet btw.
Here's the call by the Ajax:
var $form = $('form#test-form'),
url = 'https://script.google.com/macros/s/MyScript/exec'
$('#submit-form').on('click', function(e) {
e.preventDefault();
var jqxhr = $.ajax({
url: url,
method: "GET",
dataType: "json",
data: $form.serializeObject()
}).success(
// do something
);
})
The code on google sheet web app
function doGet(e){
return handleResponse(e);
}
// Enter sheet name where data is to be written below
var SHEET_NAME = "Sheet1";
var SCRIPT_PROP = PropertiesService.getScriptProperties(); // new property service
function handleResponse(e) {
// shortly after my original solution Google announced the LockService[1]
// this prevents concurrent access overwritting data
// [1] http://googleappsdeveloper.blogspot.co.uk/2011/10/concurrency-and-google-apps-script.html
// we want a public lock, one that locks for all invocations
var lock = LockService.getPublicLock();
lock.waitLock(30000); // wait 30 seconds before conceding defeat.
try {
// next set where we write the data - you could write to multiple/alternate destinations
var doc = SpreadsheetApp.openById(SCRIPT_PROP.getProperty("key"));
var sheet = doc.getSheetByName(SHEET_NAME);
// we'll assume header is in row 1 but you can override with header_row in GET/POST data
var headRow = e.parameter.header_row || 1;
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
var nextRow = sheet.getLastRow()+1; // get next row
var row = [];
// loop through the header columns
for (i in headers){
if (headers[i] == "Timestamp"){ // special case if you include a 'Timestamp' column
row.push(new Date());
} else { // else use header name to get data
row.push(e.parameter[headers[i]]);
}
}
// more efficient to set values as [][] array than individually
sheet.getRange(nextRow, 1, 1, row.length).setValues([row]);
// return json success results
return ContentService
.createTextOutput(JSON.stringify({"result":"success", "row": nextRow}))
.setMimeType(ContentService.MimeType.JSON);
} catch(e){
// if error return this
return ContentService
.createTextOutput(JSON.stringify({"result":"error", "error": e}))
.setMimeType(ContentService.MimeType.JSON);
} finally { //release lock
lock.releaseLock();
}
}
function setup() {
var doc = SpreadsheetApp.getActiveSpreadsheet();
SCRIPT_PROP.setProperty("key", doc.getId());
}
If there is a way to change the variable SHEET_NAME dynamically then I think it will be good. Thanks

How do I access every index of a specific Array inside an AJAX object

I'm calling an ajax for giphy, with this code:
$.ajax({
url: queryURL,
method: "GET"
}). then(function(response) {
console.log(response);
when I look at the console log there's an object with the first property being data. Each index of data is another object, inside this object are two properties i'm trying to pull, rating and url. I want to be able to list the rating and url not just of a specific index, but every index in that data array. What would be the best way to do that? Currently I've tried a for loop
for (var i = 0; i<response.data.length;i++){
var dataIndex = response.data[i];
}
then <creating a variable something like>
var imgURL = response.data[dataIndex].url
but its not working.
Here's the entire code
function displayTopicGif() {
var topic = $(this).attr("data-name");
// query url
var queryURL = "https://api.giphy.com/v1/gifs/search?q=" + topic + "&limit=20&rating=r&api_key=";
$.ajax({
url: queryURL,
method: "GET"
}).then(function (response) {
console.log(response);
// for loop to create a variable for the index of the objects data
for (var i = 0; i < response.data.length; i++) {
var dataIndex = response.data[i];
}
// where the gif's will be dumped
var topicDiv = $("<div class='topic'>");
// rating of gif
var rating = response.data[0].rating;
console.log(rating);
// Creating an element to have the rating displayed
var pOne = $("<p>").text("Rating: " + rating);
// add to the rating element
topicDiv.append(pOne);
// retrieve the IMG of the gif
var imgURL = response.data[0].url;
var image = $("<img>").attr("src", imgURL);
topicDiv.append(image);
// put gif into topic-view div
$("#topic-view").prepend(topicDiv);
});
}
You can check that something is an object using $.isPlainObject and then read through its properties via:
for (key in object) {
var value = object[key];
//log
}
Or you can get the keys using Object.getOwnPropertyNames();. See this sample excerpt from MDN:
const object1 = {
a: 1,
b: 2,
c: 3
};
console.log(Object.getOwnPropertyNames(object1));
// expected output: Array ["a", "b", "c"]

Dragula not sending AJAX request

I am using the following code to sort the rows of a table based on Ids. I am using Dragula for drag and drop functionality. The Sorted Ids is presented in the variable sortedIDs. The alert present within if(sortedIDs) is showing an alert, but no request is being sent using AJAX.
var container = document.getElementById('tb');
var rows = container.children;
var nodeListForEach = function (array, callback, scope) {
for (var i = 0; i < array.length; i++) {
callback.call(scope, i, array[i]);
}
};
var sortableTable = dragula([container]);
var pingu='';
sortableTable.on('dragend', function() {
nodeListForEach(rows, function (index, row) {
//alert(row.id);
pingu=pingu+','+row.id;
//alert(pingu);
// row.lastElementChild.textContent = index + 1;
// row.dataset.rowPosition = index + 1;
});
var sortedIDs=pingu;
pingu='';
// alert (sortedIDs);
if (sortedIDs) {
alert(sortedIDs);
$.ajax({
type: 'GET',
url: '<?php echo $site_url . 'index.php/API/p2376ghDSPOLWYBdhBT'?>',
data: 'lmqSPOEhyVt87H6tBYSfdreg=' + sortedIDs + '&hjhqweuty87685gh87GCfsc6HF=' + sbds98JWUDGHKJ98yujg,
success: function (tata) {
alert (tata);
if (tata == '1') {
$("#success").show();
$('#success').delay(2000).fadeOut('slow');
} else {
$("#failure").show();
$('#failure').delay(5000).fadeOut('slow');
}
}
});
} else {
//$('#ms').html('<option value="">Select Q level first</option>');
}
});
And when i am adding
error : function(jqXHR, textStatus, errorThrown){
}
for showing AJAX error, it starts throwing the alert too.
Any sort of help would be deeply appreciated.
Thanks
I solved the problem. I forgot to retrieve the value of an attribute and send it to the API.
var sbds98JWUDGHKJ98yujg = $('#p2JMopns3hfBubNNHJeer').val();

Removing appended isotope items

I'm appending isotope items via Ajax in Wordpress:
My JS Code:
var $news_container = $('#news'); //The ID for the list with all the blog posts
$news_container.isotope({ //Isotope options, 'item' matches the class in the PHP
itemSelector: '.newsItem',
masonry: {
columnWidth: '.news-item-sizer',
gutter: '.gutter-sizer'
}
});
var has_run = false;
var init_offset = 0;
$('button.showall').click(function(e) {
e.preventDefault();
var button = $(this);
// Disable button
$(button).removeClass('showall');
$(button).addClass('showless');
// Record Nonce
var nonce = $(this).data("nonce");
if(has_run == false) {
button.data('offset', $(this).data("offset"));
init_offset = $(this).data("offset");
}
// Set AJAX parameters
data = {
action: 'mft_load_more_ajax',
init_offset: init_offset,
offset: button.data('offset'),
nonce: nonce
};
$.post(mft_load_more_ajax.ajaxurl, data, function(response) {
// Set Container Name
var response = JSON.parse(response);
console.log(response);
// Run through JSON
$.each( response, function( key, value ) {
// Set Value
var val = $(value);
// Set Container
var $container = $('#news').isotope();
// Append Val
$container.append(val).isotope( 'appended', val );
$(button).html('show less');
});
// Set Offset
var offset = button.data("offset");
button.data("offset", offset + 11 );
// If Has Run
has_run = true;
return false;
}
Until now, this works quite fine. Now I would like to switch the buttontext and it's class to .showless and on the next click all previously appended items should be removed. They all have the class .newsItem.appendedItem.
I tried this method:
$('button.showless').click(function(e) {
var button = $(this);
console.log('showless');
$out = $('.newsItem.appendedItem');
var isotopeInstance = $('#news').data('isotope');
isotopeInstance.$allAtoms = isotopeInstance.$allAtoms.not($out);
$out.remove();
// Disable button
$(button).removeClass('showless');
$(button).addClass('showall');
has_run = false;
return false;
});
Unfortunately this doesn't work, because the showless function is not even being entered, as I don't get a log in the console. What am I overlooking?
Thanks for your help!
Cara
Update 1:
I'm getting this error in Google Console.
Not sure, what was the problem now. But I cleaned the code a little bit with using an if statement, to check if the elements already got appended.
So my final code now looks like this:
var $news_container = $('#news'); //The ID for the list with all the blog posts
$news_container.isotope({ //Isotope options, 'item' matches the class in the PHP
itemSelector: '.newsItem',
masonry: {
columnWidth: '.news-item-sizer',
gutter: '.gutter-sizer'
}
});
var is_appended = false;
$('button.showall').click(function(e) {
e.preventDefault();
var button = $(this);
// Record Nonce
var nonce = $(this).data("nonce");
if(is_appended == false) {
button.data('offset', $(this).data("offset"));
// Disable button
button.prop( "disabled" , true );
// Set AJAX parameters
data = {
action: 'mft_load_more_ajax',
offset: button.data('offset'),
nonce: nonce
};
$.post(mft_load_more_ajax.ajaxurl, data, function(response) {
// Set Container Name
var response = JSON.parse(response);
console.log(response);
// Run through JSON
$.each( response, function( key, value ) {
// Set Value
var val = $(value);
// Set Container
var $container = $('#news').isotope();
// Append Val
$container.append(val).isotope( 'appended', val );
});
// Undo Button Disable
button.prop( "disabled" , false );
button.html('Weniger News anzeigen');
// Set Offset
// var offset = button.data("offset");
// button.data("offset", offset + 11 );
// If Was appended
is_appended = true;
return false;
});
} else if(is_appended == true) {
$out = $('.newsItem.appendedItem');
$news_container.isotope( 'remove', $out )
// layout remaining item elements
.isotope('layout');
button.html('Alle News anzeigen');
is_appended = false;
return false;
}
});
In Chrome everything works perfectly. But just figured out, that in Firefox my Ajax array is completely empty and I'm not able to fetch any data. Probably another problem, I'm going to post separately.

Ajax call within a loop using $resource

I'm in difficulty doing this operation correctly.
I have an Order and for every item I have to get the data from the API, what I'm doing is this:
if ($scope.order.order_items.length > 0) {
var itemArray = [];
for (var i = 0; i < $scope.order.order_items.length; i++) {
var itemId = $scope.order.order_items[i].id;
Items.get({
itemId: itemId
}).$promise.then(function (data) {
itemArray.push(data.item);
});
}
$scope.order.order_items = itemArray;
}
The API receive the request and send the data back but the promise do not return anything...
One more error here is from jshint: Don't make functions within a loop.
It will be nice to solve both the issues for me... I tried to create an external function but having the same issue not returning data I don't know if I was doing it well, the external function I was doing is:
function addItem(id) {
Items.get({
itemId: id
}).$promise.then(function (data) {
console.log(data);
return data.item;
});
}
You are making an asynchronous call from the code and thinking that it will work like synchronously. As you are assigning itemArray to $scope.order.order_items outside the factory, at that time itemArray is blank. Before making that assignment you need to ensure that all the ajax call the each item has been completed or not. You could use $q.all for such scenario. $q.all need an promise array & it will call the .then function when all the promise gets resolved.
if ($scope.order.order_items.length > 0) {
var itemArray = [], promiseArray = [];
for (var i = 0; i < $scope.order.order_items.length; i++) {
var itemId = $scope.order.order_items[i].id;
var currentPromise = Items.get({
itemId: itemId
}).$promise.then(function (data) {
itemArray.push(data.item);
return true; //returning dummy value from promise.
});
promiseArray.push(currentPromise); //creating promise array
}
$q.all(promiseArray) //giving promise array input.
.then(function(data){ //success will call when all promises get resolved.
$scope.order.order_items = itemArray;
},function(error){
console.log("Error occured")
});
}
I would avoid reading and writing to the same array and instead use another array for the actual items.
As Resource returns an instance that gets filled on success you should be fine adding the instances to the scope directly. With that you reduce your code a lot and also remove the jshint warning.
if ($scope.order.order_items.length > 0) {
$scope.order.order_items_with_data = [];
for (var i = 0; i < $scope.order.order_items.length; i++) {
var itemId = $scope.order.order_items[i].id;
$scope.order.order_items_with_data.push(Items.get({itemId: itemId}));
}
}

Resources