VueJS: JSON objects are not showing in my code - javascript

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)
}
}
}

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 use v-for 2 times to get specific values in check-box action form?

I am new to Vue js. I am trying to do an action form for the rest of API. I don't know how to get the data of name and location only. I was trying to use slice in Array, but it does not work.
My action form:
<div class="form-group">
<label class="required"> Social Media </label>
<b-form-checkbox v-for="event in events" :key="event._id" :value="event" v-model="selected">
{{event.name}}, {{event.location}}
</b-form-checkbox>
<span class="mt-3">Selected: <strong>{{ selected }}</strong></span>
</div>
My Vue instance
export default {
data() {
return {
events: [{
"_id": "d4d81da6-b453-4a31-999f-a2ea04848ee9",
"name": "A",
"location": "US",
"__v": 0
},
{
"_id": "91205d34-4480-4e4e-bdf7-fe66e46922b0",
"name": "B",
"location": "Korea",
"__v": 0
},
{
"_id": "0b168c44-4f38-4f86-8ee6-e077333aca95",
"name": "C",
"location": "Japan",
"__v": 0
}],
selected: ''
};
}
}
The Output when checking the first option of the checkbox:
Selected: ["_id": "d4d81da6-b453-4a31-999f-a2ea04848ee9", "name": "A", "location": "US", "__v": 0]
Expected output when checking the first option of the checkbox:
Selected: [ "name": "A", "location": "US" ]
You can create the necessary structure within the :value="" assignment.
<b-form-checkbox v-for="event in events" :key="event._id" :value="{ name: event.name, location: event.location }" v-model="selected">
{{event.name}}, {{event.location}}
</b-form-checkbox>
Firstly make Selected:false boolean ... then make a button and on click it'll get to a function which will accepts a parameter, iterate your array and select an object which is matching with the parameter
private selectFun(item){this.events.filter(val=>{val._id===item._id})//and then whatever}

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

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

React cannot map through prop array

I fetch an api on componentDIdMount() then store the json to a state then I pass that state as a prop, I have no problem showing the data except on arrays.
<Component details={this.state.details} />
json:
{
"adult": false,
"backdrop_path": "/qonBhlm0UjuKX2sH7e73pnG0454.jpg",
"belongs_to_collection": null,
"budget": 90000000,
"genres": [
{
"id": 28,
"name": "Action"
},
{
"id": 878,
"name": "Science Fiction"
},
{
"id": 35,
"name": "Comedy"
},
{
"id": 10751,
"name": "Family"
}
]
}
then I try to map the genres:
<div className={style.genre}>
{details.genres.map(g => (
<span key={g.id}>{g.name}</span>
))}
</div>
But then I get Cannot read property 'map' of undefined, I don't know why this is happening because I'm able to do details.budget
It's trying to read data before you get the result from api.
so write the map function as
{details&&details.genres&&details.genres.map(g => (
<span key={g.id}>{g.name}</span>
))}
In react Initially when component is mounted, render() function is called and then componenentDidMount() is called in which you fetch data. So Initially details is empty. So you need to write the condition.

React would not access nested state

I have set React state to data from an API
this.setState({loan: response.data})
response.data is a nested object
{
application: {
amount: 20,
interest: 10,
guarantor: {
firstName: "John",
lastName: "Doe"
}
},
userId: "123"
}
Normally inside the render function i can access
<p>{this.state.loan.userId}</p>
<p>{this.state.loan.application.amount}</p>
<p>{this.state.loan.application.guarantor.firstName}</p>
Now I can only access the first child of the loan. Except i practically set the state for each individual item in the object. Note console.log(this.state.loan.application.guarantor) works fine.
This is the API call
fetch(`http://localhost:8000/api/v1/loans/${this.state.id}`)
.then(res => {
return res.json();
}).then(response => {
this.setState({loan: response.data});
})
.catch(err => console.log(err));
const {loan} = this.state;
<div className="col-md-4">
<h5 className="title">Full Name</h5>
<p>{loan.fullName}</p>
<h5 className="title mt-3">Account Number</h5>
<p>{loan.accountNumber}</p>
<h5 className="title mt-3">Phone Number</h5>
<p>Phone Number</p>
</div>
<div className="col-md-4">
<h5 className="title">Loan Amount</h5>
<p>
{(loan.application.amount).toLocaleString("en-NG", {
style: "currency",
currency: "NGN"
})}
</p>
<h5 className="title mt-3">Interest Rate</h5>
<p>{loan.interestRate}%</p>
<h5 className="title mt-3">Duration</h5>
<p>{loan.duration} Months</p>
</div>
The response from API call
{
"application": {
"guarantor1": {
"fullName": "Ayebakuro Ombu",
"residentialAddress": "30 Udengs Eradiri Avenue Off Azikoro Village Road",
"occupation": "Accountant",
"netIncome": "50000",
"placeOfWork": "Dreamworld",
"employer": "Ayebakuro Ombu",
"relationship": "Employer",
"bvn": "0101010101",
"bank": "GTBank",
"accountNumber": "10101010101",
"phoneNumber": "010101010101"
},
"guarantor2": {
"fullName": "Ayebakuro Ombu",
"residentialAddress": "B48 Copa Cobana Estate, Wumba, Lokogoma",
"occupation": "business man",
"netIncome": "500000",
"placeOfWork": "Dreamworld",
"employer": "SafeScrow Tech",
"relationship": "Employer",
"bvn": "0101010101",
"bank": "GTBank",
"accountNumber": "0101010101",
"phoneNumber": "0101010101"
},
"mode": {
"name": "DreamWorld Savings And Loans Ltd",
"address": "30 Udengs Eradiri Avenue Off Azikoro Village Road",
"netIncome": "50000"
},
"bankDetails": {
"bank": "Parallex Bank",
"accountNumber": "0101010101",
"bvn": "0101010101"
},
"amount": 200000,
"number": "25642",
"date": "2019-03-22T02:37:58.069Z",
"purpose": "For debt payment"
},
"approval": {
"amount": 0,
"status": "Pending"
},
"issue": {
"status": false
},
"payment": {
"schedule": [],
"completed": false
},
"_id": "5c944a86abf7ea09c40301e5",
"accountNumber": "1000000002",
"fullName": "Ayebakuro Ombu",
"type": "Business",
"duration": 5,
"interestRate": 10,
"__v": 0
}
The error: LoanPage.js:61 Uncaught TypeError: Cannot read property 'amount' of undefined
at LoanPage.render (LoanPage.js:61)
Logging this.state.loan.application.amount logs correctly
When a component is rendered (like the following code), React calls the render method of corresponding component immediately.
ReactDom.render(<LoanPage />, element);
Event if you were to execute a asynchronous fetch in constructor, or componentWillMount method, that wouldn't prevent the React system from executing render.
This is how you should approach this problem. In constructor / componentWillMount, you should set this.state.loading = true, and then fire the fetch call. In the .then part of fetch call, setState to clear the loading flag like this:
this.setState({
loading: false,
loan: response.data
});
The render method of LoanPage can now benefit from the knowledge of 'fetch call in progress' like this:
render() {
if(this.state.loading) {
return (<h3>Loading...</h3>);
}
return (
<div> Loan amount is {this.state.loan.application.amount} </div>
);
}
You can change the first part of render (in if condition) to display a spinner or some equivalent. You should change the second part to render everything that you are rendering now.

Categories

Resources