Office.js API for PowerPoint (Preview) - javascript

I am trying to use the new Office.js API for Powerpoint which is currently in preview. I am unable to get anything working with the PowerPoint.run() method call because it seems to behave differently that the ones in Excel and Word. Could anyone help me find a working way to call the SlideCollection.getCount() method referenced here?
https://learn.microsoft.com/en-us/javascript/api/powerpoint/powerpoint.slidecollection?view=powerpoint-js-preview
Sample code (assumed I needed to load items first before trying to get the count):
PowerPoint.run(function (context) {
var properties = context.presentation.slides.items;
context.load(properties);
return context.sync()
.then(function() {
console.log(properties);
})
.catch((error) => console.log(error));
})

Here is a call to slides.getCount() which should work
PowerPoint.run(async (context) => {
context.presentation.load("slides");
await context.sync();
var slides = context.presentation.slides;
var slideCount = slides.getCount();
await context.sync();
console.log("There are ", slideCount.value, " slides in this presentation");
}

PowerPoint.run(async function (context) {
context.presentation.load("slides");
await context.sync();
const slide = context.presentation.slides.getItemAt(0);
slide.load("id");//you just load any property from PPT object model and then sync
await context.sync();
console.log(slide.id);
});

Related

Cant work out out fetch api of met office to html page

Been tasked with displaying details from the met office data point api using javascript onto a html page and have only a brief knowledge of using the fetch api function.The met office uses users keys for their data point that needs inserted into the url in order to access the data. Im currently using the url that displays location information and would like to start with displaying the longitude and lattidide.
Ive wrote a html page and used an example I found of using fetch online but still no luck of displaying an data.
async function getLocations() {
let url = 'http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/json/sitelist?key=231f9773-2c4f-4afd-beee-6878c1c63f0a';
try {
let res = await fetch(url);
return await res.json();
} catch (error) {
console.log(error);
}
}
async function renderLocations() {
let locations = await getLocations();
let html = '';
locations.forEach(Location => {
let htmlSegment = `<div class="Location">
<h2>${Location.longitude} ${Location.latitude}</h2>
</div>`;
html += htmlSegment;
});
let container = document.querySelector('.container');
container.innerHTML = html;
}
renderLocations();
<div class="container"></div>
By trying out the API endpoint by myself and logging out the result of getLocations(), I see that the structure of the Object looks like:
{
Locations: {
Location: [
...data
]
}
}
So to fix your code, change from
locations.forEach(Location => {
to
locations.Locations.Location.forEach(Location => {

Read a page stylesheet and check a specific property with puppeteer

What I am trying to do is:
Load the page
Gain access to the contents of an external css named "mystyle.css"
Check if ".some_class" border has the value "2px"
I have tried
describe('CSS tests', () => {
it('.some_class border is 2px', async function () {
await page.goto(<homepageurl>);
const stylesheet = await page.evaluate(() => {
return document.querySelector("link[href*='mystyle.css']");
});
console.log(current_styles);
// rest of the code
});
});
I am getting an empty object {} as a result so I am lost and don't know how to carry on.

Multiple REST API calls in succession returns undefined

I'm trying to query some JIRA issues using a the jira-connector package.
I'm running into issues with the data returned not being defined until after everything else is executed in my code. I'm not sure if this is some issue with concurrency, but I can't for the life of me figure out where and how I'm messing up.
If inside the getJiraTimeEstimations function only call the getJiraTimeEstimate once it works just fine and I get access to the data to use further down in the program. It is when I'm trying to do it inside a map or foreach where I iterate over the Array.from(dataFromMaconomy.keys()) array that I seem to run into issues.
My understanding is that adding .then().catch() in the getJiraTimeEstimate function should be enough to stop it from continuing to run before all the calls are finished? Or am I misunderstanding how asynchronous calls work in Node and JS?
I've also tried converting it to an async getJiraTimeEstimations and adding an await infront of the search. But it doesn't seem to work either.
I am not populating the dataFromMaconomy array as I'm debugging. Which is what I was trying to do with the log statement. The log statement just prints undefined right now. But if I only call it with a single item from the rks array then it works fine.
function getJiraTimeEstimate(taskNumber, jiraClient) {
jiraClient.search.search({
jql: `id = ${taskNumber}`,
}).then((res) => res.issues[0].fields.timeoriginalestimate).catch((err) => err);
}
function getJiraTimeEstimations(dataFromMaconomy) {
const settings = JSON.parse(fs.readFileSync(path.join(__dirname, 'konfig.json'), 'utf8'));
const privateKeyData = fs.readFileSync(path.join(__dirname, settings.jira.consumerPrivateKeyFile), 'utf8');
const jira = new JiraClient({
host: settings.jira.server,
strictSSL: false, // Error: unable to verify the first certificate
rejectUnauthorized: false,
oauth: {
consumer_key: settings.jira.consumerKey,
private_key: privateKeyData,
token: settings.jira.accessToken,
token_secret: settings.jira.accessTokenSecret,
},
});
console.log('getting time estimations from Jira');
const dataFromMaconomyWithJira = [];
const rks = Array.from(dataFromMaconomy.keys());
rks.map((rk) => console.log(getJiraTimeEstimate(rk, jira)));
return dataFromMaconomyWithJira;
}
function generateData(){
const dataWithJira = getJiraTimeEstimations(convertedData);
// More functions where I use the data from getJiraTimeEstimations
// This gets run before all of the getJiraTimeEstimations have finished getting the data.
}
Giving your clarification in the comment, the getJiraTimeEstimate() function does not return anything. Try:
function getJiraTimeEstimate(taskNumber, jiraClient) {
return jiraClient.search.search({
jql: `id = ${taskNumber}`,
}).then((res) => res.issues[0].fields.timeoriginalestimate).catch((err) => err);
}
Also, you mentioned trying async / await but without luck. The async version of it would be:
async function getJiraTimeEstimate(taskNumber, jiraClient) {
try {
const res = await jiraClient.search.search({
jql: `id = ${taskNumber}`,
});
return res.issues[0].fields.timeoriginalestimate;
} catch (e) {
return e;
}
}

How can I update my dictionary with nested HTTP request?

I'm gonna try to explain this as clearly as I can, but it's very confusing to me so bear with me.
For this project, I'm using Node.js with the modules Axios and Cheerio.
I am trying to fetch HTML data from a webshop (similar to Amazon/eBay), and store the product information in a dictionary. I managed to store most things (title, price, image), but the product description is on a different page. To do a request to this page, I'm using the URL I got from the first request, so they are nested.
This first part is done with the following request:
let request = axios.get(url)
.then(res => {
// This gets the HTML for every product
getProducts(res.data);
console.log("Got products in HTML");
})
.then(res => {
// This parses the product HTML into a dictionary of product items
parseProducts(productsHTML);
console.log("Generated dictionary with all the products");
})
.then(res => {
// This loops through the products to fetch and add the description
updateProducts(products);
})
.catch(e => {
console.log(e);
})
I'll also provide the way I'm creating product objects, as it might clarify the function where I think the problem occurs.
function parseProducts(html) {
for (item in productsHTML) {
// Store the data from the first request
const $ = cheerio.load(productsHTML[item]);
let product = {};
let mpUrl = $("a").attr("href");
product["title"] = $("a").attr("title");
product["mpUrl"] = mpUrl;
product["imgUrl"] = $("img").attr("src");
let priceText = $("span.subtext").text().split("\xa0")[1].replace(",", ".");
product["price"] = parseFloat(priceText);
products.push(product);
}
}
The problem resides in the updateProducts function. If I console.log the dictionary afterwards, the description is not added. I think this is because the console will log before the description gets added. This is the update function:
function updateProducts(prodDict) {
for (i in prodDict) {
let request2 = axios.get(prodDict[i]["mpUrl"])
.then(res => {
const $ = cheerio.load(res.data);
description = $("div.description p").text();
prodDict[i]["descr"] = description;
// If I console.log the product here, the description is included
})
}
// If I console.log the product here, the description is NOT included
}
I don't know what to try anymore, I guess it can be solved with something like async/await or putting timeouts on the code. Can someone please help me with updating the products properly, and adding the product descriptions? Thank you SO much in advance.
To refactor this with async/await one would do:
async function fetchAndUpdateProducts() => {
try {
const response = await axios.get(url);
getProducts(response.data);
console.log("Got products in HTML");
parseProducts(productsHTML);
console.log("Generated dictionary with all the products");
await updateProducts(products);
} catch(e) {
console.log(e);
}
}
fetchAndUpdateProducts().then(() => console.log('Done'));
and
async function updateProducts(prodDict) {
for (i in prodDict) {
const response = await axios.get(prodDict[i]["mpUrl"]);
const $ = cheerio.load(response.data);
description = $("div.description p").text();
prodDict[i]["descr"] = description;
}
}
This will not proceed to conclude the call to fetchAndUpdateProducts unless the promise returned by updateProducts has been resolved.

Excel JS API: write, calculate and load values from cells with custom functions

The intention is to write the formula (custom function) to the cell, calculate it, load values and retrieve them in a single function.
function myFunc() {
Excel.run(function (ctx) {
var fExcel = '=SUM(1,2)';
var fCustom = '=custFunc()';
var rng = ctx.workbook.worksheets.getActiveWorksheet().getRange('A1');
//rng.formulas = [[fExcel]]; // works OK
rng.formulas = [[fCustom]]; // values are #GETTING_DATA
// try different calc calls
rng.load("values");
return ctx.sync().then(function () {
console.log(rng.values);
});
});
}
For built-in Excel functions, everything works as expected and console logs a value 3 after ctx.sync(). With custom functions (that send a request to the external server to compute the result) the values are '#GETTING_DATA'. I've tried all the following things before rng.load("values"); to trigger the calculation, but nothing have worked so far:
rng.calculate();
var s = ctx.workbook.worksheets.getActiveWorksheet();
s.calculate(true);
ctx.workbook.application.calculate('Full');
Is there a way to trigger the calculation of custom functions and make sure that the values are available after the ctx.sync()?
Interesting scenario!
Today, this may be feasible leveraging the onCalculate event but the caveat is you it will fire 2x when you're custom function is calculating.
This is because your custom function first will show a #GETTING_DATA, while it calculates in the background.
This gives the user back control while your functions are still evaluating, allowing the application to be more responsive. This behavior differs from VBA or XLL UDFs that could hang Excel.
When Excel is done with calculation, it will fire the calculation event again. This is when the results come back in by resolving the promise.
This Script lab gist should give you an indication of how it works:
/*This gist works in combination with any registered Excel JS Custom function*/
$("#set-formulas").click(() => tryCatch(setFormulas));
var rangeToCheck;
async function setFormulas() {
await Excel.run(async (context) => {
//register for event
context.workbook.worksheets.getActiveWorksheet().onCalculated.add(handleCalculate);
//write to grid
const sheet = context.workbook.worksheets.getItem("Sheet1");
rangeToCheck = "A1";
const range = sheet.getRange(rangeToCheck);
range.formulas = [['=CONTOSO.CONTAINS(A1, Days)']];
range.format.autofitColumns();
await context.sync();
});
}
async function handleCalculate(event) {
//read cell
console.log("calc ended - begin");
console.log("Change type of event: " + event.changeType);
console.log("Address of event: " + event.address);
console.log("Source of event: " + event.source);
//Read A1 and log it back to the console
await Excel.run(async (context) => {
//write to grid
const sheet = context.workbook.worksheets.getItem("Sheet1");
const range = sheet.getRange(rangeToCheck);
range.load("values");
await context.sync();
if (range.values.toString() != "GETTING_DATA") {
console.log("Success: " + range.values);
}
});
}
/** Default helper for invoking an action and handling errors. */
async function tryCatch(callback) {
try {
await callback();
} catch (error) {
OfficeHelpers.UI.notify(error);
OfficeHelpers.Utilities.log(error);
}
}

Categories