I'm a bit struggling with rendering nested object in my front end. I know there is a map function might be helpful, but I'm not sure how I can get it to work in my case (with renderItem). The back end I'm using are Rest API framework and Django.
This is what JSON structure looks like.
{
"id": 1,
"name": "Job 1",
"address": [
{
"id": 4,
"street": "65 Karamea Street",
"suburb": "Beautiful Surburb",
"town": "Christchurch",
"postcode": "8001",
"address_type": "h"
}
],
"franchise": {
"id": 2,
"name": "Company ABC",
"person": 2,
"legal_name": "Company ABC Ltd.",
"created": "2019-08-09T09:40:35.697582Z",
"modified": "2019-09-23T03:21:43.258983Z",
"region": {
"id": 4,
"region": "QueensTown"
}
},
"customer1": {
"id": 1,
"last_name": "Tom",
"first_name": "Wilson",
"address": [
{
"id": 11,
"street": "1 Sunset Road",
"suburb": "Auckland",
"town": "Auckland",
"postcode": "1234"
}
]
}
This is the React code:
import React from 'react';
import { List, Card } from 'antd';
const Job = props => {
return (
<React.Fragment>
<List
grid={{
gutter: 16,
xs: 1,
sm: 2,
md: 4,
lg: 4,
xl: 6,
xxl: 3,
}}
dataSource={props.data}
renderItem={item => (
<List.Item>
<Card title={<a href={`/job/${item.id}`}>{item.customer1.first_name}</a>}>{item.franchise.legan_name}
<span> | Based on </span>
{item.name}
</Card>
</List.Item>
)}
/>
</React.Fragment>
);
};
export default Job;
Within the card object, I wish to render the first_name of customer1 and the legal_name of franchise. Apparently item.customer1.first_name and item.franchise.legal_name aren't working.
I'm NEW to React, any help would be much appreciated! It would be great if you could provide some actual code just to be specific.
Many thanks in advance.
You are not sending array of jobs but an object to List.
Changes done:-
1) Converted the passed object into array.
2) Corrected name of attribute item.franchise.legal_name
Below is the working code:-
import React from "react";
import ReactDOM from "react-dom";
import { List, Card } from "antd";
class App extends React.Component {
render() {
return (
<React.Fragment>
<List
grid={{
gutter: 16,
xs: 1,
sm: 2,
md: 4,
lg: 4,
xl: 6,
xxl: 3
}}
dataSource={new Array(this.props.data)}
renderItem={item => (
<List.Item>
<Card
title={
<a href={`/job/${item.id}`}>{item.customer1.first_name}</a>
}
>
{item.franchise.legal_name}
<span> | Based on </span>
{item.name}
</Card>
</List.Item>
)}
/>
</React.Fragment>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
In order to show your JSON data you should use map in your render()
This is how map works
render(){return(
< div>{this.state.mydata.map(m=><div>{m. name < /div> })
< /div>
);
Now in order to use your nested data
In the map you can map m again (like m.map(...) )
Hope you get the idea and works for you
Related
im learning about vuejs 3 and for example i want to show a chartjs with a combo to filter data. (Without the combo, everything works correctly)
i have a parent component chartjs.vue where import the chartjs and the combo. when i select a year, i change the variable and show it on the template
<script setup>
import ChartJsBarChart from '#/views/charts/chartjs/ChartJsBarChart.vue'
import SelectYear from '#/componentes/selectYear.vue'
const api = ref('exp')
const year = ref([])
function selectYear(x) {
year.value = x
}
</script>
<template>
<!-- 👉 Latest Statistics -->
<VCol cols="24" md="12">
<VCard>
<VCardItem class="d-flex flex-wrap justify-space-between gap-4">
<VCardTitle>Choose a year</VCardTitle>
</VCardItem>
<VCardText>
<SelectAno #input="selectAYear" />
</VCardText>
</VCard>
</VCol>
<VCol cols="24" md="12">
<VCard>
<VCardItem class="d-flex flex-wrap justify-space-between gap-4">
<VCardTitle>Total</VCardTitle>
</VCardItem>
<VCardText>
<ChartJsBarChart :yearSelected="year" :url="api" />
</VCardText>
</VCard>
</VCol>
</template>
one child component with a select (to try props and emit) selectYear.vue
<script setup>
import { ref, defineEmits, watch } from 'vue'
const emit = defineEmits(['input'])
let selected = ref([])
const years = [
'2005',
'2008',
'2009',
'2010',
'2011',
'2012',
'2014',
'2015',
'2016',
'2017',
'2018',
'2019',
'2020',
'2021',
'2022',
'2023',
]
watch(
() => selected.value,
(newValue, oldValue) => {
change(newValue)
},
)
const change = val => emit('input', val)
</script>
<template>
<VSelect
v-model="selected"
:items="years"
label="choose a year"
/>
</template>
and last child component with the chartjs ChartJsBarChart.vue
<script setup>
import BarChart from '#/libs/chartjs/components/BarChart'
import axios from '#axios'
import { ref, onMounted, computed } from "vue"
import { useStatesStore } from '#/store/states'
const props = defineProps({
url: {
type: null,
required: true,
},
yearSelected: {
type: null,
required: true,
},
})
const apiData = ref([]) //data from API
const data = ref({}) // data parsed to chartjs
const store = useStatesStore()
const states = ref(store.states) // legend
const filterByYear = computed(() => {
return apiData.value.filter(item => item.year === '2005')
})
onMounted(async () => {
await axios
.get('/api/dashboard/expProvActiv')
.then(res => {
apiData.value = res.data['hydra:member']
})
})
</script>
<template>
{{ props.yearSelected }}
<hr>
{{ apiData }}
<BarChart
:height="400"
:chart-data="data"
/>
</template>
the result (shortened) of {{ apiData }} with hundred of items is:
[ { "state": "state 1", "activity": "string", "subactivity": "string", "year": 2015, "surface": "3.5500", "total": 3, "rcs": 3 }, { "state": "state 2", "activity": "string", "subactivity": "string", "year": 2016, "surface": "10.9400", "total": 13, "rcs": 13 }]
if i try to show filterByYear, the first time i have not data and how can i do to call filterByYear when i change the year?
[answer myself] the year was string instead number
how can i update the child component BarChart to update the information?
thank you!
import {Entity, model, property} from '#loopback/repository';
#model()
export class Misc extends Entity {
#property({
type: 'number',
id: true,
generated: true,
})
id?: number;
#property({
type: 'array',
itemType: 'number',
required: true,
})
members: number[];
constructor(data?: Partial<Misc>) {
super(data);
}
}
export interface MiscRelations {
// describe navigational properties here
}
export type MiscWithRelations = Misc & MiscRelations;
Above is the model for misc API. I am using PostgreSQL.
I have inserted data in the table. Result of GET request from this table is as following -
[
{
"id":1,
"members":[
1,
2,
3
]
},
{
"id":2,
"members":[
1,
2,
3,
4,
5
]
},
{
"id":3,
"members":[
10,
20,
30,
40,
50
]
},
{
"id":4,
"members":[
100,
200,
300,
400,
500
]
},
{
"id":5,
"members":[
1,
2,
3,
500,
1000,
5000
]
}
]
I want to get the records who have members with value 1, so I applied a filter like this -
http://localhost:3000/miscs?filter[where][inq][members]=1
But this isn't working. If there is no way to execute such a query then can I do some change in the model to adjust its type such that it can accept CSV values and also can filter those data?
Please help. Thanks in advance!
For the Postgresql connector, use contains, which accepts an array:
?filter[where][contains][members][0]=1
- SAME AS -
{
where: {
contains: [1]
}
}
Finally, I found an answer. Regex can be used to match the record here like this
filter[where][members][regexp]=1,|1]
I have simple django api which provide a list of movies title with their ids.
I have created a movies service in type script which performs the get operation and get the list of movies title and id.
In native script I have two files, items.component.ts
import { Component, OnInit } from "#angular/core";
import { MovieService } from "../services/movie.service";
#Component({
selector: "ns-items",
moduleId: module.id,
templateUrl: "./items.component.html",
providers: [MovieService]
})
export class ItemsComponent implements OnInit {
items;
constructor(private movieService: MovieService) { }
ngOnInit(): void {
this.movieService.getMovies().subscribe(
movies => {
this.items = movies;
console.log(movies);
},
error => {
console.log('error', error);
}
);
}
}
and items.component.html
<ActionBar title="Movie Rater App" class="action-bar">
</ActionBar>
<StackLayout class="page">
<ListView [items]="items" class="list-group">
<ng-template let-item="item">
<Label [nsRouterLink]="['/item', item.id]" [text]="item.title"
class="list-group-item"></Label>
</ng-template>
</ListView>
</StackLayout>
I am getting blank screen on the app in the emulator - just the action bar title. No exception in logs
I validated API is running fine and even I can see the response in console (i.e. output of console.log(movies)).
Any help will be appreciated.
django API response:
{
"count": 5,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"title": "Rocky (1976)",
"description": "A small-time boxer gets a supremely rare chance to fight a heavy-weight champion in a bout in which he strives to go the distance for his self-respect.",
"moviePoster": "http://127.0.0.1:8000/pic_folder/rocky-1976-poster2451370.jpg",
"avg_rating": 5,
"no_of_ratings": 1,
"maxRatings": 5
},
{
"id": 16,
"title": "Rocky II",
"description": "Rocky II",
"moviePoster": "http://127.0.0.1:8000/pic_folder/rocky2.jpg",
"avg_rating": 5,
"no_of_ratings": 1,
"maxRatings": 5
}
}
You must assign the result array to items so it suppose to be,
this.movieService.getMovies().subscribe(
movies => {
this.items = movies.results;
console.log(movies);
},
error => {
console.log('error', error);
}
);
Also you may not need the StackLayout wrapping the ListView, you could remove that.
I have a model like:
var Survey = DS.Model.extend({
title: DS.attr('string'),
});
and:
var SurveySection = DS.Model.extend({
survey: DS.belongsTo('survey', {async:true}),
title: DS.attr('string'),
help_text: DS.attr('string'),
});
If i have a survey object, can I just do survey.get('survey_section') to get all the sections associated with a particular survey, because this isn't working? It doesn't even work if I add a survey_sections: DS.hasMany('survey_sections', {async:true}) to my survey model.
I should add that I'm using fixtures. When I release the app they'll still be used (ie so if the RESTAdapater would fix it, that's not a fix in my case):
Survey.reopenClass({
FIXTURES: [
{
"id": 1,
"title": "Favourite food"
},
{
"id": 2,
"title": "Sports"
}
]
});
and:
SurveySection.reopenClass({
FIXTURES: [
{
"help_text": "",
"id": 1,
"survey": 1,
"title": "Italian food"
},
{
"help_text": "",
"id": 2,
"survey": 1,
"title": "Team sports"
}, ...]});
Is the fixture adapter not able to retrieve related records in the reverse direction like this? If not, will I have to go the laborious route of manually getting the sections with survey=1, for example (laborious because I'll have to take this approach throughout my whole app with other models)?
Update
Specifically my failing code is (with survey 1):
this.get('survey').get('survey_sections').then(function(survey_sections) {
// survey_sections contains no objects, so objectAt(0) returns undefined.
survey_sections.objectAt(0).get('questions').then(function(questions) {
console.log('Set first question ID to ' + self.get('firstQuestionId'));
});
});
As the fixtures show there should be 2 SurveySection objects in survey_sections, but instead none are found.
I didn't want to do it, but I had to add the forward relation to the items in the Survey fixture, e.g.:
Survey.reopenClass({
FIXTURES: [
{
"id": 1,
"title": "Favourite food",
"survey_sections": [1, 2],
},
{
"id": 2,
"title": "Sports",
"survey_sections": [3],
}
]
});
and update the Survey model with:
survey_sections: DS.hasMany('survey_sections', {async:true})
I can already push a new object into the jobs and jobProducts array thanks to this post How to create nested models in Ember.js?
but I cannot seem to push new allocations or deliverys. I have included the JSON object below.
Any advice is appreciated, I will put together a fiddle of where I currently am when I get a moment.
Cheers
App.jobs = [
{
id: 0,
jobTitle: "This is the only job",
jobProducts: [
{
id: 0,
productTitle: "Product 1",
allocations:[
{
id: 0,
allocationTitle: "Allocation 1",
deliverys:[
{
id: 0,
deliveryTitle: "Delivery 1"
},
{
id: 1,
deliveryTitle: "Delivery 2"
}
]
},
{
id: 1,
allocationTitle: "Allocation 2",
deliverys:[
{
id: 0,
deliveryTitle: "Delivery 3"
},
{
id: 1,
deliveryTitle: "Delivery 4"
}
]
}
]
},
{
id: 1,
productTitle: "Product 2",
allocations:[
{
id: 0,
allocationTitle: "Allocation 3",
deliverys:[
{
id: 0,
deliveryTitle: "Delivery 5"
},
{
id: 1,
deliveryTitle: "Delivery 6"
}
]
},
{
id: 1,
allocationTitle: "Allocation 4",
deliverys:[
{
id: 0,
deliveryTitle: "Delivery 7"
},
{
id: 1,
deliveryTitle: "Delivery 8"
}
]
}
]
}
]
}
];
The short:
here is an example how you might do it: http://jsbin.com/esixeh/7/edit
The long:
In the example you will find code lines like the below, which look scary but it works:
App.get('jobs').objectAt(0).jobProducts.objectAt(0).allocations.objectAt(0).deliverys.pushObject({...});
Since down you JSON structure, starting from App.get('jobs') the objects are just plain javascript objects and do not extend from Ember.Object you cannot use ember methods like .get('allocations') or .get('deliverys') on them and chain them together like:
App.get('jobs').get('jobProducts').get('allocations').get('deliverys');
or
App.get('jobs.jobProducts.allocations.deliverys');
but you can still use plain javascript dot notation accessor like .allocations.
On array's you can still use ember's .pushObject(), .objectAt() etc. instead of plain .push(), because array's are augmented by the framework by default see here for more info on that.
Hope it helps.