How to loop through and display API data containing a JavaScript Object - javascript

Live CodeSandbox link.
I'm trying to access and pull in data from an API, specifically the price text value below:
"price": {
"currency": "CAD",
"text": "500"
},
JS code (everything else pulls in fine, just the <p>${product.price.text}</p> I'm having trouble with):
// Fetch Data
async function getData() {
const res = await fetch(url);
const data = await res.json();
let output = "";
// Loop through first 'groups' array
data.groups.map(function (group) {
// Loop through each 'equipments' array
group.equipments.map((product) => {
// Define below variable to match cat products only
const catProducts =
product["dealer-name"] === "CATERPILLAR FINANCIAL SERVICES CORPORATION";
// If the dealer name is everything but cat products (aka only battlefield products)..
if (!catProducts) {
// Loop through each 'photos' array
product.photos.map(() => {
// Then output the data
// If year is undefined, replace with empty string
output += `
<div class="card">
<img class="img-fluid" src=${product.photos[0].text} alt=${
product.model
} />
<div class="card--body">
<h3>${product.year ?? ""} ${product.manufacturer} ${
product.model ?? ""
}</h3>
<p>${product.city ?? "City Not Available"}, ${product.state}</p>
<p>${product.hours} hours</p>
<p>${product.price.text}</p> <--- Not working
<a href='https://used.ca/en/${product["group-code"]}/${
product["serial-number"]
}' class="btn btn-primary">View Details</a>
</div>
</div>
`;
});
}
});
});
// Add to slider
$(".used-slider").slick("slickAdd", output);
}
getData();
Currently throwing a console error: "app.js:26 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'text')"
API structure:
{
"version": "5",
"company-code": "N001",
"language-code": "en-CA",
"total-count": 148,
"created-date": "2021-09-22T18:12:03.2387128+00:00",
"template-identifier": "4da31196-7f4b-4529-b832-90d40ef4a024",
"group-type-code": "ProductFamilyCategory",
"groups": [
{
"group-code": "Backhoe Loaders - Chargeuses-pelleteuses",
"group-name": "Backhoe Loaders",
"group-display-name": "Backhoe Loaders",
"count": 7,
"equipments": [
{
"id": "4536522",
"dealer-name": "DEALER NAME",
"GroupName": "Compact Track Loader",
"product-family-code": "CTL",
"product-family": "COMPACT TRACK LOADER",
"product-family-display-name": "Compact Track Loader",
"manufacturer-code": "CAT",
"manufacturer": "MANUFACTURER",
"model": "RUBBER TRACKS FOR CTL 259D ",
"serial-number": "XXXXX",
"year": "2016",
"hours": 0,
"city": "Ville St-laurent, Montréal",
"state": "QC",
"certification": "None",
"availability": "Available",
"price": {
"currency": "CAD",
"text": "500"
},
"product-family-categories": {},
"photos": [
{
"text": "https://s7d2.scene7.com/is/image/CatUsedProduction/wtk?JHNyYz04ZjRjN2UyYzJkMzFmZWNjY2NiZDQ1MTc2NTA4MGY3MiYkdHh0PUJBVFRMRUZJRUxEJTIwRVFVSVBNRU5UJTIwUkVOVEFMUyUyMCUyOFFVJUMzJTg5QkVDJTI5JjUxMTY2"
}
]
}
]
}
]
}
Anyone know why I'm unable to access the price text value but can access all the others?

The error implies that some products don't have a price property. You need to check for this before trying to access the text property. You can display a default placeholder instead.
You can use optional chaining to simplify this.
<p>${product.price?.text || "unknown"}</p> <--- Not working

Related

Filter data using a multiselect. When selecting 2 or 3 options result need to throw only registers where options together exist

thank you in advance for reading me. So I have been working in a filte. Right now my filter works, however doesn't do what I want. The current status is. When I select 2 options or more. I get all the values inside the data that contains either optionA oder optionB.
See my example data below:
{
"_uid": "1",
"body": [
{
"_uid": "2",
"name": "John",
"image": {
"id": 6807178,
"filename": "https://",
"copyright": "",
"fieldtype": "asset",
"is_external_url": false
},
"gewerk": "Project Owner",
"skill": ["vuejs", "react", "symfony"],
"component": "person",
},
{
"_uid": "3",
"name": "Jean",
"image": {
"id": 6807182,
"filename": "https://",
"copyright": "",
"fieldtype": "asset",
"is_external_url": false
},
"gewerk": "UI",
"skill": ["svelte"],
"component": "person",
},
{
"_uid": "4",
"name": "Martha",
"gewerk": "Frontend",
"skill": ["vuejs", "react"],
"component": "person",
},
{
"_uid": "5",
"name": "Tom",
"gewerk": "UI",
"skill": ["svelte", "angular", "vuejs"],
"component": "person",
}
],
}
With that being says when I filter using this example combi(screenshot). I get Martha, Tom and John as a result. When what I actually want is to have only Tom as a result. because only Tom have both criterias together inside his skills data.
This is my current computed function:
filterPersonSkill() {
return this.getComponentPerson.filter((e) =>
e.skill.map((skill) => this.multiValue.includes(skill)).includes(true)
);
}
At the beginning I used includes instead of map and that worked half. Because I was getting the result only if I selected in the same order(in the multiselect) as the array skills was appearing. Example below
filterPersonSkill() {
return this.getComponentPerson.filter((e) =>
e.skill.includes(...this.multiValue)
);
}
Thank in advance for the advice and reading me.
I think, it will be much simpler, if you add checkbox for the user to use "exact" filtering, i.e. results which include only selected tags.
With such a checkbox you can do something like this:
// your vue component
export default {
data() {
return {
exactMatch: true,
}
},
methods: {
filterPersonSkillExactMatch() {
const result = [];
for (const p of this.getComponentPerson) {
if (p.skill.length === this.multiValue.length
&& this.multiValue.every(val => p.skill.includes(val))) {
result.push(p)
}
}
return result
}
// somewhere in your code (either computed prop or method):
filteredPersons() {
if (exactMatch) {
return this.filterPersonSkillExactMatch()
}
return this.filterPerson()
}
}
}

How to create pagination using orderByChild, equalTo and endBefore from Firebase Query? React Native

I am working in a pagination method where I want to load more data based on category type. Currently I am getting an Error:
endBefore: Starting point was already set (by another call to endAt, endBefore or equalTo).
I know I can't use endBefore and equalTo but I can't find a way to get what I want. If there is any approach to solve this will be amazing. Here is what I have of code.
function getPost() {
const vibesQuery = query(
vibesRef,
orderByChild("category"),
equalTo(categoryType),
limitToLast(2)
);
onValue(vibesQuery, (snapshot) => {
const data = snapshot.val();
if (data) {
const vibesArray = Object.values(data);
setVibes(vibesArray.reverse());
setLastVibe(vibesArray[vibesArray.length - 1][sortingType]);
}
});
function getMorePosts() {
const vibesQuery = query(
vibesRef,
orderByChild("category"),
equalTo(categoryType),
endBefore(lastVibe),
limitToLast(2)
);
onValue(vibesQuery, (snapshot) => {
const data = snapshot.val();
if (data) {
const vibesArray = Object.values(data);
setVibes([...vibes, ...vibesArray.reverse()]);
setLastVibe(vibesArray[vibesArray.length - 1][sortingType]);
}
setIsMoreLoading(false);
});
}
My data structure is:
{
"-LbzPjzin65Rt3ZIK1Lo": {
"caption": "Great",
"category": "OUTDOORS",
"cityVibe": "Chino",
"stateVibe": "CA",
"creationDate": 1573942298.999069,
"fullname": "Bryant",
},
"-LbzPjzin65Rt3ZIK1Io": {
"caption": "Amazing",
"category": "OUTDOORS",
"cityVibe": "Chino",
"stateVibe": "CA",
"creationDate": 1576382057.7584639,
"fullname": "Bravo",
},
"-LbzPjzin65Rt3ZIK1Ao": {
"caption": "Beatiful",
"category": "OUTDOORS", <-- THIS IS MY (categoryType)
"cityVibe": "Chino",
"stateVibe": "CA",
"creationDate": 1586638159.889124, <-- THIS IS MY (lastVibe)
"fullname": "Bravo",
},
"-LbzPjzin65Rt3ZIK1Bo": {
"caption": "Fantastic",
"category": "OUTDOORS",
"cityVibe": "Chino",
"stateVibe": "CA",
"creationDate": 1604361787.34916,
"fullname": "Bravo",
},
}
If there is any additional information, let me know and thank you so much!
There is no way to pass multiple property values to filter on. What you can do in this case, it use Firebase's startAt/endBefore overload that takes two parameters. The first value is the property value you want to start/end at, but the second parameter is the key of the node you want to start/end at in case there are multiple matches on the first value.
So if you have the key of the last vibe in a variable called lastVibeKey, you can do:
query(
vibesRef,
orderByChild("category"),
endBefore(categoryType, lastVibeKey),
limitToLast(2)
);

VueJS: JSON objects are not showing in my code

I have API that stores JSON data as shown in JSON body below... I wanted to show the data amount stored in installments but it didn't work good because its showing me each amount value two times and I couldn't figure out the problem here.
{
"response": [{
"floors": [{
"flats": [{
"status": "sold",
"price": "150000",
"currency": "USD",
"end_date": "Not Set",
"buyer": "ella",
"buyer_phone_number": "002822128",
"receipt_number_field": "553108012022",
"size_unit": "M",
"_id": "61d9b61397e87e39832a5abb",
"flat_number": 1,
"description": "This is a newly created flat.",
"city": "NY",
"payment": {
"installment_payment": {
"installments": [{
"amount": "1344",
"date": "2022-01-13",
"is_paid": false
},
{
"amount": "444",
"date": "2022-01-24",
"is_paid": false
},
{
"amount": "44444",
"date": "2022-01-17",
"is_paid": false
}
],
"remaining": "150000"
},
"paid_amount": "1234"
},
"floor": "61d9b61397e87e39832a5aba",
"building": "61d9b61397e87e39832a5ab9",
"size": "176.25",
"directions": " south",
"createdAt": "2022-01-08T16:04:43.557Z",
"updatedAt": "2022-01-08T16:22:29.220Z",
"__v": 0
},
my code:
<div v-for="(flat,index) in Flats" :key="index">
<div v-for="(find,indexT) in flat.payment" :key="indexT" >
<div v-if="flat.payment.installment_payment">
<div v-for="(find,indexT) in flat.payment.installment_payment.installments" :key="indexT">
<div v-if="find.amount >0">
<p> {{find.amount}}$ amount </p>
</div>
</div>
</div>
</div>
</div>
p.S: I stored my API data in array Flats
This will probably work, but it's untested.
You generally do not want to use v-if inside of v-for; instead, you should filter the data first and use the result in the v-for loop. [reference]
Also, since each flat has an _id field, you can use that instead of the index for the top level :key attribute.
<div v-for="flat in flatsWithPayments" :key="flat._id">
<div v-for="(installment, index) in getInstallmentsWithPaymentGTZero(flat.payment.installment_payment.installments)" :key="index">
<p> {{installment.amount}}$ amount </p>
</div>
</div>
Obviously, replace Flats with your data, but also note that in order to compare the payment amount, it needs to be converted with either Number(), parseInt() or parseFloat()
// Flats = { ... }
export default {
computed: {
flatsWithPayments() {
return Flats.filter(f => f.payment != undefined)
}
},
methods: {
getInstallmentsWithPaymentGTZero(installments) {
return installments.filter(i => Number(i.amount) > 0)
}
}
}

Loop through JavaScript array accessing objects with different IDs

I'm having trouble going through the data because of the ID 29450 and 3000 in this JSON data sample. My whole database has 1500 ID's. Now I want to print the data ['Id', 'Description', 'StartDate'] in the log from both ID's.
I'm a bit stuck now so hopefully somebody can help on the right track.
Thank you in advance. :)
const { Parser } = require('json2csv');
var fs = require('fs');
var fields = ['Id', 'Description', 'StartDate'];
var data = [
{
"29450": {
"Id": "29450",
"Description": "Lasser Niveau 4",
"StartDate": "0001-01-01T00:00:00",
"EndDate": "0001-01-01T00:00:00",
"Company": "",
"ResponsibilityCenter": "",
"FunctionGroup": "",
"City": "",
"Territory": "",
"Country": "",
"Attributes": {
"Name": {
"Description": "",
"Name": ""
},
"WERKTIJDEN": {
"Description": "Anders",
"Name": "Werktijden"
}
},
"RequestNo": ""
},
"3000": {
"Id": "3000",
"Description": "Lasser Niveau 4",
"StartDate": "0001-01-01T00:00:00",
"EndDate": "0001-01-01T00:00:00",
"Company": "",
"ResponsibilityCenter": "",
"FunctionGroup": "",
"City": "",
"Territory": "",
"Country": "",
"Attributes": {
"Name": {
"Description": "",
"Name": ""
},
"WERKTIJDEN": {
"Description": "Anders",
"Name": "Werktijden"
}
},
"RequestNo": ""
},
];
const json2csvParser = new Parser({fields, unwind: ['Id','Description','StartDate'], unwindBlank: true });
const csv = json2csvParser.parse(data);
fs.writeFile('file.csv', csv, function(err) {
if (err) throw err;
console.log('file saved');
});
Expected output:
Instead of...
const csv = json2csvParser.parse(data);
...use...
const csv = json2csvParser.parse(Object.keys(data[0]).map(key => data[0][key]));
Full explanation
Your data is in a strange format. It's an array of one object. I'm not sure if there would ever be another object in the array, but I have to assume that there won't be. So data[0] is the only relevant object here.
This data[0] is what I would call a index. It is an object that has properties that are the primary keys of the objects contained within. It's useful because you can access data[0]['1234'] to obtain the object with id '1234' in constant time. It's not clear if it would ever contain any other properties, but again, I'll assume that it won't because it looks a lot like an index.
You want to begin by getting all the keys of that one-and-only object of interest with Object.keys(data[0]). If you just map these keys to an array of the value of those properties, then you turn the index back into an regular unindexed array of objects -- and this is what json2csv expects as input.
The meat of the fix is a technique like this:
let unindexed = Object.keys(indexed).map(key => indexed[key])
It essentially turns this kind of structure...
var indexed = {
"29450": {
"Id": "29450",
"Description": "Lasser Niveau 4"
},
"3000": {
"Id": "3000",
"Description": "Lasser Niveau 4"
}
};
...into this kind of structure...
var unindexed = [
{
"Id": "29450",
"Description": "Lasser Niveau 4"
},
{
"Id": "3000",
"Description": "Lasser Niveau 4"
}
];
I think your problem is that you want to access the object but don't know its Id. You'll have to define how the object is to be distinguished from any other allowable properties in the containing object. Here's an example that just uses the first key as the one that specifies the object.
Note, this code is intended to be run in a node.js environment and requires the json2csv package npm i json2csv --save
const { Parser } = require('json2csv');
var fs = require('fs');
var fields = ['Id', 'Description', 'StartDate'];
var data = [
{
"29450": {
"Id": "29450",
"Description": "Lasser Niveau 4",
"StartDate": "0001-01-01T00:00:00"
},
"RequestNo": ""
},
{
"3000": {
"Id": "3000",
"Description": "Lasser Niveau 4",
"StartDate": "0001-01-01T00:00:00"
},
"RequestNo": ""
}
];
function getContainedObjectId(container) {
return Object.keys(container)[0];
}
var flattened = data.map(container => container[getContainedObjectId(container)]);
const json2csvParser = new Parser({ fields, unwind: ['Id', 'Description', 'StartDate'], unwindBlank: true });
const csv = json2csvParser.parse(flattened);
fs.writeFile('file.csv', csv, function (err) {
if (err) throw err;
console.log('file saved');
});
Here we rely on the ID being the first key. You'll have to define for us how to distinguish the ID from any other properties that may exist.
Here's another way that is potentially more robust. Search for the first key that looks like an integer (consists of digits 0-9) whose property name matches its value's Id property.
function getContainedObjectId(container) {
return Object.keys(container).filter(key => /^[0-9]+$/.test(key) && container[key].Id === key)[0];
}

JSON parsing in JS

I am getting a JSON in response from server:
{
"width": "765",
"height": "990",
"srcPath": "http://192.168.5.13:8888/ebook/user_content/_ADMIN_/_MERGED_/1273.pdf",
"coverPage": "",
"documents": [
{
"index": "1",
"text": "Archiving Microsoft® Office SharePoint® Server 2007 Data with the Hitachi Content Archive Platform and Hitachi Data Discovery for Microsoft SharePoint",
"type": "doc",
"id": "HDS_054227~201106290029",
"children": [
{
"text": "Page 1",
"leaf": "true",
"pageLocation": "http://192.168.5.13:8888/ebook/user_content/_ADMIN_/_IMAGES_/HDS_054227~201106290029/image_1.png"
},
{
"text": "Page 2",
"leaf": "true",
"pageLocation": "http://192.168.5.13:8888/ebook/user_content/_ADMIN_/_IMAGES_/HDS_054227~201106290029/image_2.png"
}
]
},
{
"index": "11",
"text": "Brocade FCoE Enabling Server I/O Consolidation",
"type": "doc",
"id": "HDS_053732~201105261741",
"children": [
{
"text": "Page 1",
"leaf": "true",
"pageLocation": "http://192.168.5.13:8888/ebook/user_content/_ADMIN_/_IMAGES_/HDS_053732~201105261741/image_1.png"
},
{
"text": "Page 2",
"leaf": "true",
"pageLocation": "http://192.168.5.13:8888/ebook/user_content/_ADMIN_/_IMAGES_/HDS_053732~201105261741/image_2.png"
}
]
}
]
}
And I want to get pagelocation of the children.
Can anyone tell me how to do this?
Hi
i also want to get indexes from this and then want to get pagelocations of that particular children. Can you tell me how would i do that?
And also when i when i am getting indexes array it is returning me ,, only and not the index nos.
I am using following code for that :
indexes=response.documents.map(function(e){ return e.children.index; })
Thanks & Regards
If you're interested in simply retrieving all the page locations, you can do it using filter:
var locations = [];
json.documents.forEach(function(e,i) {
e.children.forEach(function(e2,i2) {
locations.push(e2.pageLocation);
)}
});
// returns flat array like [item1,item2,item3,item4]
You can get an array of arrays using map:
var locations = [];
var locations = json.documents.map(function(e) {
return e.children.map(function(e2) {
return e2.pageLocation;
});
});
// returns 2-dimensional array like [[item1,item2],[item1,item2]]
Your json response is an appropriate javascript object So you can access all elements of the object like you do as in back end.
here, you have an array of object of the type documents and each document object has array of objects of the type children. so
syntax would be
myjson.documents[0].children[0].pagelocation
( = http://192.168.5.13:8888/ebook/user_content/_ADMIN_/_IMAGES_/HDS_054227~201106290029/image_1.png)
will give you the very first page location..
and so on

Categories

Resources