I have a component to render only the latest product gets from API:
const about = ({products}) => {
const data = products.attributes
console.log(data)
return (
<div>
<h1>{data.Name}</h1>
<p>{data.Description}</p>
<p>{Number(data.Price).toLocaleString('it-IT', {style : 'currency', currency : 'VND'})}</p>
<p>{data.Release}</p>
<p>{data.Expire}</p>
<p>{data.Close ? "Close" : "Open"}</p>
</div>
);
}
export async function getStaticProps() {
const data = await fetch(myAPI)
const res = await data.json()
const products = res.data[0]
return {
props: {products}
}
}
export default about;
The JSON from API looks like this:
{
"data": [
{
"id": 1,
"attributes": {
"Name": "Vĩ Hoạ",
"Description": "Vĩ Hoạ",
"Price": "30000",
"Release": "2022-05-04",
"Expire": "2022-05-26",
"Close": false,
"createdAt": "2022-05-09T22:28:09.622Z",
"updatedAt": "2022-05-10T05:50:38.430Z",
"publishedAt": "2022-05-10T05:50:12.353Z"
}
}
],
"meta": {
"pagination": {
"page": 1,
"pageSize": 25,
"pageCount": 1,
"total": 1
}
}
}
The highest id from JSON is the latest product, I haven't figured out how to resolve this JSON for getting the latest product.const products = res.data[x] is used to get the specific product based on x, like an index. This is my temporary solution but not flexible to get the latest one!
The best solution is descending data by createdAt when getting data from the API. Otherwise, you can use this method.
const about = ({products}) => {
const data = products.attributes
console.log(data)
return (
<div>
<h1>{data.Name}</h1>
<p>{data.Description}</p>
<p>{Number(data.Price).toLocaleString('it-IT', {style : 'currency', currency : 'VND'})}</p>
<p>{data.Release}</p>
<p>{data.Expire}</p>
<p>{data.Close ? "Close" : "Open"}</p>
</div>
);
}
export async function getStaticProps() {
const data = await fetch(myAPI)
const res = await data.json()
const products = res.data.sort((a, b) => b.id - a.id)[0]
return {
props: {products}
}
}
export default about;
Related
I'm trying to show a page in React that shows a grid of images. I get the data for the grid with a fetch to a file in a public subfolder.
export const GalleryGrid = () => {
const { galleries, loading } = useFetchGalleries()
return (
<div>
{loading && <div className="diving__loading flex-column">
<div><Loader
type="Puff"
color="#264653ff"
height={200}
width={200}
/></div>
<div>
<p>
Please Wait ...
</p>
</div>
</div>}
<div className="card-grid">
<div className="row row-cols-1 row-cols-sm-2 row-cols-md-3 row-cols-lg-4 row-cols-xl-5">
{
galleries.map(gal => (
<GalleryGridItem
key={gal.url}
{...gal}
/>
))
}
</div>
</div>
</div>
)
}
I use the function "useFetchGAlleries()" to get the data I neew for the grid. This function launch a helper, called "getGalleries", and return de data stored with useState
export const useFetchGalleries = () => {
const [ state, setState] = useState({
galleries: [],
loading: true
});
useEffect(() => {
getGalleries()
.then( galleries => {
setState({
galleries,
loading: false
})
})
.catch( e => {
console.log( e );
});
}, [ ]);
return state;
}
The helper "getGalleries" uses a fetch to read the files that contain objects in json format, and transform them to an object:
export const getGalleries = async () => {
const galleries = await fetch(`./assets/data/galleries.txt`)
.then( res => {
return res.json();
})
.then( body => {
return body.galleries;
})
.catch( e => {
console.log( e );
});
// the .map check if the gallery have images or not
await galleries.map( gal => (
gal.interactive ? fetch(`./assets/data/${gal.url}.txt`)
.then( res => {
return res.json();
})
.then( body => {
gal.images = body.images;
})
.catch( e => {
console.log( e );
})
: ""
));
return galleries ;
}
In "GalleryGrid" I have all information about galleries I need. For example, the first gallery from the array is:
{
"name": "Nuestros Fondos 2022",
"url": "galeria_22_fishes",
"number": 8,
"interactive": true,
"images": [
{"index": '01', "url": 'galeria_03_cursos'},
{"index": '02', "url": 'galeria_03_cursos'},
{"index": '03', "url": 'galeria_03_cursos'},
{"index": '04', "url": 'galeria_03_cursos'},
{"index": '05', "url": 'galeria_03_cursos'},
{"index": '06', "url": 'galeria_03_cursos'},
{"index": '07', "url": 'galeria_03_cursos'},
]
}
But when I give the info to the component "GalleryGridItem" in the "GalleryGrid" function, the data doesn't contain the array of images. The data is as follow:
{
"name": "Nuestros Fondos 2022",
"url": "galeria_22_fishes",
"number": 8,
"interactive": true,
"images": []
}
Any suggestion about what is happening?
The JSON of images is invalid JSON. You need to add quotes to the keys.
You are awaiting an array of promises. You need to use Promise.all()
await Promise.all(galleries.map( gal => (...))
Your function is returning immediately after .map, before any images are loaded.
How do I set my returned data from a JSON file to a const so I can use it in other functions. I'm able to console.log but how do I proceed? The end goal is to be able to use data.purchase_orders and loop through the data (ie - price_list)
data.json
{
"purchase_order": [
{
"id": "1",
"external_number": "1000",
"status": "Created",
"price_list": [
{
"id": "msrp",
"name": "retail price",
"currency": "USD"
}
],
"shipments": [
{
"id": "1",
"external_number": "10000",
"status": "Created",
"tracking_number": "Z1F2"
},
{
"id": "2",
"external_number": "9000",
"status": "In Transit",
"tracking_number": "PL21F"
}
]
}
]
}
index.html
<div id="shipments"></div>
<script>
const data_file = 'data.json';
async function fetchPO(){
const reponse = await fetch(data_file);
const data = await response.json();
const PO = data.purchase_orders.forEach((PODetails) => {
console.log(PODetails);
//^this displays key and value of my JSON data_file
})
displayShipments(PO);
}
fetchPO();
function displayShipments(shipmentsList){
document.getElementById("shipments").innerHTML = `
${Object.keys(shipmentsList).map(function (shipments)
return `${shipments.id}
<p>${shipments.tracking_number}</p>`
)}
}
`
}
</script>
One approach is to return the data from the async fetccPO() and store the promise in a variable.
A promise can be used as many times as you want.
Simplified example:
async function fetchUsers() {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
return response.json();
}
// makes request and stores promise in variable
const usersPromise = fetchUsers();
async function logAddress() {
// promise can be used many times
const users = await usersPromise;
console.clear()
console.log(users[0].address);
}
async function logUserName() {
const users = await usersPromise;
console.clear()
console.log(users[0].name);
}
<button onclick="logAddress()">Log first user address</button>
<button onclick="logUserName()">Log first user name</button>
i try to get some track_list data inside object JSON using Musixmatch API
here is my code
"body": {
"track_list": [
{
"track": {
"track_id": 194169151,
"track_name": "Blinding Lights",
"track_name_translation_list": [],
"track_rating": 100,
"commontrack_id": 104185748,
"instrumental": 0,
"explicit": 0,
"has_lyrics": 1,
"has_subtitles": 1,
"has_richsync": 1,
"num_favourite": 3237,
"album_id": 37216011,
"album_name": "After Hours",
"artist_id": 13937035,
"artist_name": "The Weeknd",
"track_share_url": "https://www.musixmatch.com/lyrics/The-Weeknd-3/Blinding-Lights?utm_source=application&utm_campaign=api&utm_medium=rickyreza%3A1409619798940",
"track_edit_url": "https://www.musixmatch.com/lyrics/The-Weeknd-3/Blinding-Lights/edit?utm_source=application&utm_campaign=api&utm_medium=rickyreza%3A1409619798940",
"restricted": 0,
"updated_time": "2020-04-10T08:31:57Z",
"primary_genres": {
"music_genre_list": [
{
"music_genre": {
"music_genre_id": 7,
"music_genre_parent_id": 34,
"music_genre_name": "Electronic",
"music_genre_name_extended": "Electronic",
"music_genre_vanity": "Electronic"
}
}
]
}
}
},
i just want to check if i can geat the data inside a track by doing lyric.album_name. and tried to get the album and i got this kind of things album_name as undefined. here is my main.js
main.js
function main() {
// initialize the data
const baseUrl = "https://api.musixmatch.com/ws/1.1";
const apiKey = "78fa4727ab9c4495d4fc07dae75f775b";
const chartTrack = "chart.tracks.get?chart_name=top&page=1&page_size=5&country=jp&f_has_lyrics=1"
const getLirik = () => {
fetch(`${baseUrl}/${chartTrack}&apikey=${apiKey}`)
.then(response => {
return response.json();
})
.then(responseJson => {
// console.log(responseJson);
// trackList.track_list = responseJson.message.body.track_list
console.log(responseJson.message.body.track_list.track);
// console.log(responseJson.message.body.track_list.track.album_name);
renderAllData(responseJson.message.body.track_list);
})
.catch(error => {
console.log(error);
})
}
/*
for making a new html DOM
*/
const renderAllData = (lyrics) => {
const lirikElement = document.querySelector("#popularLyrics");
lirikElement.innerHTML = "";
lyrics.forEach(lyric => {
lirikElement.innerHTML += `
<div>${lyric.album_name}</div>
`
})
}
getLirik();
}
export default main;
How do i can get all thos track_name and stuff inside track?
You forgot the property .track in your lyrics object. Try this
...
<div>${lyric.track.album_name}</div>
i checked the api call https://api.musixmatch.com/ws/1.1/chart.tracks.get?chart_name=top&page=1&page_size=5&country=jp&f_has_lyrics=1&apikey=78fa4727ab9c4495d4fc07dae75f775b the tracklist returns an Array of objects, where each object has only one key track
something like this track_list = [{track:{}},{track:{}}]
use ${lyric.track.album_name} it should work
you forgot one property, but you can do less nesting using destructuring in the function, this is a litle modification of your code:
const renderAllData = (trackList) => {
const lirikElement = document.querySelector("#popularLyrics");
lirikElement.innerHTML = "";
trackList.forEach(({ track }) => {
lirikElement.innerHTML += `
<div>${track.album_name}</div>
`;
});
};
renderAllData(data.body.track_list);
I'd like to get my trips, which are my response from API in Angular.
From the backend I'm getting:
{
"trips": [
{
"id": 0,
"name": "string",
"startDate": "2019-06-30T06:05:48.006Z",
"endDate": "2019-06-30T06:05:48.006Z",
"description": "string",
"roomSharing": true,
"countries": [
{
"id": 0,
"name": "string",
"code": "string"
}
],
"languages": [
{
"id": 0,
"name": "string",
"code": "string"
}
]
}
]
}
which is fine, but I have a problem on the client side.
Here's my code for getting trips:
getTrips(): Observable<Trip[]> {
return this.http.get<Trip[]>(this.apiUrl + '/Trip/Get')
.pipe(
tap(_ => console.log('fetched trips')),
retry(1),
catchError(this.handleError),
map(data => {
return data;
})
);
}
and in my component I have:
loadTrips() {
return this.rest.getTrips()
.subscribe((data) => {
this.trips = data;
console.log(this.trips);
}
, err => console.log(err));
}
I'd like to get trips in a template like:
<div class="card mb-3 trip" *ngFor="let trip of trips">
but I have to like:
<div class="card mb-3 trip" *ngFor="let trip of trips.trips">
So, the question is how can I map my response to get Trip array instead of Array of Trips array?
Unless I'm misunderstanding something, this should work:
interface TripsResponse {
trips: Trips[],
}
getTrips(): Observable<Trip[]> {
// use your response interface instead
//return this.http.get<Trip[]>(this.apiUrl + '/Trip/Get')
return this.http.get<TripsResponse>(this.apiUrl + '/Trip/Get')
.pipe(
tap(_ => console.log('fetched trips')),
retry(1),
catchError(this.handleError),
map(data => {
return data.trips; // set it properly here
})
);
}
Change your return statement:
return this.http.get('/Trip/Get')
.pipe(
tap(_ => console.log('fetched trips')),
retry(1),
catchError(this.handleError),
map((data: TripsResponse) => { // change made here; make data of type TripsResponse
return data.trips;
})
);
where TripsResponse is
interface TripsResponse {
trips: Trips[],
... // other fields for future if required
}
Dont over complicate by doing .map, just do:
loadTrips() {
return this.rest.getTrips()
.subscribe((data) => {
this.trips = data.trips;
}
, err => console.log(err));
}
Also, correct the model Trip[] which you have created it should be
export interface ITripsResponse {
trips: Trips[],
}
return this.http.get<ITripsResponse>(this.apiUrl + '/Trip/Get')
or else, correct .map by
map((data) => {
return data.trips;
})
and then Observable<Trip[]> would be a valid return type
I have an object of nested route.
Any route MAY contains a list of route childRoutes.
I want to get the list of all the route that contains the key menu.
const routes = [{
"name": "userManagement",
"childRoutes": [
{
"name": "blogManagement",
"childRoutes": [
{
"name": "blog", // <=== I want to have this route
"menu": {
"role": 1020
}
}
],
},
{
"name": "organizationList", // <=== and this one
"menu": {
"role": 1004
}
}
],
}, {
"name": "test",
"menu": { "role": 4667 }
}];
const deepFlatten = arr => [].concat(...arr.map(v => (Array.isArray(v) ? deepFlatten(v) : v)));
// Should handle nesting of route
const links = deepFlatten(routes).filter((r) => !!r.menu);
console.log('it should have a length of 3:', links.length === 3);
console.log('it should be blog:', links[0].name === 'blog');
console.log('it should be organizationList:', links[1].name === 'organizationList');
console.log('it should be test:', links[2].name === 'test');
The above snippet does not work recursively yet.
How can I do it recursively without any third-party library ?
#yBrodsky's answer can be adapted to isolate and exhibit the generic flatMap operation – here, you'll see that the routes flattened with much of the reduce-map-concat plumbing out of the programmer's way.
// polyfill if you don't have it
Array.prototype.flatMap = function (f)
{
return this.reduce ((acc, x) =>
acc.concat (f (x)), [])
}
// your data
const routes =
[ { name : "userManagement"
, childRoutes :
[ { name : "blogManagement"
, childRoutes :
[ { name : "blog"
, menu : { role : 1020 }
}
]
}
, { name : "organizationList"
, menu : { role : 1004 }
}
]
}
, { name : "test"
, menu : { role : 4667 }
}
]
// flat-mapped routes
const allChildRoutes =
routes.flatMap (function loop (node) {
if (node.childRoutes)
return node.childRoutes.flatMap (loop)
else
return [node]
})
console.log (allChildRoutes)
how about this, seems to work.
const flatten = (routes) => {
return routes.reduce((acc, r) => {
if(r.childRoutes && r.childRoutes.length) {
acc = acc.concat(flatten(r.childRoutes));
} else {
acc.push(r);
}
return acc;
}, [])
}
https://jsfiddle.net/vv9odcxw/