My code basically fetches API data, creates HTML elements for each and update the innerHTML elements with API data.
How can I possibly refresh the data from API and update it without creating another HTML elements?
This is my actual code:
let divCrypto = document.getElementById("divCrypto");
let temp, p1, p2, p3, imgz;
let data = [];
const getData = async () => {
for (i = 0; i < 2; i++){
coinName = await fetch("https://api.coinlore.net/api/tickers/")
.then((res) => res.json());
data.push(coinName.data[i]);
p1 = document.createElement("p");
p2 = document.createElement("p");
p3 = document.createElement("p");
p1.innerHTML = "Coin:" + " " + data[i].name;
p2.innerHTML = "Coin:" + " " + data[i].price_usd;
p3.innerHTML = data[i].percent_change_7d + "%";
divCrypto.appendChild(p1);
divCrypto.appendChild(p2);
divCrypto.appendChild(p3);
}
console.log(data);
};
getData();
console.log(data);
I tried with : setInterval (getData, 1000); but after each second, it recreates the HTML elements again and again.
I also tried to make 2 different functions but I don't know how to access the data outside the getData() function.
If I console log it outside, after the function is called and the data is updated, I get [] and I cannot understand why.
You can add to the html object the coins you want to display and the function will generate the html for them if it doesn't exist or just update the values if they do exists
let divCrypto = document.getElementById("divCrypto");
let html = { BTC: 1, ETH: 1, ADA: 1 };
let data = [];
let temp, p1, p2, p3, container;
const getData = async () => {
coinName = await fetch("https://api.coinlore.net/api/tickers/").then((res) =>
res.json()
);
for (i = 0; i < 3; i++) {
data.push(coinName.data[i]);
container = document.getElementById(data[i].symbol);
if (html[data[i].symbol] && !container) {
// if this is the first time we read this coin we generate the html
container = document.createElement("div");
container.id = data[i].symbol;
p1 = document.createElement("p");
p2 = document.createElement("p");
p3 = document.createElement("p");
container.appendChild(p1);
container.appendChild(p2);
container.appendChild(p3);
divCrypto.appendChild(container);
}
if (html[data[i].symbol]) {
container.children[0].innerHTML = "Coin:" + " " + data[i].name;
container.children[1].innerHTML = "Coin:" + " " + data[i].price_usd;
container.children[2].innerHTML = data[i].percent_change_7d + "%";
}
}
console.log(data);
};
getData();
setInterval(getData, 1000);
//console.log(data);
<div id="divCrypto"></div>
Related
I have an array which I populate like so
var list = [];
featureLayer.queryFeatures(querySnTR)
.then((result) => {
result.attachmentInfos.forEach((x) => {
list.push(uriString + "/" + x.id);
});
});
console.log("list", list);
I print out the list with console.log and it returns values inside.
Afterwards I do a foreach to go through all the elements inside and create a div for each of them. The thing is, it doesn't even go in the foreach function.
list.forEach((x) => {
console.log("CL", list);
console.log("x element", x);
var image = document.createElement("img");
image.src = x;
image.className = "queryImg";
document.getElementById("queryResults").appendChild(image);
});
It doesn't print out CL or x element for that matter.
Any ideas as to why?
The whole original code, for reference
startup: function () {
var _that = this;
_this = _that;
this.map.on("click", function (e) {
_this.map.graphics.clear();
identifyTask = new IdentifyTask("https://server/arcgis/rest/services/MUNICIPALITY_BUNDLE/ZK_KATASTAR_NA_ZELENILO/MapServer");
identifyParams = new IdentifyParameters();
identifyParams.tolerance = 10;
identifyParams.returnGeometry = true;
identifyParams.layerIds = [1];
identifyParams.layerOption = IdentifyParameters.LAYER_OPTION_ALL;
identifyParams.width = _this.map.width;
identifyParams.height = _this.map.height;
identifyParams.spatialReference = _this.map.spatialReference;
identifyParams.geometry = e.mapPoint;
identifyParams.mapExtent = _this.map.extent;
identifyTask.execute(identifyParams).then(function (data) {
objId = data[0].feature.attributes.objectid;
const querySnTR = {
where: "1 = 1",
outFields: ["*"]
};
var uriString = "https://server/arcgis/rest/services/MUNICIPALITY_BUNDLE/ZK_KATASTAR_NA_ZELENILO/MapServer/101/" + objId + "/attachments";
var featureLayer = new esri.layers.FeatureLayer(uriString);
featureLayer.queryFeatures(querySnTR)
.then((result) => {
result.attachmentInfos.forEach((x) => {
list.push(uriString + "/" + x.id);
});
});
const myFunction = async () => {
const { attachmentInfos } = await featureLayer.queryFeatures(querySnTR);
const list = attachmentInfos.map(({ id }) => `${uriString}/${id}`);
console.log("list", list);
list.forEach((x) => {
var image = document.createElement("img");
image.src = x;
image.className = "queryImg";
document.getElementById("queryResults").appendChild(image);
});
};
});
});
}
That's a trick on how the console works.
When you are executing the log the list is empty (100% sure) because you are populating it asynchronously. But the console has the reference to it and it will print it afterwards.
That's why your list is empty. You need to handle asynchrony here. You could work with an async/await approach or using promises, that will depend on the rest of your code, this is an example of how to do it with an async function (and rewritted it to modern javascript):
const myFunction = async () => {
const {attachmentInfos} = await featureLayer.queryFeatures(querySnTR);
const list = attachmentInfos.map(({id}) => `${uriString}/${id}`);
console.log("list", list);
list.forEach((x) => {
// put your code here
});
};
Edited:
Now that you share all your code you can simply do:
featureLayer.queryFeatures(querySnTR)
.then((result) => {
result.attachmentInfos.forEach((attachmentInfo) => {
var x = uriString + "/" + attachmentInfo.id
var image = document.createElement("img");
image.src = x;
image.className = "queryImg";
document.getElementById("queryResults").appendChild(image);
});
});
I would recommend you also to give vars meaningful names, not x but attachmentInfo, etc...
I have this JS script, who call an Airtable API
var type = "Coupons"
var api_key = "?api_key=123456"
var maxRecords = "&maxRecords=10"
var filterByFormula = "&filterByFormula=%7Bvip_ou_50%7D%3D%2250%222"
var offset = "";
var url = "https://api.airtable.com/v0/app123456/" + type + api_key + maxRecords + "&offset=" + offset + "&sort%5B0%5D%5Bfield%5D=coupons_id";
async function catchJson() {
const response = await fetch(url);
const data = await response.json();....
as you see next, I created a function to change the value of the offset
var next_page = function () {
console.log(offset);
offset = data.offset;
console.log(offset);
}
page_suivante.onclick = next_page;
so I want to create a next page bouton Onclick that change the offset value
How can I do that !
Thanks for your help !
This is my result page for now : https://web.pinkmarket.co
Edit : this is my full JS with correction
var type = "Coupons"
var api_key = "?api_key=1234"
var maxRecords = "&maxRecords=10"
var filterByFormula = "&filterByFormula=%7Bvip_ou_50%7D%3D%2250%222"
var offset = "&offset"
var url = "https://api.airtable.com/v0/app1234/" + type + api_key + offset + "&sort%5B0%5D%5Bfield%5D=coupons_id";
const app = document.getElementById('root')
const card = document.createElement('div');
card.setAttribute('class', 'rightcontainer w-container')
app.appendChild(card)
async function catchJson() {
const response = await fetch(url);
const data = await response.json();
if (response.status >= 200 && response.status < 400) {
data.records.forEach(records => {
const records_length = document.getElementById('number')
records_length.innerHTML = 'Liste de coupons <br> <span class="text-span-2">Ouvrir la Map</span>'
const property_card = document.createElement('a')
property_card.setAttribute('class', 'property-card left w-inline-block w-clearfix')
property_card.style.background = "-webkit-gradient(linear, left top, left bottom, color-stop(29%, hsla(0, 0%, 100%, 0)), color-stop(68%, rgba(0, 0, 0, 0.5))), url('" + records.fields.image_url + "');";
property_card.style.background = "linear - gradient(180deg, hsla(0, 0 %, 100 %, 0) 29 %, rgba(0, 0, 0, 0.5) 68 %), url('" + records.fields.image_url + "');"
const image_quantity_div = document.createElement('div')
image_quantity_div.setAttribute('class', 'image-quantity-div')
const price_text = document.createElement('h1')
price_text.setAttribute('class', 'price-text')
price_text.innerText = records.fields.titre
const div_lower_info = document.createElement('div')
div_lower_info.setAttribute('class', 'div-lower-info w-clearfix')
const info_text = document.createElement('div')
info_text.setAttribute('class', 'info-text')
info_text.innerText = records.fields.compagny_name + ' - ' + records.fields.description_sub.substring(0, 100) + '...'
const view_button = document.createElement('div')
view_button.setAttribute('class', 'view-button')
view_button.textContent = 'Plus'
root.appendChild(card);
card.appendChild(property_card);
property_card.appendChild(image_quantity_div);
property_card.appendChild(price_text);
div_lower_info.appendChild(info_text);
div_lower_info.appendChild(view_button);
property_card.appendChild(div_lower_info);
})
const offset_page = document.createElement('a');
offset_page.setAttribute('class', 'button-2 left-aligned w-button')
offset_page.setAttribute('id', 'next')
offset_page.setAttribute('href', data.offset)
offset_page.innerHTML = "Page Suivante"
card.appendChild(offset_page);
});
}
else {
const errorMessage = document.createElement('a')
errorMessage.textContent = `Bah, ça ne marche pas !`
app.appendChild(errorMessage)
}
}
document.addEventListener('DOMContentLoaded', function () {
catchJson()
});
<div class="premium-properties-div" id="root">
</div>
If I got your question right you want to run the next_page() function on button click. If so this code does that:
EDIT: As discussed in the comments the below code will update your offset variable without restarting.
var type = "Coupons"
var api_key = "?api_key=123456"
var maxRecords = "&maxRecords=10"
var filterByFormula = "&filterByFormula=%7Bvip_ou_50%7D%3D%2250%222"
//I assume you set the ofset to "" because as discussed in the comments you get the offset value after calling the api the first time
var offset = "";
var url = "https://api.airtable.com/v0/app123456/" + type + api_key + maxRecords + "&offset=" + offset + "&sort%5B0%5D%5Bfield%5D=coupons_id";
var dynamicOffset = []
//your finalData
var finalData = []
//on click of button the api starts running.
document.getElementById("nextPageBtn").addEventListener('click', function() {
getNewOffset()
});
function getNewOffset() {
async function catchJson() {
const response = await fetch(url);
const data = await response.json();
//as disscussed in the comments ```data``` is the offset value you get back so now insert the offset value to the URL and run it again and again untill no ofset value is returned
//so first check if data is not empty then if not lets push every new offset data returned to an array called ```dynamic Offset``` but also empty the array before pushing then call the second fetch method.
if (data != "" && data != null) {
dynamicOffset = []
dynamicOffset.push(data)
secondFetch()
} else {
console.log('not more new offset')
//Log your final data
console.log(finalData)
}
}
}
function secondFetch() {
//insert the new Offset Value
const modifiedURL = "https://api.airtable.com/v0/app123456/" + type + api_key + maxRecords + "&offset=" + dynamicOffset[0] + "&sort%5B0%5D%5Bfield%5D=coupons_id";
//call fetch
async function catchJson() {
const response = await fetch(modifiedURL);
const data = await response.json();
//we didn't discuss how you want your final data to be saved but assuming your data are strings lets push them all to ```finalDataArray``` but you can save them in your desierd way. Note we are not clearing array here becuase we are appending not writing.
//just a precaution statment
if (data != "" && data != null) {
finalData.push(data)
//lets setTimeout of 1 second to avoid memory overload
setTimeout(() => {
//call getNewOffset() again
getNewOffset()
}, 1000)
}
}
}
<button id="nextPageBtn">Next Page</button>
i am currently trying to edit a pdf with hummus.js to replace certain placeholder characters in the pdf with others.
This works perfectly fine for almost every page, but for certain pages I get the following error:
TypeError:
pageObject.getDictionary(...).toJSObject(...).Contents.getObjectID is
not a function for:
const textObjectID = pageObject.getDictionary().toJSObject().Contents.getObjectID();
Whenever that error happens and it doesnt work,
pageObject.getDictionary().toJSObject().Contents returns a PDFArray {}, while, when it works, it returns an PDFIndirectObjectReference {}
Does anybody know how I could solve this issue or any other way to edit a pdf that way (replacing certain placeholder characters with others)
UPDATE 1: I can now differentiate between IndirectObjectReferences and arrays containing IndirectObjectReferences, but for some reason it removes all text but keeps the images from pdf pages which i access through these arrays, the rest of the pdf pages still work perfectly fine
async function replacetext(filePath, callback) {
var pageCount = 0;
const modPdfWriter = hummus.createWriterToModify(filePath+'.pdf', { modifiedFilePath: `${filePath}-modified.pdf`, compress: false })
const numPages = modPdfWriter.createPDFCopyingContextForModifiedFile().getSourceDocumentParser().getPagesCount()
var log="";
for (let page = 0; page < numPages; page++) {
const copyingContext = modPdfWriter.createPDFCopyingContextForModifiedFile()
const objectsContext = modPdfWriter.getObjectsContext()
const pageObject = copyingContext.getSourceDocumentParser().parsePage(page)
pageCount = pageCount + 1;
try
{
var replaceTextRight = " " + pageCount.toString();
if(pageCount > 9 && pageCount < 100)
{
replaceTextRight = " " + pageCount.toString();
}
else if(pageCount > 99)
{
replaceTextRight = " " + pageCount.toString();
}
const textStream = copyingContext.getSourceDocumentParser().queryDictionaryObject(pageObject.getDictionary(), 'Contents')
console.log(textStream);
if(textStream.toString() == 'Array')
{
let data = []
streamArray = textStream.toJSArray();
for(var i = 0; i<streamArray.length; i++)
{
var streamo = copyingContext.getSourceDocumentParser().queryArrayObject(textStream, i);
const readStream = copyingContext.getSourceDocumentParser().startReadingFromStream(streamo)
while (readStream.notEnded()) {
const readData = readStream.read(10000)
data = data.concat(readData)
}
var redactedPdfPageAsString = new Buffer.from(data).toString();
var replacedBuffer = replace(redactedPdfPageAsString, "12345", pageCount.toString());
log = log+" \n Replaced " +page +" with " + pageCount.toString();
var replacedBuffer = replace(replacedBuffer, "67890", replaceTextRight);
log = log+" \n Replaced " +page +" with " + replaceTextRight;
var textObjectID = streamArray[i].getObjectID();
objectsContext.startModifiedIndirectObject(textObjectID)
var stream = objectsContext.startUnfilteredPDFStream();
stream.getWriteStream().write(strToByteArray(replacedBuffer));
objectsContext.endPDFStream(stream);
objectsContext.endIndirectObject();
}
}
else
{
let data = []
const readStream = copyingContext.getSourceDocumentParser().startReadingFromStream(textStream)
while (readStream.notEnded()) {
const readData = readStream.read(10000)
data = data.concat(readData)
}
var redactedPdfPageAsString = new Buffer.from(data).toString();
var replacedBuffer = replace(redactedPdfPageAsString, "12345", pageCount.toString());
log = log+" \n Replaced " +page +" with " + pageCount.toString();
var replacedBuffer = replace(replacedBuffer, "67890", replaceTextRight);
log = log+" \n Replaced " +page +" with " + replaceTextRight;
const textObjectID = pageObject.getDictionary().toJSObject().Contents.getObjectID();
var content = pageObject.getDictionary().toJSObject().Contents;
objectsContext.startModifiedIndirectObject(textObjectID)
const stream = objectsContext.startUnfilteredPDFStream();
stream.getWriteStream().write(strToByteArray(replacedBuffer));
objectsContext.endPDFStream(stream);
objectsContext.endIndirectObject();
}
}
catch(e){
console.log(e);
}
}
fs.writeFile('C:\\Users\\Administrator\\Downloads\\PDFModifyDebugging\\PDFWRITELOG.txt', log, function (err) {
if (err) return console.log(err);
console.log('written in file');
});
modPdfWriter.end()
hummus.recrypt(`${filePath}-modified.pdf`, filePath)
callback();
}
How can I get the data from an api request from the then() method, so I can process the data outside
of the function. Can I store the data in a state object for example and how to do that.
// openweathermap async await api request
async function getData(){
try{
const url = `http://api.openweathermap.org/data/2.5/forecast?
q=${city}&units=metric&appid=${key}`;
const data = await axios(url)
console.log(data)
return data;
}catch(error){
temperature.insertAdjacentHTML('afterend', '<div id="error">Oooops
something went wrong!</div>');
}
}
getData().then( data => {
const temp = data.data.list[0].main.temp;
temperature.textContent = temp.toFixed(1) + ' \xB0' + "C ";
const temp2 = data.data.list[1].main.temp;
temperature2.textContent = temp2.toFixed(1) + ' \xB0' + "C ";
const forecast = data.data.list[0].weather[0].description;
foreCast.textContent = forecast.toLowerCase();
const forecast2 = data.data.list[1].weather[0].description;
foreCast2.textContent = forecast2.toLowerCase();
const icon = data.data.list[0].weather[0].icon
weatherIcon.insertAdjacentHTML('afterbegin', `<img
src="http://openweathermap.org/img/w/${icon}.png">`)
const icon2 = data.data.list[1].weather[0].icon
weatherIcon2.insertAdjacentHTML('afterbegin', `<img
src="http://openweathermap.org/img/w/${icon2}.png">`)
day.textContent = newTime;
day2.textContent = newTime2;
})
Should axios(url) be axios.get(url)?
Then you can handle the data inside the callback function:
getData().then(data => console.log(data))
Get data is already an async function which means it returns a Promise. Just assign variable data by calling getData function. This should be done in an async function.
(async () => {
const data = await getData();
const temp = data.data.list[0].main.temp;
temperature.textContent = temp.toFixed(1) + ' \xB0' + "C ";
const temp2 = data.data.list[1].main.temp;
temperature2.textContent = temp2.toFixed(1) + ' \xB0' + "C ";
const forecast = data.data.list[0].weather[0].description;
foreCast.textContent = forecast.toLowerCase();
const forecast2 = data.data.list[1].weather[0].description;
foreCast2.textContent = forecast2.toLowerCase();
const icon = data.data.list[0].weather[0].icon
weatherIcon.insertAdjacentHTML('afterbegin', `<img src="http://openweathermap.org/img/w/${icon}.png">`)
const icon2 = data.data.list[1].weather[0].icon
weatherIcon2.insertAdjacentHTML('afterbegin', `<img src="http://openweathermap.org/img/w/${icon2}.png">`)
day.textContent = newTime;
day2.textContent = newTime2;
})();
Found a solution: Create a class with the getData() method, create a function to control the data and store it in the state object.
// Create class
class Weather {
constructor(){
}
async getData(){
try{
const url = `http://api.openweathermap.org/data/2.5/forecast?
q=${city}&units=metric&appid=${key}`;
const data = await axios(url)
this.data = data
}catch(error){
temperature.insertAdjacentHTML('afterend', '<div id="error">Oooops something
went wrong!</div>');
}
}
}
// Create state object, declare function to get data and store data in state object
const state = {}
const controlData = async () => {
state.data = new Weather()
await state.data.getData()
const temp = state.data.data.data.list[0].main.temp;
temperature.textContent = temp.toFixed(1) + ' \xB0' + "C ";
const temp2 = state.data.data.data.list[1].main.temp;
temperature2.textContent = temp2.toFixed(1) + ' \xB0' + "C ";
const forecast = state.data.data.data.list[0].weather[0].description;
foreCast.textContent = forecast.toLowerCase();
const forecast2 = state.data.data.data.list[1].weather[0].description;
foreCast2.textContent = forecast2.toLowerCase();
const icon = state.data.data.data.list[0].weather[0].icon
weatherIcon.insertAdjacentHTML('afterbegin', `<img
src="http://openweathermap.org/img/w/${icon}.png">`)
const icon2 = state.data.data.data.list[1].weather[0].icon
weatherIcon2.insertAdjacentHTML('afterbegin', `<img
src="http://openweathermap.org/img/w/${icon2}.png">`)
day.textContent = newTime;
day2.textContent = newTime2;
let sRise = convertTime(state.data.data.data.city.sunrise);
let sSet = convertTime(state.data.data.data.city.sunset);
sunRise.textContent = `Sunrise ${sRise}`;
sunSet.textContent = `Sunset ${sSet}`;
}
controlData()
so im getting my data from Darksky api, i have elements generated with loops, and i update the text content of those via loop of the api data array. whenever i search, everthing else static changes values, not the one inside the loop
function search(ele) {
if(event.key === 'Enter') {
var url3 = 'https://geocode.xyz/' + ele.value +'?json=1' //this is where i convert the long,lat to city name
fetch(url3)
.then(z => z.json())
.then(z => {
locres = (z.latt+','+z.longt)
render()
renderLoop()
})
}
}
function renderLoop(){
var proxyUrl = 'https://cors-anywhere.herokuapp.com/';
var url1 = 'https://api.darksky.net/forecast/c34e122a56ae30a3090687878bce72c3/' + locres + '?units=auto' //i have to use proxy because of CORS
fetch(proxyUrl + url1)
.then(x => x.json())
.then(x => {
var skycons = new Skycons({"color": "white"});
skycons.set("icon0", Skycons = x.currently.icon);
skycons.play();
console.log(x.daily.data)
for(i=0;i<8;i++){
console.log(x.daily.data[i].time)
console.log(x.daily.data[i].summary)
const divs = document.createElement('div')
divs.className = ('week-day-container')
const divsholdr = document.querySelector('.week-stage')
const canv = document.createElement('canvas')
canv.id = ('icons'+(i+1))
canv.height = 100
canv.width = 70
divs.appendChild(canv)
divsholdr.appendChild(divs)
const dates = document.createElement('p')
dates.textContent = x.daily.data[i].time
divs.appendChild(dates)
const temp = document.createElement('p')
temp.textContent = 'High: '+ x.daily.data[i].temperatureHigh + 'Low: ' + x.daily.data[i].temperatureLow
divs.appendChild(temp)
const summ = document.createElement('p')
summ.textContent = x.daily.data[i].summary
divs.appendChild(summ)
}
for(y=0;y<8;y++){
skycons.set('icons'+(y+1), Skycons = x.daily.data[y].icon)
}
})
}