How to know what to target when trying to parse and store JSON data from an API - javascript

So I'm relatively new to javascript, and followed this tutorial in API linking, but there's one thing I'm confused about.
Here's my code,
const app = document.getElementById('root');
const logo = document.createElement('img');
logo.src = 'logo.png';
const container = document.createElement('div');
container.setAttribute('class', 'container');
app.appendChild(logo);
app.appendChild(container);
var request = new XMLHttpRequest();
request.open('GET', 'https://ghibliapi.herokuapp.com/films', true);
request.onload = function () {
// Begin accessing JSON data here
var data = JSON.parse(this.response);
if (request.status >= 200 && request.status < 400) {
data.forEach(movie => {
const card = document.createElement('div');
card.setAttribute('class', 'card');
const h1 = document.createElement('h1');
h1.textContent = movie.title;
const p = document.createElement('p');
movie.description = movie.description.substring(0, 300);
p.textContent = `${movie.description}...`;
container.appendChild(card);
card.appendChild(h1);
card.appendChild(p);
});
} else {
const errorMessage = document.createElement('marquee');
errorMessage.textContent = `Gah, it's not working!`;
app.appendChild(errorMessage);
}
}
request.send();
and here's the link to the JSON data querying the API will give you
https://ghibliapi.herokuapp.com/films/
So the one thing I'm confused about is this line, and subsequent lines containing movie.something
data.forEach(movie => {
I don't understand why you would use "movie"
It's not defined in the code or the actual JSON, so how would you know that it's "movie.description" instead of something like "film.description"? I'm sure that if I can figure this out it's the key to working with other API's and referencing their data.
Can anyone help me?
(Also, here's the actual API documentation, https://ghibliapi.herokuapp.com/#)

movie is the argument for the arrow function. It can be called almost anything you want. data is an array, so forEach is available.
That line is like data.forEach(function(movie) { ... }.bind(this));

If what you are really looking for is the ability to inspect what property values are available on the movie variable, you can print the variable to the console and inspect it further from there.
console.log(movie)
And to open up the console, right click on your web application from your web browser and choose "dev tools" or "inspect" (it varies depending on what browser you use).

Related

Take selected text, send it over to Scryfall API, then take the link and put it in the selected text

I've been able to sort out the middle bit (the API seems to be called to just fine) along with the submenu displaying. Originally I thought that just the end part wasn't working but I'm now thinking that the selection part isn't either.
What am I doing wrong with the getSelection() and what do I need to do to insert a link into said selection? (to clarify, not to replace the text with a link, but to insert a link into the text)
//Open trigger to get menu
function onOpen(e) {
DocumentApp.getUi().createAddonMenu()
.addItem('Scry', 'serumVisions')
.addToUi();
}
//Installation trigger
function onInstall(e) {
onOpen(e);
}
//I'm not sure if I need to do this but in case; declare var elements first
var elements
// Get selected text (not working)
function getSelectedText() {
const selection = DocumentApp.getActiveDocument().getSelection();
if (selection) {
var elements = selection.getRangeElements();
Logger.log(elements);
} else {
var elements = "Lack of selection"
Logger.log("Lack of selection");
}
}
//Test run
// insert here
// Search Function
function searchFunction(nameTag) {
// API call + inserted Value
let URL = "https://api.scryfall.com/cards/named?exact=" + nameTag;
// Grabbing response
let response = UrlFetchApp.fetch(URL, {muteHttpExceptions: true});
let json = response.getContentText();
// Translation
let data = JSON.parse(json);
// Jackpot
let link = data.scryfall_uri;
// Output
Logger.log(link);
}
// Test run
searchFunction("Lightning Bolt");
//Let's hope this works how I think it works
function serumVisions() {
const hostText = getSelectedText();
const linkage = searchFunction(hostText);
// Unsure what class I'm supposed to use, this doesn't
const insertLink = DocumentApp.getActiveDocument().getSelection().newRichTextValue()
.setLinkUrl(linkage);
Logger.log(linkage);
}
For the first part, I tried the getSelection() and getCursor() examples from the Google documentation but they don't seem to work, they all just keep returning null.
For the inserting link bit, I read all those classes from the Spreadsheet section of the documentation, at the time I was unaware but now knowing, I haven't been able to find a version of the same task for Google Docs. Maybe it works but I'm writing it wrong as well, idk.
Modification points:
In your script, the functions of getSelectedText() and searchFunction(nameTag) return no values. I think that this might be the reason for your current issue of they all just keep returning null..
elements of var elements = selection.getRangeElements(); is not text data.
DocumentApp.getActiveDocument().getSelection() has no method of newRichTextValue().
In the case of searchFunction("Lightning Bolt");, when the script is run, this function is always run. Please be careful about this.
When these points are reflected in your script, how about the following modification?
Modified script:
Please remove searchFunction("Lightning Bolt");. And, in this case, var elements is not used. Please be careful about this.
From your script, I guessed that in your situation, you might have wanted to run serumVisions(). And also, I thought that you might have wanted to run the individual function. So, I modified your script as follows.
function getSelectedText() {
const selection = DocumentApp.getActiveDocument().getSelection();
var text = "";
if (selection) {
text = selection.getRangeElements()[0].getElement().asText().getText().trim();
Logger.log(text);
} else {
text = "Lack of selection"
Logger.log("Lack of selection");
}
return text;
}
function searchFunction(nameTag) {
let URL = "https://api.scryfall.com/cards/named?exact=" + encodeURIComponent(nameTag);
let response = UrlFetchApp.fetch(URL, { muteHttpExceptions: true });
let json = response.getContentText();
let data = JSON.parse(json);
let link = data.scryfall_uri;
Logger.log(link);
return link;
}
// Please run this function.
function serumVisions() {
const hostText = getSelectedText();
const linkage = searchFunction(hostText);
if (linkage) {
Logger.log(linkage);
DocumentApp.getActiveDocument().getSelection().getRangeElements()[0].getElement().asText().editAsText().setLinkUrl(linkage);
}
}
When you select the text of "Lightning Bolt" in the Google Document and run the function serumVisions(), the text of Lightning Bolt is retrieved, and the URL like https://scryfall.com/card/2x2/117/lightning-bolt?utm_source=api is retrieved. And, this link is set to the selected text of "Lightning Bolt".
Reference:
getSelection()

Chrome extension: Get the text of a web page from given url

First, I'm completly newbie making chrome extension, then in a part of the chrome extension I will receive differents urls and I want to store the text of the web page to process it later, resulting in an array of boolean variables, each associated with the given url. Schematically it would be something like this:
var result;
function process(text){
if something -> result.push(true);
if not -> result.push(false);
}
function main(){
for (i...){
url = given[i];
text = getHTMLText(url);
process(text);
}
final();//when the loop finish activate another function that use the global variable: result
}
I have problems with main function, first I have tried with synchronous XMLHttpRequest, although it works it's very slow and chrome always give the warning that synchronous XMLHttpRequest is deprecated.
for (var i = 0; i < urls.length; i++){
url = urls[i];
var req = new XMLHttpRequest();
req.open('GET', url, false);
req.send(null);
if (req.status == 200) detecting(req.responseText);
};
Other solution that I find was use fetch(url), but the code that I find I don't fully understand. Although the returned text works correctly but then the proccess function give different results on each page update.
for (var i = 0; i < urls.length; i++){
url = urls[i];
fetch(url).then(function(response) {
response.text().then(function(text) {
detecting(text);
});
});
};
Other problem, but this is because of the little knowledge I have of fetch(), was that I can't store the text out of the fetch(), every time I do console.log give undefined, this greatly complicates the processing of the text for me.
I have seen that maybe it can be done through extension APIs of chrome but I can't see how to do it.
The algorithm shown in your main pseudocode can be implemented easily by using async/await and Promise.all, without a for loop:
(async () => {
const results = await Promise.all(urls.map(processUrl));
console.log(results);
// further processing must be also inside this IIFE
})();
async function processUrl(url) {
try {
const text = await (await fetch(url)).text();
return {url, text, status: detecting(text)};
} catch (error) {
return {url, error};
}
}

Empty response from XHR

I have a table which gets populated by results after the user has filtered them. Each result gets the user to a detail page. I want the user to go back to the search results without resetting the table. The 'back to results' button on the detail page has this JavaScript:
document.getElementById('back').onclick = function(e){
const newpage = window.open("index.html?fromDetail=yes", "_self");
newpage.onload = advancedSearchFromDetail()
}
And this is the JavaScript function which is executed once the destination page is reached:
function advancedSearchFromDetail () {
event.preventDefault()
var table = $('#mainTable').DataTable()
table.clear()
// Get the parameters in the sessionStorage
const pe1id = sessionStorage.getItem('pe1id');
const pe2id = sessionStorage.getItem('pe2id');
const plid = sessionStorage.getItem('plid');
const dateFrom = sessionStorage.getItem('dateFrom');
const dateTo = sessionStorage.getItem('dateTo');
const includeUndated = sessionStorage.getItem('includeUndated');
const data = new FormData()
data.append('pe1id', pe1id)
data.append('pe2id', pe2id)
data.append('plid', plid)
data.append('dateFrom', dateFrom)
data.append('dateTo', dateTo)
data.append('includeUndated',includeUndated)
const oReq = new XMLHttpRequest();
oReq.open("post", 'modules/advanced_search.xq', true);
oReq.send(data);
oReq.onreadystatechange = function () {
if (oReq.readyState === XMLHttpRequest.DONE && oReq.status === 200) {
const result = JSON.parse(oReq.responseText);
[populate the table]
}
}
The curious thing is that this code works when it is launched from the main page. All the parameters are there and get correctly sent. The response nevertheless is empty, blank. If I double click on the XHR details in my browser's console in order to open the .xq file with the parameters I even get the JSON results in a new page! What am I overlooking? I can't understand why it's not working if the parameters are there, the XHR call is there, I get 200 status and all that.
Edit
If I launch the function in the browser's console it works. Does this have to do something with the fact that I call the function with newpage.onload = advancedSearchFromDetail() then? If yes, how can I work around it?
OK, as I suspected, the issue appears to be how I call the function, i.e. via the .onload instruction. Therefore I appended a parameter to the URL if the user is coming from a 'detail' page, and added this JavaScript in the main page:
var urlParams = new URLSearchParams(window.location.search);
if (urlParams.has('fromDetail')) {
advancedSearchFromDetail()}
And I've delete the .onload instruction in the previous JavaScript. I'm not sure this is the best solution, if anyone has a better one please do comment here.

Grab URL from element on page for Bitly URL shortening

I'm working in shopify - attempting to do this client-side
I have a URL being generated (based on what items are in the cart presently) that adds items to the cart based on their ID#.
I'm building this little thing for our sales team, so they can start an order for a customer and send that arrangement to someone through a URL - right now in shopify if you do it their way it will take the customer to the checkout window and they can't edit that order - This way we're just sending an arrangement in the cart that they can adjust before they actually check out.
So right now, that url gets very very long depending on how many items are in the cart, and I'd like to use bit.ly to create a short url based on that generated url - I have it now so that it can encode the URL so it won't have any strange characters in it - but looking at the bitly api documentation most of the examples seem generic and other cases on stack overflow seemed to be specific to their problem --
Perhaps it can't be done? Thanks for taking the time to read this, if anyone has any suggestions at all - or if you think I just missed a big chunk of something obvious please feel free to tell me so. I can provide code for what I have so far if that makes it easier to understand what I'm trying to do!
screen shot of what that page looks like
---- ADDING CODE BELOW ----
// get the cart
if (typeof Shopify === 'undefined') var Shopify = {};
Shopify.cart = {{ cart | json }};
Shopify.idsInCart = [];
Shopify.quanInCart = [];
//where we gonna put the url
var cartURL = document.getElementById('cart_url');
// for every item in Shopify Cart - push to idsInCart and print the IDs to the cart url
for (var i=0; i<Shopify.cart.items.length; i++) {
Shopify.idsInCart.push(Shopify.cart.items[i].id);
cartURL.innerHTML += 'id[]=' + Shopify.idsInCart[i] + '&';
}
// get the div with cartURLform as an id
var longUrlNode = document.getElementById('cartURLform'),
// grab the .textContent from that div
textContent = longUrlNode.textContent;
//
var uri = longUrlNode.textContent;
var res = encodeURI(uri);
// Copy to clipboard example
document.querySelector("#qlink").onclick = function() {
// Select the content
document.querySelector("#qlink").select();
// Copy to the clipboard
document.execCommand('copy');
};
(function(long_url,callback){
bi = new URL("https://api-ssl.bitly.com/v3/shorten?");
var params = [
"login=__obviously__",
"domain=bit.ly",
"apiKey=__obviously__",
"longUrl="+ encodeURIComponent(long_url)
]
bi.search = "?"+params.join('&')
var xhr = new XMLHttpRequest();
xhr.onreadystatechange=function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
var res = JSON.parse(xhr.responseText);
callback(res["data"]["url"]);
// document.getElementById("qlink").value = JSON.parse(xhr.responseText);
} else {
alert('There was a problem with the request.');
}
}
}
xhr.open("GET",bi.toString());
xhr.send(null)
})(res,function(a){
// prompt("hello", a);
document.getElementById("qlink").value = a;
});
--- Edited to add code

Iterate through appended json file

I have this code:
function heatMapRange() {
var script1 = document.createElement('script');
script1.src = 'allCoords.js';
document.getElementsByTagName('head')[0].appendChild(script1);
}
which appends the allCoords.js file above:
allCoords_callback({
"coordinates": [
[50.1729677, 12.6692243, 580000],
[50.001168, 14.4270033, 2895000],
[50.6988037, 13.9384015, 945000],
[50.1218161, 14.4824004, 409900],
[49.470061, 17.0937597, 1499000],
[49.8509959, 18.5593087, 380000]
]
});
What I want is to iterate through this data with something like this:
function allCoords_callback(results1) {
for (var i = 0; i < results1.coordinates.length; i++) {
alert(results1.coordinates[i]);
}
}
Is it possible?
You can iterate an array in javascript with Array.map().
In your example will be something like:
results1.coordinates.map(function(coordinate) { alert(coordinate); })
That's about iterating part.
Then, another topic is how do you get JSON you need to process. In the example given on Google Maps docs they do it using JSONP just because that is the way the real-time earthquake data works. Another method to fetch data are XMLHttpRequests (AKA as AJAX). This is a more common practice and I would recomend using it if possible.
In your case I would re-write your code to look something like this:
function heatMapRange(){
var request = new XMLHttpRequest();
request.open('GET', '/allCoords.js', true);
request.onload = function () {
if (request.status >= 200 && request.status < 400) {
// Success!
var data = JSON.parse(request.responseText);
// process the data in the response, like
// iterating through the list of coordinates
data.coordinates.map(function(coordinate) { alert(coordinate); })
} else {
// We reached our target server, but it returned an error
}
}
request.error = function () {
// There was a connection error of some sort
}
request.send();
}
Which fetch the data from the JSON file allCoords.json:
{
"coordinates": [
[50.1729677,12.6692243,580000],
[50.001168,14.4270033,2895000],
[50.6988037,13.9384015,945000],
[50.1218161,14.4824004,409900],
[49.470061,17.0937597,1499000],
[49.8509959,18.5593087,380000]
]
}
This way of fetching data from a server align more with the best practices used in the industry. This is just the straight forward example using vanillaJS XMLHttpRequest. There are tons of libraries that simplify this action. Even better there is Fetch API coming tackling the topic of fetching resources.
Well the code on the top works, problem was that I disabled the alerts in google chrome. So closing the tab and reopening page did the trick.

Categories