Get images from JSON response - javascript

I am developing a shopify theme. Inside my theme. I have a div that I am looping. Inside the div, I have an image tag where I want to pass in the image from my JSON file
where the div id == to the image id
In my HTML file, I have this.
{% for order in customer.orders %}
{% for line_item in order.line_items %}
<span id="lineNumber">{{ line_item.product_id }}</span>
<div class="order-body">
<div class="row order-single">
<div class="col-12 col-md-3">
<img src="" alt="logo" class="fit-image-product" id="imglink">
</div>
...
{% endfor %}
{% else %}
<div class="container">
<div class="lg-header">
<h3>You are not Logged In</h3>
</div>
</div>
{% endif %}
In my script file, I have this
const lineNumberElements = document.querySelectorAll("#lineNumber");
let arrayOfLineNumbers = [];
for (const key in lineNumberElements) {
if (lineNumberElements.hasOwnProperty(key)) {
const element = lineNumberElements[key];
arrayOfLineNumbers.push(element.innerHTML);
}
console.log(arrayOfLineNumbers[key]);
}
const imgsrcElements = document.querySelectorAll("#imglink");
let arrayOfimgSrc = [];
for (const key in imgsrcElements) {
if (imgsrcElements.hasOwnProperty(key)) {
const element = imgsrcElements[key];
arrayOfimgSrc.push(element.innerHTML);
}
console.log(arrayOfimgSrc[key]);
}
const geturl = `https://website.myshopify.com//admin/api/2020-04/products.json`;
fetch(geturl, {
method: "GET",
headers: {
"Content-Type": "application/json",
"X-Shopify-Access-Token": "shppa_###################",
},
})
.then((response) => {
// console.log('resolved', response);
return response.json();
})
.then((data) => {
let allproducts = data.products;
console.log(allproducts);
allproducts.forEach(function (product) {
let product_id = product.id;
let product_image = product.image.src;
//console.log(product_id);
if (product_id == arrayOfLineNumbers[key]) {
console.log("how far", product_id, product_image);
arrayOfimgSrc[key] = product_image;
}
});
})
.catch((error) => {
console.error("There has been a problem with your operation:", error);
});
I kept getting the error
There has been a problem with your operation: ReferenceError: key is not defined
UPDATE
I have been able to minimize my code and error has been removed, but the first image was sent and looped over.
const lineNumberElements = document.querySelectorAll('#lineNumber');
const imgsrcElements = document.querySelectorAll('#imglink');
const geturl = `https://beymossweb.myshopify.com//admin/api/2020-04/products.json`
fetch(geturl, {
method: "GET",
headers: {
"Content-Type": "application/json",
"X-Shopify-Access-Token": "shppa_#############",
}
})
.then((response) => {
return response.json();
})
.then(data => {
let allproducts = data.products
console.log(allproducts)
allproducts.forEach(function (product) {
let product_id = product.id
let product_image = product.image.src
console.log(product_id, product_image);
for (let j = 0; j <= imgsrcElements.length; j++) {
imgsrcElements[j].src = product_image;
}
});
})
.catch(error => {
console.error('There has been a problem with your operation:', error);
});

In order to collaborate, it is not a solution to the case you describe but I think it can put us on track to solve it
The methods commented as helpers obtain the text of each lineNumber and the value of src of each imglink, manipulating them as an array, thus solving what I commented regarding for-in
Within the successful fetch response I am not clear what you are trying, I understand that in this line product_id == arrayOfLineNumbers [key] what you want is to check if there is a value equal to arrayOfLineNumbers in the array if that is the case this line will achieve your goal arrayOfLineNumbers.includes(product_id)
Finally in this line arrayOfimgSrc[key] = product_image; your intention is not clear
key does not exist in this context
the line tries to assign product_image to an array if it is the case you must use push method
As I mentioned at the beginning this is not intended to be a solution but perhaps by correcting some things and commenting on doubts we can reach the solution
// helpers
const toTextContent = (element) => element.textContent;
const toSrc = (element) => element.src;
const nodesToArray = (nodes) => Array.from(nodes);
const getTextContent = (nodes) => nodesToArray(nodes).map(toTextContent);
const getSrc = (nodes) => nodesToArray(nodes).map(toSrc);
// collections
const arrayOfLineNumbers = getTextContent(
document.querySelectorAll("#lineNumber")
);
const arrayOfimgSrc = getSrc(document.querySelectorAll("#imglink"));
// ajax
const geturl = `https://website.myshopify.com//admin/api/2020-04/products.json`;
fetch(geturl, {
method: "GET",
headers: {
"Content-Type": "application/json",
"X-Shopify-Access-Token": "shppa_###################",
},
})
.then((response) => response.json())
.then((data) => {
data.products.forEach((product) => {
let product_id = product.id;
let product_image = product.image.src;
if (arrayOfLineNumbers.includes(product_id)) {
console.log("how far", product_id, product_image);
arrayOfimgSrc[key] = product_image;
}
});
})
.catch((error) => {
console.error("There has been a problem with your operation:", error);
});

Related

Spotify API - Audio Player

I am relatively new to Javascript, I am practicing with a program that is able to pull data from Spotify API starting with Genre, then Playlists by Genre, Tracks, Track details, and an audio tag player to play a preview of the track.
I am able to do the Genre, Tracks, Track Details, but can't figure out the audio tag being linked to the track. The two issues, I have:
How to generate the audio tag based on user selection, and then reset it once a new selection is made
How to Get the Preview for the track based on user selection (for now I have the src for the audio tag as a random track.
const APIController = (function() {
const clientId = 'XX';
const clientSecret = 'XX';
//Fetch data from spotify api; private methods
const _getToken = async () => {
const result = await fetch('https://accounts.spotify.com/api/token', {
method: 'POST',
headers: {
'Content-Type' : 'application/x-www-form-urlencoded',
'Authorization' : 'Basic ' + btoa( clientId + ':' + clientSecret)
},
body: 'grant_type=client_credentials'
});
const spot = await result.json();
return spot.access_token;
}
const _getGenres = async (token) => {
const limit = 10;
const result = await fetch(`https://api.spotify.com/v1/browse/categories?country=CA&limit=${limit}`, {
method: 'GET',
headers: { 'Authorization' : 'Bearer ' + token}
});
const spot = await result.json();
return spot.categories.items;
}
const _getPlaylistByGenre = async (token, genreId) => {
const limit = 10;
const result = await fetch(`https://api.spotify.com/v1/browse/categories/${genreId}/playlists?limit=${limit}`, {
method: 'GET',
headers: { 'Authorization' : 'Bearer ' + token}
});
const spot = await result.json();
return spot.playlists.items;
}
const _getTracks = async (token, tracklist) => {
const limit = 30;
const result = await fetch(`${tracklist}?limit=${limit}`, {
method: 'GET',
headers: { 'Authorization' : 'Bearer ' + token}
});
const spot = await result.json();
return spot.items;
}
const _getTrack = async (token, trackdetail) => {
const result = await fetch(`${trackdetail}`, {
method: 'GET',
headers: { 'Authorization' : 'Bearer ' + token}
});
const spot = await result.json();
return spot;
}
const _getPreview = async (token, trackpreview) => {
const result = await fetch(`${trackpreview}`, {
method: 'GET',
headers: { 'Authorization' : 'Bearer ' + token}
});
const spot = await result.json();
return spot.preview;
}
return {
getToken() {
return _getToken();
},
getGenres(token) {
return _getGenres(token);
},
getPlaylistByGenre(token, genreId) {
return _getPlaylistByGenre(token, genreId);
},
getTracks(token, tracklist) {
return _getTracks(token, tracklist);
},
getTrack(token, trackdetail) {
return _getTrack(token, trackdetail);
},
getPreview(token, trackpreview) {
return _getPreview(token, trackpreview);
}
}
})();
// UI Module
const UIController = (function() {
//object to hold references to html selectors
const DOMElements = {
selectGenre: '#select_genre',
selectPlaylist: '#select_playlist',
buttonSubmit: '#btn_submit',
divSongDetail: '#song-detail',
hfToken: '#hidden_token',
divSonglist: '.song-list',
preview:'.songpreview'
}
//public methods
return {
//method to get input fields
inputField() {
return {
genre: document.querySelector(DOMElements.selectGenre),
playlist: document.querySelector(DOMElements.selectPlaylist),
tracks: document.querySelector(DOMElements.divSonglist),
submit: document.querySelector(DOMElements.buttonSubmit),
songDetail: document.querySelector(DOMElements.divSongDetail),
songPreview: document.querySelector(DOMElements.preview)
}
},
// need methods to create select list option
createGenre(text, value) {
const html = `<option value="${value}">${text}</option>`;
document.querySelector(DOMElements.selectGenre).insertAdjacentHTML('beforeend', html);
},
createPlaylist(text, value) {
const html = `<option value="${value}">${text}</option>`;
document.querySelector(DOMElements.selectPlaylist).insertAdjacentHTML('beforeend', html);
},
// need method to create a track list group item
createTrack(id, name) {
const html = `${name} `;
document.querySelector(DOMElements.divSonglist).insertAdjacentHTML('beforeend', html);
},
// need method to create the song detail
createTrackDetail(img, title, artist) {
const detailDiv = document.querySelector(DOMElements.divSongDetail);
// any time user clicks a new song, we need to clear out the song detail div
detailDiv.innerHTML = '';
const html =
`
<div class="songimg">
<img src="${img}" alt=""width="100px" height="100px">
</div>
<div class="songname"><span>
<label for="Genre" style="font-size:20px; color:black" class="form-label">${title}</label>
</span>
</div>
<div class="artistname"><span>
<label for="artist" style="color:blue" class="form-label">${rtist}</label>
</span></div>
`;
detailDiv.insertAdjacentHTML('beforeend', html)
},
createPreview() {
const html = `<audio class="preview" id="newplayer" controls onplay="playtrack()" onpause="pausetrack()" type="audio/mpeg" src="https://p.scdn.co/mp3-preview/ad57003c15e607c0d74c8a25ed7581c770b28a9a?cid=774b29d4f13844c495f206cafdad9c86" preload="auto"></audio>`;
document.querySelector(DOMElements.songPreview).insertAdjacentHTML('beforeend', html);
},
//method to reset fields
resetPreview() {
this.inputField().songPreview.innerHTML = '';
},
resetTrackDetail() {
this.inputField().songDetail.innerHTML = '';
},
resetTracks() {
this.inputField().tracks.innerHTML = '';
this.resetTrackDetail();
const spotpreview=document.getElementById("newplayer").classList;
spotpreview.remove("showme");
document.getElementsByTagName("body")[0].style="background-image:url('hands.jpeg');";
document.getElementsByTagName("body")[0].class="backgrd3";
},
resetPlaylist() {
this.inputField().playlist.innerHTML = '';
this.resetTracks();
},
storeToken(value) {
document.querySelector(DOMElements.hfToken).value = value;
},
getStoredToken() {
return {
token: document.querySelector(DOMElements.hfToken).value
}
}
}
})();
const APPController = (function(UICtrl, APICtrl) {
// get input field object ref
const DOMInputs = UICtrl.inputField();
// get genres on page load
const loadGenres = async () => {
//get the token
const token = await APICtrl.getToken();
//store the token onto the page
UICtrl.storeToken(token);
//get the genres
const genres = await APICtrl.getGenres(token);
//populate our genres select element
genres.forEach(element => UICtrl.createGenre(element.name, element.id));
}
// create genre change event listener
DOMInputs.genre.addEventListener('change', async () => {
//reset the playlist
UICtrl.resetPlaylist();
//get the token that's stored on the page
const token = UICtrl.getStoredToken().token;
// get the genre select field
const genreSelect = UICtrl.inputField().genre;
// get the genre id associated with the selected genre
const genreId = genreSelect.options[genreSelect.selectedIndex].value;
// ge the playlist based on a genre
const playlist = await APICtrl.getPlaylistByGenre(token, genreId);
// create a playlist list item for every playlist returned
playlist.forEach(p => UICtrl.createPlaylist(p.name, p.tracks.href));
});
// create submit button click event listener
DOMInputs.submit.addEventListener('click', async (e) => {
// prevent page reset
e.preventDefault();
// clear tracks
UICtrl.resetTracks();
//get the token
const token = UICtrl.getStoredToken().token;
// get the playlist field
const playlistSelect = UICtrl.inputField().playlist;
// get track endpoint based on the selected playlist
const tracksEndPoint = playlistSelect.options[playlistSelect.selectedIndex].value;
// get the list of tracks
const tracks = await APICtrl.getTracks(token, tracksEndPoint);
// create a track list item
tracks.forEach(el => UICtrl.createTrack(el.track.href, el.track.name))
});
// create song selection click event listener
DOMInputs.tracks.addEventListener('click', async (e) => {
// prevent page reset
e.preventDefault();
UICtrl.resetTrackDetail();
// get the token
const token = UICtrl.getStoredToken().token;
// get the track endpoint
const trackEndpoint = e.target.id;
//get the track object
const track = await APICtrl.getTrack(token, trackEndpoint);
// load the track details
UICtrl.createTrackDetail(track.album.images[2].url, track.name, track.artists[0].name);
});
// create song preview selection click event listener
DOMInputs.songPreview.addEventListener('click', async (e) => {
// prevent page reset
e.preventDefault();
UICtrl.resetPreview();
// get the token
const token = UICtrl.getStoredToken().token;
// get the playlist field
const previewsong = UICtrl.inputField().songPreview;
const previewEndPoint = previewsong.options[previewsong.selectedIndex].value;
// get the list of tracks
const tracks = await APICtrl.getTracks(token, previewEndPoint);
// create a track list item
tracks.forEach(el => UICtrl.createTrack(el.track.href, el.track.name))
});
return {
init() {
console.log('App is starting');
loadGenres();
}
}
})(UIController, APIController);
// will need to call a method to load the genres on page load
APPController.init();

How to make API calls in Vanilla JS

Am building a weather app using vanilla JS and weatherbit rapid API, but whenever I run the program, it logs an error Can not read properties of undefined (reading 'temp')
const tempValue = document.getElementsByClassName('temp')
// console.log(cityName)
const options = {
method: 'GET',
headers: {
'X-RapidAPI-Key': '************************************',
'X-RapidAPI-Host': 'weatherbit-v1-mashape.p.rapidapi.com'
}
}
document.getElementById('submit').addEventListener('click', e => {
e.preventDefault()
fetch(
'https://weatherbit-v1-mashape.p.rapidapi.com/forecast/3hourly?lat=35.5&lon=-78.5',
options
)
.then(response => response.json())
.then(data => {
let tempval = data['temp']
tempValue.innerHtml = tempval
})
.catch(err => console.error(err))
})
pls consult the docs.
https://rapidapi.com/weatherbit/api/weather
response object structure is:
{
country_code:"US",
lon:-78.5,
data: [...],
city_name:"Four Oaks",
lat:35.5,
timezone:"America/New_York",
state_code:"NC",
}
To access 'temp'. use `
fetch(
'https://weatherbit-v1-mashape.p.rapidapi.com/forecast/3hourly?lat=35.5&lon=-78.5',
options
).then(response => {
const someItemIndex = 0;
console.log(response.data);
const tempval = response.data[someItemIndex].temp
tempValue.innerHtml = tempval
})
.catch(err => console.error(err))
there is no temp in response. and there is no any field 'temp' in data. Temp is defined only on iterable items of data array.
After some advice I received from this platform, I have managed to modify the code and it's working perfectly. The problem was in the way I was accessing the fields from the JSON. I am new to APIs and this is an excellent start for me thank you.
Modified Code
const tempValue = document.querySelector('.temp')
const cityName = document.querySelector('.city_name')
const humid = document.querySelector('.humidity')
const weatherValue = document.querySelector('.weather')
// console.log(cityName)
const options = {
method: 'GET',
headers: {
'X-RapidAPI-Key': '30583b6ad4msh649637ae1b0f6d3p1edde0jsn53b7839146a2',
'X-RapidAPI-Host': 'weatherbit-v1-mashape.p.rapidapi.com'
}
}
document.getElementById('submit').addEventListener('click', e => {
e.preventDefault()
fetch(
'https://weatherbit-v1-mashape.p.rapidapi.com/forecast/3hourly?lat=35.5&lon=-78.5',
options
)
//Modified code
.then(response => response.json())
.then(response => {
const someItemIndex = 0
console.log(response.data)
const tempval = response.data[someItemIndex].temp
const cityval = response.city_name
const weatherval = response.data[someItemIndex].weather.description
// console.log(tempval)
tempValue.innerHTML = `<h3>Temperature: </h3>${tempval}&#x2103`
weatherValue.innerHTML = `<h3>Weather Description: </h3>${weatherval}`
cityName.innerHTML = `<h3>City Name: </h3>${cityval}`
})
.catch(err => console.error(err))
})

Using Axios to post a joke on click ( 1 at a time )

I could use some help.
I have a button and on click, it generates a joke using dad jokes API and Axios. However, I can't figure out how to get rid of the old joke when I click on the button again. Here is my code. Thanks
let button = document.querySelector('button')
button.addEventListener("click", getJoke)
function getJoke() {
const p = axios
.get('https://icanhazdadjoke.com/', { headers: { "Accept": "text/plain" },
})
.then((response) => {
const joke = response.data
const jokeContainer = document.querySelector('.joke');
const blockquoteEl = document.createElement('blockquote');
blockquoteEl.append(joke);
jokeContainer.appendChild(blockquoteEl);
})
.catch((error) => {
const jokeContainer = document.querySelector('.joke');
jokeContainer.innerText = 'Joke not found :(';
});
}
<div class="joke">
<button>Click if you want a cringe joke</button>
</div>
What you should do is use the functions inherited by dom elements to delete de child node:
<body>
<div class="joke">
<button>Click if you want a cringe joke</button>
</div>
<script>
let button = document.querySelector('button');
button.addEventListener("click", getJoke);
function getJoke(){
const p = axios.get('https://icanhazdadjoke.com/', { headers: { "Accept": "text/plain" }
}).then((response) => {
const joke = response.data
const jokeContainer = document.querySelector('.joke');
jokeContainer.removeChild(jokeContainer.childNodes[2]);
const blockquoteEl = document.createElement('blockquote');
blockquoteEl.append(joke);
jokeContainer.appendChild(blockquoteEl);
}).catch((error) => {
const jokeContainer = document.querySelector('.joke');
jokeContainer.innerText = 'Joke not found :(';
});
}
</script>
</body>
you need to store the incoming jokes in ana array to check the duplicates. try this
function getJoke() {
const p = axios
.get('https://icanhazdadjoke.com/', { headers: { "Accept": "text/plain" },
})
.then((response) => {
const joke = response.data
const jokesArr = [];
// stores joke history
jokesArr.push(joke);
// checkes the repeated joke in jokes history
const jokeCheck = (joke) => {
const currentItemCount = jokesArr.filter(val => val=== joke).length;
if(currentItemCount > 0) {
p();
}
return joke;
}
const currentJoke = jokeCheck(joke);
const jokeContainer = document.querySelector('.joke');
const blockquoteEl = document.createElement('blockquote');
blockquoteEl.append(currentJoke);
jokeContainer.appendChild(blockquoteEl);
})
.catch((error) => {
const jokeContainer = document.querySelector('.joke');
jokeContainer.innerText = 'Joke not found :(';
});
}

Getting access to the index in plain JS

so I'm building a seemingly simple playlist JS app with a rails backend and I'm running into an issue. I cannot seem to get the return value I want. I have my tracks and playlist rendered but I need to get the index of each song on the page and I am only able to figure out how to get the first track. I'm new to JS as you can probably tell so any advise you have would be great. Thanks in advance.
function getPlaylists() {
fetch(BACKEND_URL)
.then(response => response.json())
.then(list => {
list.data.map((playlist, index) => {
let newPlaylist = new Playlist(playlist, playlist.attributes) ;
document.getElementById('playlist-container').innerHTML += newPlaylist.renderPlaylistCard();
})
}
)
}
function postFetch(title, artist){
fetch(BACKEND_URL, {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
name: name,
title: title,
artist: artist
})
})
.then(response => response.json())
.then(playlist => {
const playlistData = playlist.data;
let newPlaylist = new Playlist(playlistData, playlistData.attributes);
document.getElementById('playlist-container').innerHTML += newPlaylist.renderPlaylistCard() ;
})
}
```class Playlist {
constructor(playlist, playlistAttributes) {
this.id = playlist.id
this.name = playlistAttributes.name
this.track = playlistAttributes.tracks
Playlist.all.push(this);
//debugger
}
renderPlaylistCard() {
return `
<div data-id=${this.id}>
<h3><li>Playlist Name: ${this.name}</h3></li>
<h3><li>Title: ${this.track[0].title}</h3></li>
<h3><li>Title: ${this.track[0].artist}</h3></li>
<button data-id=${this.id}>EDIT!</button>
</div> </li>
` ;
}
}
Playlist.all = [];

How to implement the 'show more' button?

I want to implement button behavior Show more.
When I click the button, new objects must be loaded without rebooting.
I do const [data, setData] = useState(users); to initialize the first 10 users.
When I press the button, that to this array data, I add the following 10 users
var users = response.data;
for (var i=0; i < users.length; i++) {
data.push(users[i]);
}
setData(data);
But nothing is rendered in the browser.
how to do it correct?
const Cards = ({users, bottomUrl }) => {
const [data, setData] = useState(users);
const handleSubmit = e => {
e.preventDefault();
const page = bottomUrl.slice(-1);
const axios = require('axios');
const url = '/users';
axios.get(url, {
params: { page: page }
}, {headers: {'Content-Type': 'application/json'}})
.then(function (response) {
var users = response.data;
for (var i=0; i < users.length; i++) {
data.push(users[i]);
}
setData(data);
})
.catch(function (error) {
console.log(error);
})
.then(function () {
// always executed
});
};
return (
<div>
<div className="users-list">
{data.map((element, elIndex) => (
<UserCard
key={elIndex}
lastName={element.lastName}
firstName={element.firstName}
description={element.description}
/>
))}
</div>
<div className="users-page-button-container">
<a className="button" onClick={handleSubmit} href={bottomUrl}>Show more</a>
</div>
</div>
)
};
You are pushing on the state object data. You must use an intermediate variable and pass that to setData
You are manipulating the state directly, which is wrong. Please update the handleSubmit method as below.
const handleSubmit = e => {
e.preventDefault();
const page = bottomUrl.slice(-1);
const axios = require('axios');
const url = '/users';
axios.get(url, {
params: { page: page }
}, {headers: {'Content-Type': 'application/json'}})
.then(function (response) {
users = response.data;
setData([...data, ...users]); // You need to save the previous data along with the new data and pass it together to setData function. So here data = previous data + new users data
})
.catch(function (error) {
console.log(error);
})
.then(function () {
// always executed
});
};

Categories