Iterate objects over nested array JavaScript - javascript

how would I be able to iterate over this JSON api response to get the "body" object from "Incident_updates" array?
Here is the JSON:
[
{
"id": 3787,
"title": "Dummy title!",
"start_time": "2020-04-25T16:54:00.000Z",
"created_at": "2020-04-25T17:22:13.315Z",
"updated_at": "2020-04-25T17:32:15.364Z",
"incident_updates": [
{
"id": 9905,
"body": "Dummy Paragraph test!",
I have tried using .map and foreach in my script.js file but no matter what I try and do, nothing seems to work and I get a "undefined undefined" error in the console. I also need to get the incident_updates.body response from all arrays that were in the api response. doing something like incident_updates[0].body works however I also need the responses from incident_updates[1].body etc etc.
This is my script.js file
fetch(url)
.then((response) => {
if (!response.ok) {
throw Error("ERROR");
}
return response.json();
})
.then((data) => {
console.log(data);
const html = data
.map((item) => {
console.log(item.incident_updates[0]);
return `<div class="card card-space">
<div class="card-body">
<h5 class="card-title">${item.title}</h5>
<h6 class="card-subtitle mb-2 text-muted">${item.start_time}</h6>
<p class="card-text">${item.incident_updates.body}</p> // issues with this
</div>
</div>`;
})
.join("");
Thanks for your help!

The incident_updates is an array of object, you need to retrieve one of the items using item.incident_updates[0].body. If it has multiple elements, you should consider creating another loop and retrieve them.
Here's an example that how you can output all item:
fetch(url).then((response) => {
if (!response.ok) {
throw Error("ERROR");
}
return response.json();
}).then((data) => {
console.log(data);
const html = data
.map((item) => {
console.log(item.incident_updates[0]);
return `<div class="card card-space">
<div class="card-body">
<h5 class="card-title">${item.title}</h5>
<h6 class="card-subtitle mb-2 text-muted">${item.start_time}</h6>
${item.incident_updates.map(update => `
<p class="card-text">${update.body}</p>
`).join('')}
</div>
</div>`;
})
.join("");
});
Edit
If you only need the first one of the item.incident_updates, just try item.incident_updates[0].body
fetch(url).then((response) => {
if (!response.ok) {
throw Error("ERROR");
}
return response.json();
}).then((data) => {
console.log(data);
const html = data
.map((item) => {
console.log(item.incident_updates[0]);
return `<div class="card card-space">
<div class="card-body">
<h5 class="card-title">${item.title}</h5>
<h6 class="card-subtitle mb-2 text-muted">${item.start_time}</h6>
<p class="card-text">${item.incident_updates[0].body}</p>
</div>
</div>`;
})
.join("");
});

not exactly the same example, but in this example you will see the logic to do what you need, I use destructuring to get the data in the function params and to access the first value of the array, I use square bracket notation:
const data = [
{
id: 3787,
title: "Dummy title!",
start_time: "2020-04-25T16:54:00.000Z",
created_at: "2020-04-25T17:22:13.315Z",
updated_at: "2020-04-25T17:32:15.364Z",
incident_updates: [
{
id: 9905,
body: "Dummy Paragraph 05!",
},
{
id: 9906,
body: "Dummy Paragraph 06!",
},
{
id: 9907,
body: "Dummy Paragraph 07!",
},
],
},
];
const html = data.forEach(({ title, start_time, incident_updates }) => {
const template = `
<div class="card card-space">
<div class="card-body">
<h5 class="card-title">${title}</h5>
<h6 class="card-subtitle mb-2 text-muted">${start_time}</h6>
${incident_updates
.map((incident) => `<p class="card-text">${incident.body}</p> `)
.join(" ")}
</div>
</div>
`;
console.log(template);
});

Related

Is there a way to sort each odd and even object in an array in Javascript?

I need to be able to append every even object on the left side of a vertical line, and every odd object on the right side. I am not sure how I can achieve this.
Sample of the JSON, (This is just dummy data for now) (url)
[{
"Year": 2010,
"Title": "Cadillac",
"Description": "Escalade ESV"
},
{
"Year": 1998,
"Title": "Volvo",
"Description": "V70"
},
{
"Year": 1992,
"Title": "Toyota",
"Description": "Camry"
},
{
"Year": 2012,
"Title": "Ford",
"Description": "Explorer"
}]
Heres my code:
fetch(url)
.then(result => {
return result.json();
})
.then (data =>{
console.log(data);
data.forEach( (point) => {
const appendToHtml = `
<div class="container left">
<div class="content">
<h2>${point.Title}</h2>
<p>${point.Description}</p>
<p>${point.Year}</p>
</div>
</div>
<div class="container right">
<div class="content">
<h2>${point.Title}</h2>
<p>${point.Description}</p>
<p>${point.Year}</p>
</div>
</div>
`;
$(".timeline").append(appendToHtml);
});
})
The issue is it append on the left AND the right.
Click here for an image of the issue.
I need to alternate
for example
Cadillac on the left, Volva on the right etc...
I cant seem to figure out what to do..
Thanks in advance!
You can calculate the odd or even of car index and based on that apply class left and right.
data.forEach( (point, index) => {
const isOdd = index % 2;
const appendToHtml = `
<div class="container ${isOdd ? 'right' : 'left' }">
<div class="content">
<h2>${point.Title}</h2>
<p>${point.Description}</p>
<p>${point.Year}</p>
</div>
</div>`;
$(".timeline").append(appendToHtml);
});
Here you go with a solution
fetch(url)
.then(result => {
return result.json();
})
.then (data =>{
console.log(data);
data.forEach( (point, i) => {
const appendToHtml = `
<div class=`container ${i%2 === 0 ? "right" : "left" }`>
<div class="content">
<h2>${point.Title}</h2>
<p>${point.Description}</p>
<p>${point.Year}</p>
</div>
</div>
`;
$(".timeline").append(appendToHtml);
});
})
Use template literal for finding odd even using mod function

Pass parameters via GET to return filter

I want to return a data query via GET to return me values according to what is selected in the v-model.
I would like to know how to get the v-model values from the input and make the request to get by parameter
My filter (the components are already returning object as your id according to what I select)
<div class="row gutter-sm">
<div class="col-md-12">
<q-card class="full-width bg-white q-pa-md q-card-flex">
<div class="col-md-2">
<situacao-select multiple v-model="situacao" :stackLabel="'Situação OS'" style="height:50px;" :clearable="true" />
</div>
<div class="col-md-2">
<input-holder label="Help Desk" style="height:50px;">
<pessoa-funcao-select :funcao="'Help Desk'" :clearable="true" />
</input-holder>
</div>
<div class="col-md-2">
<input-holder label="Supervisor" style="height:50px;">
<pessoa-funcao-select :funcao="'Supervisor'" :clearable="true" />
</input-holder>
</div>
<div class="col-auto">
<q-btn
color="primary"
style="margin-left: auto; margin-right: auto;"
#click="search = false"
>FILTER</q-btn>
</div>
</div>
</q-card>
Request the API (I know it is wrong, I would like to know how to request with the parameter according to what the GET requests)
mounted() {
this.refresh()
},
methods: {
refresh () {
this.$axios.get()
this.$axios.get("/Operacional/GetRelatorio").then(res => {
this.prazos = res.data
this.$refs.chart1.updateSeries([{
name: 'NO PRAZO',
data: [this.prazos.noPrazo, this.prazos.emDia, this.prazos.atrasadas]
}])
})
this.$axios.get("/Operacional/GetAprovadas").then(res => {
this.os = res.data
})
this.$axios.get("/Operacional/GetPendenciasOS").then(res => {
this.os = res.data
this.$refs.chart4.updateSeries([{
name: 'EM DIA',
data: [ this.os.emdiaPendencia, this.os.emdiaSPendencia],
},{
name: 'ATRASADAS',
data: [ this.os.atrasadasPendencia, this.os.atrasadasSPendencia],
}
])
})
This is how you get that value you selected, let's say you want to use 'situacao'.
and pass that value to your backend via GET parameters:
refresh () {
this.$axios.get()
var selectedSituacao = this.situacao;
var url = "/Operacional/GetRelatorio?ID=" + selectedSituacao;
this.$axios.get(url).then(res => { .... })
// or you could do this:
var axiosParams = {
params: {
ID: selectedSituacao
}
}
this.$axios.get("/Operacional/GetRelatorio", axiosParams).then(res => { .... })
edit: Updated url get parameter situacao to ID as requested.

Fetch only items 'x' items from an api instead of all and load more content when user scrolls

I'm making a simple GK app that shows user information about countries and makes use of restcountries API.
I make request a to "https://restcountries.eu/rest/v2/all" which returns data about all countries.
But how do I make a request for just certain countries like the first 10 or 15 countries from the API , display it on the webpage or once all the content is returned, display only first 10 or 15 countries, and once the user scrolls down more content from the API is loaded?
rest countries API link : https://restcountries.eu/#rest-countries
HTML CODE:
<div class="list-of-countries">
//Countries are displayed in this block
</div>
JS CODE:
function displayCountries(countries) {
countries.forEach((country) => {
console.log(country);
let countryCard = $(`<div class="card" style="width: 18rem;">
<img src="${country.flag}" class="card-img-top" alt="${country.name} Flag">
<div class="card-body">
<h5 class="card-title">${country.name} </h5>
<p class="card-text">Population : ${country.population}</p>
<p class="card-text">Region : ${country.region}</p>
<p class="card-text">Capital : ${country.capital}</p>
</div>
</div>`);
$(".list-of-countries").append(countryCard);
});
}
window.onload = fetch("https://restcountries.eu/rest/v2/all")
.then((response) => {
if (!response.ok) {
throw Error(response.statusText);
}
return response.json();
})
.then((response) => {
displayCountries(response);
})
.catch((err) => {
console.log(err);
});

.map() nested array not working JavaScript

I am having issues with using the .map function in JavaScript to extract a nested array from an api response.
here is the JSON:
[
{
"id": 3787,
"title": "Dummy title!",
"start_time": "2020-04-25T16:54:00.000Z",
"created_at": "2020-04-25T17:22:13.315Z",
"updated_at": "2020-04-25T17:32:15.364Z",
"incident_updates": [
{
"id": 9905,
"body": "Dummy Paragraph test!",
Here is the code that I put together my script.js file:
fetch(url)
.then((response) => {
if (!response.ok) {
throw Error("ERROR");
}
return response.json();
})
.then((data) => {
console.log(data);
const html = data
.map((item) => {
console.log(item.incident_updates[0]);
return `<div class="card card-space">
<div class="card-body">
<h5 class="card-title">${item.title}</h5>
<h6 class="card-subtitle mb-2 text-muted">${item.start_time}</h6>
<p class="card-text">${item.incident_updates.body}</p> // issues with this
</div>
</div>`;
})
.join("");
for whatever reason everything else is working fine like item.title & item.start_time however item.incident_updates.body doesn't work at all and in my HTML file it says "Undefined".
How am I able to get render the data from incident_updates.body?
Thanks guys!
incident_updates is an array, so you will need an index first to get the right element. Try something like this where i is the index of the element you're after:
var i = 0;
item.incident_updates[i].body
Since item.incident_updates is an array you can use map for that
const html = data
.map((item) => {
console.log(item.incident_updates[0]);
return `<div class="card card-space">
<div class="card-body">
<h5 class="card-title">${item.title}</h5>
<h6 class="card-subtitle mb-2 text-muted">${item.start_time}</h6>
{item.incident_updates.map((data)={return(<p class="card-text">${data.body}</p>)})}
</div>
</div>`;
})

How to use spinner to show axios status on a specific button

i am using a v-for to display list of product from an api request, the product card contains three buttons, one of the Adds item to cart,with a shopping-cart icon.
i want it so that when a user clicks the add to cart button, the shopping-cart icon changes to a spinner icon
I try declaring a "loading" in the data object, default set to false, so in my add to cart function, before the function is called, loading is set to true,
And in my template i use a v-show="loading" which set the visibility of the fa-spin to true if loading is true
//template
<template>
<div class="row">
<div v-for="product in products" v-bind:key="product_slug"
class="col-md-auto mx-auto card text-center card-product">
<div class="card-product__img">
<img class="card-img" src="img/product/product1.png" alt="">
<ul class="card-product__imgOverlay">
<li>
<button><i class="ti-search"></i></button>
</li>
<li>
<button #click="addToCart(product.id, product.slug, product.price)"><i
class="ti-shopping-cart"></i> <i v-show="loading" class="fa fa-spinner fa-spin"></i>
</button>
</li>
<li>
<button><i class="ti-heart"></i></button>
</li>
</ul>
</div>
<div class="card-body">
<p>Accessories</p>
<h4 class="card-product__title">{{ product.slug }}</h4>
<p class="card-product__price">₦ {{ product.price}}</p>
</div>
</div>
//script
<script>
export default {
data() {
return {
loading: false,
products: [],
product: {
"id": '',
"slug": '',
"product_image_1": '',
"product_image_2": '',
"product_image_3": '',
"product_image_4": '',
"price": '',
"qty": '',
"stock_status": '',
"sku": '',
"short_description": '',
"description": '',
},
product_slug: '',
pagination: {},
}
},
created() {
this.fetchProduct();
},
methods: {
fetchProduct(page_url) {
//assign variable to this
let vm = this;
// check if page url exist, = page url else = /api/shop
page_url = page_url || '/api/shop';
fetch(page_url)
.then(res => res.json())
.then(res => {
this.products = res.data;
vm.makePagination(res.links, res.meta);
})
.catch(err => console.log(err));
},
makePagination(links, meta) {
//Make an object made up of meta, page details from the api response
let pagination = {
current_page: meta.current_page,
last_page: meta.last_page,
next_page_url: links.next,
prev_page_url: links.prev,
};
// Set the object to the pagination value
this.pagination = pagination;
},
addToCart(id, slug, price) {
this.loading = true;
axios.post('/api/cart', {
id: id,
name: slug,
price: price,
})
.then(function (response) {
this.loading = false;
console.log(response.data);
})
.catch(function (err) {
this.loading = false;
this.addToCart = err;
});
}
}
}
</script>
The problems are
1) Once the add to cart button is clicked, the spinner shows in all of the product's card.
2) fa-cart icon is not hiding, shows side-by-side with the shopping-cart icon
3) fa-spin continues, even after success of api request
You need to maintain a dictionary of the loading state. In addToCart function, you need to set true for particular product id. Try this code.
addToCart(id, slug, price) {
this.loading[id] = true;
axios.post('/api/cart', {
id: id,
name: slug,
price: price,
})
.then(function (response) {
this.loading[id] = false;
console.log(response.data);
})
.catch(function (err) {
this.loading[id] = false;
this.addToCart = err;
});
}
In Fetch product function made some changes.
fetchProduct(page_url) {
//assign variable to this
let vm = this;
// check if page url exist, = page url else = /api/shop
page_url = page_url || '/api/shop';
fetch(page_url)
.then(res => res.json())
.then(res => {
this.products = res.data;
this.products.filter(function (item) {
vm.loading[item.id]=false;
return item;
})
vm.makePagination(res.links, res.meta);
})
.catch(err => console.log(err));
},
html changes.
<button #click="addToCart(product.id, product.slug, product.price)"><i
class="ti-shopping-cart"></i> <i v-show="loading[product.id]" class="fa fa-spinner fa-spin"></i>
</button>

Categories

Resources