Excel JavaScript API - problem with passing variables between multiple ".then()" - javascript

I'm trying to pass variables between a chain of ".then()" calls like so:
Excel.run(function (context) {
var currentWorksheet = context.workbook.worksheets.getActiveWorksheet();
var table = currentWorksheet.tables.getItem("NewTable");
table.rows.load('count')
return context.sync()
.then(function () {
var rowCount = table.rows.count;
console.log("There are " + rowCount + " rows in the table.");
var firstColumn = table.columns.getItem(1);
firstColumn.load("values");
return context.sync();
})
.then(function () {
var firstColumnValues = firstColumn.values;
var summary = {};
for (var i = 0; i < firstColumnValues.length; i++) {
var value = firstColumnValues[i][0];
if (summary[value]) {
summary[value]++;
} else {
summary[value] = 1;
}
}
console.log(summary);
})
.catch(function (error) {
console.log("Error: " + error);
if (error instanceof OfficeExtension.Error) {
console.log("Debug info: " + JSON.stringify(error.debugInfo));
}
});
})
.catch(function (error) {
console.log("Error: " + error);
if (error instanceof OfficeExtension.Error) {
console.log("Debug info: " + JSON.stringify(error.debugInfo));
}
});
But I get an error:
Error: ReferenceError: firstColumn is not defined
How can I pass variables in a chain of ".then()" calls?

i think you have your then in the the wrong place
the second then looks like it should be attached to the second sync not the first
Excel.run(function(context) {
var currentWorksheet = context.workbook.worksheets.getActiveWorksheet();
var table = currentWorksheet.tables.getItem("NewTable");
table.rows.load("count");
return context.sync().then(function() {
var rowCount = table.rows.count;
console.log("There are " + rowCount + " rows in the table.");
var firstColumn = table.columns.getItem(1);
firstColumn.load("values");
return context
.sync()
.then(function() {
var firstColumnValues = firstColumn.values;
var summary = {};
for (var i = 0; i < firstColumnValues.length; i++) {
var value = firstColumnValues[i][0];
if (summary[value]) {
summary[value]++;
} else {
summary[value] = 1;
}
}
console.log(summary);
})
.catch(function(error) {
console.log("Error: " + error);
if (error instanceof OfficeExtension.Error) {
console.log("Debug info: " + JSON.stringify(error.debugInfo));
}
});
});
}).catch(function(error) {
console.log("Error: " + error);
if (error instanceof OfficeExtension.Error) {
console.log("Debug info: " + JSON.stringify(error.debugInfo));
}
});
however i think you would be greatly helped by switching to the async/await syntax, also notice that the use of var for variable declaration is frowned on these days and is a hold over from the early days of javascript before it had the concept of scoping so can lead to some very odd side effects, you should use const and let (const for a variable that will be set once and read many or let for a variable that can be set and read many times)
Excel.run(async function(context) {
const currentWorksheet = context.workbook.worksheets.getActiveWorksheet();
const table = currentWorksheet.tables.getItem("NewTable");
table.rows.load("count");
await context.sync().catch(function(error) {
console.log("Error: " + error);
if (error instanceof OfficeExtension.Error) {
console.log("Debug info: " + JSON.stringify(error.debugInfo));
}
});
const rowCount = table.rows.count;
console.log("There are " + rowCount + " rows in the table.");
const firstColumn = table.columns.getItem(1);
firstColumn.load("values");
await context.sync().catch(function(error) {
console.log("Error: " + error);
if (error instanceof OfficeExtension.Error) {
console.log("Debug info: " + JSON.stringify(error.debugInfo));
}
});
const firstColumnValues = firstColumn.values;
const summary = {};
for (let i = 0; i < firstColumnValues.length; i++) {
const value = firstColumnValues[i][0];
if (summary[value]) {
summary[value]++;
} else {
summary[value] = 1;
}
}
console.log(summary);
});

Related

javascript If/Else Loop; async issue

Right now this section of code is passing along undefined to if(customerWaiting >0). It's an issue with async that I can't seem to figure out.
Based off the other threads I looked at, it's very basic and a newbie question, I just can't make it work.
I was seeing if you could find it for me
Edit 1:
the goal of the code is to see if there are customers in the firebase "customerWaiting" database, if there is then display the modal, if there is not then say there are no customers waiting
structure for database is
customerWaiting
-Automatically generated ID
-customer information
Here is the code
var customerWaiting;
var employeeWaiting;
var ref = firebase.database().ref();
$("#connectNextUser").click(function() {
{
ref.child("customerWaiting").on("value", function(snapshot) {
var customerWaiting = snapshot.numChildren();
console.log("There are " + snapshot.numChildren() + " customers waiting");
});
ref.child("employeeWaiting").on("value", function(snapshot) {
var employeeWaiting = snapshot.numChildren();
console.log("There are " + snapshot.numChildren() + " employees waiting");
});
}
if (customerWaiting > 0) {
$("#myModal").modal();
console.log("connect");
} else {
console.log("There are " + customerWaiting + " employees waiting");
console.log("no connect");
}
});
If I understand you correctly you want to do this:
var ref = firebase.database().ref();
$("#connectNextUser").click(function() {
// query how many customers are waiting
ref.child("customerWaiting").on("value", function(snapshot) {
// as soon as you have the result then get the numChildren
var customerWaiting = snapshot.numChildren();
console.log("There are " + snapshot.numChildren() + " customers waiting");
if (customerWaiting > 0) {
// show the modal if customerWaiting > 0
$("#myModal").modal();
console.log("connect");
} else {
console.log("There are " + customerWaiting + " employees waiting");
console.log("no connect");
}
});
});
If you want to use await/async then ref.child("customerWaiting").on("value", resolve) has to support Promises, or you need to convert it to one:
var ref = firebase.database().ref();
$("#connectNextUser").click(async function() {
var snapshot = await new Promise((resolve, reject) => {
ref.child("customerWaiting").on("value", resolve)
// you should also handle the error/reject case here.
})
var customerWaiting = snapshot.numChildren();
console.log("There are " + snapshot.numChildren() + " customers waiting");
if (customerWaiting > 0) {
$("#myModal").modal();
console.log("connect");
} else {
console.log("There are " + customerWaiting + " employees waiting");
console.log("no connect");
}
});

Filter data obtained through GitHub API

I created this function to obtain GitHub issues:
retrieveEnerpriseIssues: function(repoOrg, repoName, callback) {
let data = null;
// token auth
octokit.authenticate({
type: 'basic',
username: config.githubEnterprise.username,
password: config.githubEnterprise.token
});
async function paginate(method) {
let response = await method({
q: "repo:" + repoOrg + "/" + repoName + " is:issue",
per_page: 100
});
data = response.data.items;
var count = 0;
while (octokit.hasNextPage(response)) {
count++;
console.log(`request n°${count}`);
response = await octokit.getNextPage(response);
data = data.concat(response.data.items);
}
return data;
}
paginate(octokit.search.issues)
.then(data => {
callback(data);
})
.catch(error => {
console.log(error);
});
}
It is called in this function which takes the issues, filters out all of the unwanted keys into json format and puts it in my db.
extractToDb: function() {
let gitIssues = null;
for(var i = 0; i < config.githubEnterprise.orgs.length; i++) {
for(var j = 0; j < config.githubEnterprise.orgs[i].repos.length; j++) {
gitHubService.retrieveEnerpriseIssues(
config.githubEnterprise.orgs[i].owner,
config.githubEnterprise.orgs[i].repos[j].repoName,
function(data, err) {
if(err) {
console.log('err: ', err);
} else {
gitIssues = data;
}
gitIssues = JSON.stringify(gitIssues);
gitIssues = JSON.parse(gitIssues);
let issueFormatForDb = null;
for(var i = 0; i < gitIssues.length; i++) {
issueFormatForDb = gitIssues[i];
const body = '{' +
'"github_id": "' + issueFormatForDb.id + '",' +
'"issue_title": "' + issueFormatForDb.title + '",' +
'"issue_number": "' + issueFormatForDb.number + '",' +
'"issue_url": "' + issueFormatForDb.url + '",' +
'"issue_state": "' + issueFormatForDb.state + '"' +
'}';
console.log('Body: ', body);
getGitHubIssues.postToDb(body);
}
});
}
}
}
I'd like to take this a step further by filtering out any issues where the state is closed. How is this done and should it be handled in my retrieveEnerpriseIssues function or my extractToDb?
Possible solution
I tried this in my extractToDb function:
gitIssues = JSON.parse(gitIssues);
gitIssues = _.where(gitIssues, {state: "open"});
let issueFormatForDb = null;
Is it the best solution or is there a better way?
As #givehug stated:
Better use _.filter, or native filter method like
gitIssues = gitIssues.filter(i => i.state === 'open')
I think .where was deprecated in later versions of lodash github.com/lodash/lodash/wiki/Deprecations. Other than that its perfectly fine.
I just realsied I can filter the state in my paginate function with this:
let response = await method({
q: "repo:" + repoOrg + "/" + repoName + " is:issue" + " label:issue_label" + " state:open",
per_page: 100
});

Making sync call using callbacks/promises/other inside for loop in Javascript

I've a following situation:
I've an appendToFile() function that I wrote:
function appendToFile(text, file) {
(function (e) {
freeze();
FileUtils.readAsText(file)
.done(function (data) {
console.log("File data: " + data);
console.log("File text: " + e);
var text = data + e;
FileUtils.writeText(file, text, true)
.done(function () {
console.log("File saved. Text: " + text);
unfreeze();
//window.alert("File saved. Text: " + text);
})
.fail(function (err) {
console.error(err);
window.alert(err);
});
})
.fail(function (err) {
console.error(err);
});
})(text);
}
This function needs to append some text to a file. It is called from this function:
function processAttrs(clazz) {
//window.alert("Hello" + clazz.name + " " + clazz.length);
var file = FileSystem.getFileForPath("/Users/XXX/" + clazz.name + ".txt");
createFile(file, function () {
for (var i=0; i<clazz.attributes.length; i++) {
var attr = clazz.attributes[i];
var text = "private " + attr.type + " " + attr.name + "\n";
appendToFile(text, file);
}
});
}
The problem is that FileUtils.readAsText(file) is called asynchronously, so some lines that need to be written to a file get lost.
freeze() and unfreeze() are just empty functions where I thought about implementing something to stop and resume the code execution, but this mechanism doesn't seem to exist in Javascript.
I thought about using a callback as I did with createFile(file) function. The problem is that I don't know what to pass in as a callback function since the code execution is inside the for loop.
I could think of the solution without the for loop, and handling the flow manually using callbacks, but I don't like it. There have to be a more elegant solution
There is couple approaches to solve this problem. You can use async/await
so you can "block" your loop
function appendToFile(text, file) {
return new Promise((resolve, reject) => {
(function (e) {
//...
})(text);
});
}
async function processAttrs(clazz) {
//window.alert("Hello" + clazz.name + " " + clazz.length);
var file = FileSystem.getFileForPath("/Users/XXX/" + clazz.name + ".txt");
createFile(file, async function () {
for (var i=0; i<clazz.attributes.length; i++) {
var attr = clazz.attributes[i];
var text = "private " + attr.type + " " + attr.name + "\n";
const result = await appendToFile(text, file);
}
});
}
Or some kind of promise waterfall like shown here Is Node.js native Promise.all processing in parallel or sequentially?
Change your code and use the async/await syntax, like this.
async function appendToFile(text, file) {
try {
freeze();
var data = await FileUtils.readAsText(file)
console.log("File data: " + data);
console.log("File text: " + text);
var text = data + text;
await FileUtils.writeText(file, text, true)
console.log("File saved. Text: " + text);
unfreeze();
return;
} catch (e) {
console.log('Error', e)
}
}
function processAttrs(clazz) {
var file = FileSystem.getFileForPath("/Users/XXX/" + clazz.name + ".txt");
createFile(file, async function () {
for (var attr of clazz.attributes) {
var text = "private " + attr.type + " " + attr.name + "\n";
await appendToFile(text, file) //This will stop the loop until each file is completed
}
})
}

javascript league api combinedTick callback

async run(message, args) {
LolApi.init('censored', 'na');
LolApi.setRateLimit(10, 500);
var input = '';
args = args.toLowerCase();
LolApi.Summoner.getByName(args, function (err, summoner) {
if (!err) {
Name = summoner[args].name;
Name = Name.toLowerCase();
Id = summoner[Name].id;
Level = summoner[Name].summonerLevel;
input += "Name: " + summoner[Name].name + '\n' +
"Level: " + Level + "\n";
console.log(input);
//message.reply(input);
process.nextTick(LolApi.getLeagueData);
}
else {
message.reply('Error fam.');
}
});
setTimeout(function(){console.log('Waiting...')},2000);
LolApi.getLeagueData(Id,'NA', function (err, summoner) {
if (!err) {
Tier = summoner[Id][0].tier;
Division = summoner[Id][0].entries[0].division;
input += "Tier: " + Tier + '\n' +
"Division: " + Division;
message.reply(input);
} else {
console.log(Name);
console.log(err);
message.reply('Error Fam' + Id + "test");
}
});
}
When i run this code up get an error 404 running the second part. It gives me an saying combinedTickCallback but im not sure what this means because i am a noob. I use node.js if that helps with anything

For loop jumping to condition

I wonder if anyone can see a problem with this for loop.
I'm using parse, the for loop is inside a success callback for an object query.
When the loop runs, i jumps to response.length before it even finishes it's first loop
var e = [];
for (i = 0; i < response.length; i++) {
console.log("length: " + response.length);
var query = new Parse.Query(conEvent.Events);
query.get(response[i].get("eventID"), {
success: function (result) {
var object = result;
console.log("i: " + i)
e[i] = {
"name": object.get("name"),
"description": object.get("description"),
"dates": conEvent.datesToArray(object.get("dates")),
"ufDates": object.get("dates"),
"creator": object.get("creator"),
"id": object.id,
"invited": conEvent.getInvited(object.id)
}
console.log(e);
},
error: function (error) {
alert("Error: " + error.code + " " + error.message);
}
});
}
at the moment:
console.log("length: " + response.length); outputs "length: 2"
console.log("i: " + i) outputs "i: 2"
A more contextual view of the loop if anyone needs it:
this.getEvents = function () {
//get all the events user is invited to, list them and list the last....3? actions on the event
//display most likely date
//display number of users voted
//go green when date chosen
console.log("getEvents");
var Invite = Parse.Object.extend("Invite");
var query = new Parse.Query(Invite);
query.equalTo("username", Parse.User.current().get("username"));
query.find({
success: function (response) {
var e = [];
for (i = 0; i < response.length; i++) {
console.log("length: " + response.length);
var query = new Parse.Query(conEvent.Events);
query.get(response[i].get("eventID"), {
success: function (result) {
var object = result;
console.log("i: " + i)
e[i] = {
"name": object.get("name"),
"description": object.get("description"),
"dates": conEvent.datesToArray(object.get("dates")),
"ufDates": object.get("dates"),
"creator": object.get("creator"),
"id": object.id,
"invited": conEvent.getInvited(object.id)
}
console.log(e);
},
error: function (error) {
alert("Error: " + error.code + " " + error.message);
}
});
}
conEvent.myEvents = e;
console.log(e);
$scope.$apply();
}
});
}

Categories