This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 3 years ago.
I am writing data to firebase using a loop and async function. I am using promises to get the result of query and want to display success message when all of data is inserted. I can not figure out what I am doing wrong. I know it has a small bug. Can anyone help me?
CODE:
async function submitAttendance() {
var uploadPromises = [];
for (var j = 0; j < i; j++) {
uploadPromises.push(
new Promise((resolve, success) => {
var naid = "name" + j + "";
var na = document.getElementById(naid).innerHTML + "";
var stid = "status" + j + "";
var stat = document.getElementById(stid).value + "";
var uidid = "uid" + j;
var uidstu = document.getElementById(uidid).innerHTML + "";
var attinfo = {
student_Id: uidstu,
student_attendanceValue: stat,
student_class: clstd,
student_name: na
};
db.collection("Parent").doc(uidstu).collection("Attendance").doc(f).set(attinfo).then(function () {
console.log(attinfo);
});
})
)
}
await Promise.all(uploadPromises)
alert("Attendance Marked Successfully");
}
uploadPromises.push(
new Promise((resolve, success) => {
...
db.collection("Parent").doc(uidstu).collection("Attendance").doc(f).set(attinfo).then(function () {
console.log(attinfo);
resolve();
});
})
)
You need to resolve inside your promise somewhere. Presumably in the .then of your db interaction
However, rather than returning a manually created promise, you may consider pushing the db interaction itself if it is a promise, which it looks like:
for (var j = 0; j < i; j++) {
var naid = "name" + j + "";
var na = document.getElementById(naid).innerHTML + "";
var stid = "status" + j + "";
var stat = document.getElementById(stid).value + "";
var uidid = "uid" + j;
var uidstu = document.getElementById(uidid).innerHTML + "";
var attinfo = {
student_Id: uidstu,
student_attendanceValue: stat,
student_class: clstd,
student_name: na
};
uploadPromises.push(
db.collection("Parent").doc(uidstu).collection("Attendance").doc(f).set(attinfo).then(function () {
console.log(attinfo);
});
)
}
Related
At the moment, I manually create code then manually ask the user to set the trigger for the said function in order for the said user to receive a task and update task.
Heres an example of my coding:
User's Function
function Person1Variables () {
taskedPerson = assignedPerson.filter(x => x == "Person1 (assigned by Somebody)").length
taskReceiver = "Person1 (assigned by Somebody)"
taskReceived = "Person1 (Sent)"
functionCaller = "Person1 "
myTask = "My Tasks"
}
function taskSendPerson1() {
Person1Variables()
if (taskedPerson + 1 > 1){taskSending(taskTitle(myTask)); console.log("Snag")}
}
function updateTaskPerson1() {
Person1Variables()
taskComplete(taskTitle(myTask));
}
Task Creation and Update
function taskTitle(titleTasksList) {
if (typeof titleTasksList === 'undefined') { titleTasksList = 'default'; }
var rezultId = 0;
var response = Tasks.Tasklists.list();
var taskLists = response.items;
if (taskLists && taskLists.length > 0) {
for (var i = 0; i < taskLists.length; i++) {
var taskList = taskLists[i];
if (titleTasksList == 'default') {
rezultId = taskList.id; //return first item
break;
} else {
Logger.log('%s (%s)', taskList.title, taskList.id);
if (titleTasksList == taskList.title) {
rezultId = taskList.id;
break;
}
}
}
} else {
Logger.log('No task lists found.');
}
return rezultId;
}
function taskSending(taskListId) {
// Task details with title and notes for inserting new task
var currentResult = 1
var nextResult = 1
for (var resultsFound = 0; resultsFound < taskedPerson; resultsFound++){
console.log("pong")
var searchEngine = "Assigned Person"
var searchRange = sheet.getRange(nextResult,(lastColumn[0].indexOf(searchEngine) + 1),
sheet.getLastRow(), 1)
var searchRangeValues= searchRange.getValues()
currentResult = searchRangeValues.map(String).indexOf(taskReceiver) + nextResult
var resultTitle = responseNumber[currentResult -1]
var resultNote = typeSupport[currentResult - 1] + " = " + typeRequest[currentResult - 1]
let task = {
title: String(resultTitle),
notes: resultNote,
};
// Call insert method with taskDetails and taskListId to insert Task to specified tasklist.
console.log(task)
console.log(taskListId)
task = Tasks.Tasks.insert(task, taskListId);
// Print the Task ID of created task.
Logger.log('Task with ID "%s" was created.', task.id);
sheet.getRange(currentResult,2).setValue (taskReceived)
nextResult = currentResult + 1
console.log(nextResult + " " + "processed")
}
}
function newTask(taskListId) {
// Task details with title and notes for inserting new task
var allResults = [];
var allTitles = [];
for (var j = 0; j < itemResponses.length + 1; j++) {
var itemResponse = itemResponses[j];
for (var g = 0; g < 30; g++){ try {allResults [g] = String(itemResponses[g].getResponse()); allTitles [g] = itemResponses[g].getItem().getTitle();var lastResponse = g} catch(err) {}}
}
console.log("PING")
var refNumber = new Date().getFullYear().toString().substr(-2) + String(("00000000" + (formResponses.length))).substr(String(("00000000" + (formResponses.length))).length - 8);
let task = {
title: refNumber,
notes: allTitles [3] + " = " + allResults [3],
};
try {
// Call insert method with taskDetails and taskListId to insert Task to specified tasklist.
task = Tasks.Tasks.insert(task, taskListId);
// Print the Task ID of created task.
Logger.log('Task with ID "%s" was created.', task.id);
} catch (err) {
// TODO (developer) - Handle exception from Tasks.insert() of Task API
Logger.log('Failed with an error %s', err.message);
}
}
function taskComplete(taskListId) {
var optionalArgs = {
maxResults: 100,
showHidden: true
};
var tasks = Tasks.Tasks.list(taskListId, optionalArgs);
if (tasks.items) {
for (var i = 0; i < tasks.items.length; i++) {
var task = tasks.items[i];
for (var x = 0; x < responseNumber.length; x++){
if (responseNumber[x] == task.title){sheet.getRange(x + 1,lastColumn[0].indexOf("Status")+1).setValue(task.status); }
}
}
var dataFound = 0
//Tasks.Tasks.remove(taskListId,tasks.items[dataFound].id)
for (var x = 0; x < responseNumber.length; x++)
{try{if (tasks.items[dataFound].status == "completed" && (responseNumber.map(String).indexOf(String(tasks.items[dataFound].title))) > 1){Tasks.Tasks.remove(taskListId,tasks.items[dataFound].id); sheet.getRange(responseNumber.map(String).indexOf(String(tasks.items[dataFound].title)) + 1,lastColumn[0].indexOf("Assigned Person")+1).setValue(functionCaller)}; dataFound++} catch(err){}}
}
}
My plan was to create a button that can detect if that user has or has not created a function. If the user does not have dedicated function, then this button will create a function and assigned the trigger.
You don't need another function. The typical way to handle per user data is to store it in propertiesService and link it to triggerUid of the installed trigger.
Related:
Best way to create and manage someone's triggers (GAS)
Can the function called by ScriptApp.newTrigger identify the triggerID?
Is it possible to create a function on the fly and create triggers though? Maybe as a two step process through google-apps-script-api, but it's unnecessarily complicated for your case.
Performing an ajax call to a drinks api and I've nested a loop to pull the ingredients out and render them to the page. The nested loop consoles the ingredients correctly but when I use jquery to append the results to the page only the item in the last index is displayed. I know there are null values I was going to remove them with an if statement after I got them to show.
function displayDrinkData(drinkName) {
var queryURL = "https://thecocktaildb.com/api/json/v1/1/search.php?s=" + drinkName
$.ajax({
url: queryURL,
method: "GET"
}).then(function (response) {
console.log(response);
var results = response.drinks;
for (var i = 0; i < results.length; i++) {
console.log(results[i]);
var eachDrink = results[i];
var drinkDiv = $("<div>");
var drinkName = results[i].strDrink;
for (var k = 1; k < 16; k++) {
console.log(eachDrink['strIngredient' + k]);
var ingList = $("<ul>").text("Ingredients: " + eachDrink['strIngredient' + k])
}
var pOne = $("<p>").text("Drink name: " + drinkName);
var drinkInstructions = results[i].strInstructions;
var pTwo = $("<p>").text("Instructions: " + drinkInstructions);
var drinkImage = $("<img>");
drinkImage.attr("src", results[i].strDrinkThumb);
drinkDiv.append(pOne);
drinkDiv.append(ingList);
drinkDiv.append(pTwo);
drinkDiv.append(drinkImage);
$("#drinks-view").append(drinkDiv);
}
})
}
Because var ingList is inside loop, not appending, but creating a new one every time.
var ingList = $("<ul>");
for (var k = 1; k < 16; k++) {
console.log(eachDrink['strIngredient' + k]);
ingList.append($('<li>').text("Ingredients: " + eachDrink['strIngredient' + k]));
}
Declare variable outside loop, and append <li> for each element.
Hope someone can help - I'm new to js/jQuery so I'm hoping it's something really simple I'm missing here.
I'm trying to populate a dropdownlist with the xml result from below. The parseXML function works great and the result.push(valueid + "," + value) leaves me with the following:
1,Service
2,Breakdown
How do I get this into a dropdownlist please? Using the below, I get the error "Object doesn't support property or method 'split'"
Many thanks
leddy
function testFunction() {
var jobresults = "<resultset morerecords='0'> " +
"<result> " +
"<itt_jobtypeid>1</itt_jobtypeid> " +
"<itt_name>Service</itt_name> " +
"</result> " +
"<result> " +
"<itt_jobtypeid>2</itt_jobtypeid> " +
"<itt_name>Breakdown</itt_name> " +
"</result> " +
"</resultset> ";
var xml = parseXML(jobresults);
var jobid = xml.getElementsByTagName("itt_jobtypeid");
var jobname = xml.getElementsByTagName("itt_name");
var result = [];
for (var i = 0; i < jobid.length; i++) {
var valueid = jobid[i].childNodes[0].nodeValue;
var value = jobname[i].childNodes[0].nodeValue;
// add longitude value to "result" array
result.push(valueid + "," + value);
}
var jobtype = $("#ddlJobType");
$.each(result, function () {
var arr = result.split(',');
for (var i = 0; i < arr.length; i++) {
jobtype.append($("<option />").val(arr[0]).text(arr[1]));
}
});
}
function parseXML(text) {
if (window.DOMParser) {
parser = new DOMParser();
doc = parser.parseFromString(text, "text/xml");
}
else { // Internet Explorer
doc = new ActiveXObject("Microsoft.XMLDOM");
doc.async = "false";
doc.loadXML(text);
}
return doc;
}
It can be simpler and cleaner if you optimize data structure for result array. Push an object with value and label so that you can simply use attr method directly after:
for (var i = 0; i < jobid.length; i++) {
var valueid = jobid[i].childNodes[0].nodeValue;
var value = jobname[i].childNodes[0].nodeValue;
// add longitude value to "result" array
result.push({value: valueid, label: value});
}
var jobtype = $("#ddlJobType");
$.each(result, function (i, obj) {
$('<option>').attr(obj).appendTo(jobtype);
});
See https://api.jquery.com/jquery.each/. The callback function gets each jobtype as parameter to the function.
Try changing the code to:
$.each(result, function (idx, value) {
var arr = value.split(',');
for (var i = 0; i < arr.length; i++) {
jobtype.append($("<option />").val(arr[0]).text(arr[1]));
}
});
I have the following code:
PHP code:
$data = array();
$data[0]['name'] = "Kj";
$data[0]['age'] = 30;
$data[0]['country'] = "Italy";
$data[1]['name'] = "Dn";
$data[1]['age'] = 18;
$data[1]['country'] = "USA";
$data[2]['name'] = "Jo";
$data[2]['age'] = 22;
$data[2]['country'] = "Switzerland";
$data[3]['name'] = "Ro";
$data[3]['age'] = 34;
$data[3]['country'] = "UAE";
$data[4]['name'] = "Lc";
$data[4]['age'] = 13;
$data[4]['country'] = "UK";
echo json_encode($data);
Javascript code:
var jsonData = {};
$(document).ready(function () {
$.get('page.php', function (data) {
jsonData = jQuery.parseJSON(data);
});
});
for (var i = 0; i < jsonData.length; i++) {
$('ul').append("<li>" + jsonData[i].name + "</li>");
}
The problem is when put the for loop inside the $.get callback works fine like as the following.
$.get('page.php', function (data) {
jsonData = jQuery.parseJSON(data);
for (var i = 0; i < jsonData.length; i++) {
$('ul').append("<li>" + jsonData[i].name + "</li>");
}
});
But when put the for loop outside the $.get callback does not print out anything, but the data has been received successfully, but without print it.
Now, how can store the data that has been received in global variable to print it in anywhere ?
You should change your approach when you work with asynchronous operations (AJAX, timeouts). Something like this:
function GetData(callback) {
$.get('page.php', function (data) {
callback(jQuery.parseJSON(data));
});
}
GetData(function (data) {
for (var i = 0; i < data.length; i++) {
$('ul').append("<li>" + data[i].name + "</li>");
}
});
Your code already stores data in a global variable correctly.
Type jsonData into F12-javascript console and you will see it.
The question is rather about the control flow, what is the other event that will trigger usage of jsonData?
var select = [];
for (var i = 0; i < nameslots; i += 1) {
select[i] = this.value;
}
This is an extract of my code. I want to generate a list of variables (select1, select2, etc. depending on the length of nameslots in the for.
This doesn't seem to be working. How can I achieve this? If you require the full code I can post it.
EDIT: full code for this specific function.
//name and time slots
function gennametime() {
document.getElementById('slots').innerHTML = '';
var namelist = editnamebox.children, slotnameHtml = '', optionlist;
nameslots = document.getElementById('setpresentslots').value;
for (var f = 0; f < namelist.length; f += 1) {
slotnameHtml += '<option>'
+ namelist[f].children[0].value
+ '</option>';
};
var select = [];
for (var i = 0; i < nameslots; i += 1) {
var slotname = document.createElement('select'),
slottime = document.createElement('select'),
slotlist = document.createElement('li');
slotname.id = 'personname' + i;
slottime.id = 'persontime' + i;
slottime.className = 'persontime';
slotname.innerHTML = slotnameHtml;
slottime.innerHTML = '<optgroup><option value="1">00:01</option><option value="2">00:02</option><option value="3">00:03</option><option value="4">00:04</option><option value="5">00:05</option><option value="6">00:06</option><option value="7">00:07</option><option value="8">00:08</option><option value="9">00:09</option><option value="10">00:10</option><option value="15">00:15</option><option value="20">00:20</option><option value="25">00:25</option><option value="30">00:30</option><option value="35">00:35</option><option value="40">00:40</option><option value="45">00:45</option><option value="50">00:50</option><option value="55">00:55</option><option value="60">1:00</option><option value="75">1:15</option><option value="90">1:30</option><option value="105">1:45</option><option value="120">2:00</option></optgroup>';
slotlist.appendChild(slotname);
slotlist.appendChild(slottime);
document.getElementById('slots').appendChild(slotlist);
(function (slottime) {
slottime.addEventListener("change", function () {
select[i] = this.value;
});
})(slottime);
}
}
You'll have to close in the iterator as well in that IIFE
(function (slottime, j) {
slottime.addEventListener("change", function () {
select[j] = this.value;
});
})(slottime, i);
and it's only updated when the element actually change
The cool thing about JavaScript arrays is that you can add things to them after the fact.
var select = [];
for(var i = 0; i < nameSlots; i++) {
var newValue = this.value;
// Push appends the new value to the end of the array.
select.push(newValue);
}