Display json nested objects in React - react-native

I am new to react and trying to display nested json object. I want to iterate "hookah_tobacco" nested object and display tobacco types.
Json part:
{
"id": 1,
"hookah_name": "Smoke city",
"city": 131,
"street": "Osinnya, 33",
"website": "",
"phone": "0672222222",
"description": "Cool bar.",
"credit_card": true,
"hookah_type": [],
"hookah_tobacco": [
{
"hookah_tobacco": "Al-Fakher"
},
{
"hookah_tobacco": "Serbetli"
}
],
"summer_terrace": false,
"hookah_images": [
{
"id": 1,
"hookah_image": "http://127.0.0.1:8000/hookahImages/O4P02PtmT22nv8LwB85KDw-752x440.jpg"
},
{
"id": 2,
"hookah_image": "http://127.0.0.1:8000/hookahImages/kalyannaya-zmist-kiev-vxod-pushkinskoy-1024x768.jpeg"
}
]
}
React part:
class HookahDetail extends Component{
render(){
const obj = this.props.hookahDetail;
return(
// TODO move style to css
<div style = {{ color: "yellow", border: "1px solid yellow" }}>
<h4>{obj.hookah_name}</h4>
<h5>
<p>{obj.city}</p>
{obj.street}
<p>{obj.hookah_style}</p>
<p>{obj.phone}</p>
Tobacco:
<div>
</div>
<p>{obj.description}</p>
<p>{obj.credit_card}</p>
<p>{obj.summer_terrace}</p>
<div>
{/* here is some mistake */}
{obj.hookah_tobacco.map((t) => {
return (
<div>{t.hookah_tobacco}</div>
)
})}
</div>
</h5>
</div>
)
}
}
Error part:
TypeError: obj.hookah_tobacco is undefined
Console log part when {console.log(obj.hookah_tobacco)}():
0: Object { hookah_tobacco: "Al-Fakher" }
​
1: Object { hookah_tobacco: "Serbetli" }
I can't understand why map() function does not work.

Try to use it like this. This way can handle the undefined error
...
{obj.hookah_tobacco ? obj.hookah_tobacco.map((t) => {
return (
<div>{t.hookah_tobacco}</div>
)
}) : null}

Related

Creating a Search Input Filter with Computed in Vue 3

I've worked through this guide to create a search filter input field but can't figure out how to correctly implement computed in the v-model.
I've transformed the code from the guide into:
<template>
<div id="table-cms" class="table-cms">
<input class="search-field textfield-closed" type="search" placeholder="Search" v-model="filter">
<p>{{ filter }}</p>
<p>{{ state.array }}</p>
</div>
</template>
<script setup>
import {computed, reactive} from "vue";
const state = reactive({
search: null,
array: [
{id: 1, title: 'Thanos', content: '123'},
{id: 2, title: 'Deadpool', content: '456'},
{id: 3, title: 'Batman', content: '789'}
]
})
const filter = computed({
get() {
console.log('check1')
return state.search
},
set() {
if (state.search) {
console.log('check2a')
return state.array.filter(item => {
return state.search
.toLowerCase()
.split(" ")
.every(v => item.title.toLowerCase().includes(v))
});
} else {
console.log('check2b')
return state.array;
}
}
})
</script>
But the console shows:
check1
check2b
check2b
check2b
...
This means that computed gets executed but it doesn't enter if (state.search) {} (the actual filter). Displaying state.array does render the initial array but does not get updated by typing different titles in the input field:
<p>{{ state.array }}</p>
rendering:
[
{
"id": 1,
"title": "Thanos",
"content": "123"
},
{
"id": 2,
"title": "Deadpool",
"content": "456"
},
{
"id": 3,
"title": "Batman",
"content": "789"
}
]
What am I doing wrong?
You have to use state.search as the v-model on your input:
<input class="search-field textfield-closed" type="search" placeholder="Search" v-model="state.search">
Otherwise it stays null forever because it is not changing which causes the code to skip the if statement.
Also you don't need a setter in your computed filter.
<template>
<div id="table-cms" class="table-cms">
<input
class="search-field textfield-closed"
type="search"
placeholder="Search"
v-model="state.search"
/>
<p>{{ state.array }}</p>
</div>
</template>
<script setup>
import { computed, reactive } from "vue";
const state = reactive({
search: null,
array: [
{ id: 1, title: "Thanos", content: "123" },
{ id: 2, title: "Deadpool", content: "456" },
{ id: 3, title: "Batman", content: "789" },
],
});
const filter = computed(() => {
if (state.search) {
//console.log('check2a')
return state.array.filter((item) => {
return state.search
.toLowerCase()
.split(" ")
.every((v) => item.title.toLowerCase().includes(v));
});
} else {
console.log("check2b");
return state.array;
}
});
</script>

Cannot render multiple times the same amchart3 graph in a vue component

I'm using amcharts3 to generate graphs, Bootstrap 4 for the style and Vue2 for the components. I have a parent component which shows a donut chart which is a component on its own, and I want to render those charts many times as I need
Parent component
<template>
<div class="w-100 container-fluid">
<div class="row">
<!-- Here it goes the Donut Charts -->
</div>
</div>
</template>
<script>
import donutChart from './donutChart';
export default {
components:{
'donut-chart': donutChart
},
data(){
return{
graficos: [
{id: 'grafico', valor:100, valor2: 0},
{id: 'dona', valor:75, valor2: 25},
{id: 'homero', valor:50, valor2:50},
]
}
}
}
</script>
<style></style>
donutChart.vue (the amcharts3 library is already loaded in the Vue project)
<template>
<div class="col">
<div :id="this.dato.id"></div>
</div>
</template>
<script>
export default {
props:{
dato: {
type: Object,
default: {id: 'chartdiv', valor:50, valor2:50}
}
},
data() {
return {
}
},
created: function(){
console.log(this.dato)
AmCharts.makeChart( this.dato.id, {
"type": "pie",
"theme": "none",
"responsive": {
"enabled": true
},
"minWidth": 200,
"maxWidth": 400,
"dataProvider": [ {
"title": "et0",
"value": this.dato.valor
},
{
"title": "Restante",
"value": this.dato.valor2
} ],
"startDuration": 0,
"titleField": "title",
"valueField": "value",
"labelRadius": 5,
"radius": "40%",
"innerRadius": "80%",
"allLabels": [{
"y": "46%",
"align": "center",
"size": 14,
"text": "50%",
"color": "#555"
}]
});
},
mounted: function(){
},
methods:{
}
}
</script>
<style></style>
The problem is the donutChart.vue component is rendered in the parent, and it shows the chart
<donut-chart></donut-chart>
But when I try to render multiple times the same component and/or passing data via props the chart doesn't render at all
<donut-chart :dato="{id: 'grafico', valor: 100, valor2: 0}"></donut-chart>
<donut-chart :dato="{id: 'dona', valor: 75, valor2: 25}"></donut-chart>
<donut-chart :dato="{id: 'homero', valor: 50, valor2 :50}"></donut-chart>
I'm doing something wrong?
Well. I've managed to see what's going on and it looks so stupid. In donutChart.vue there´s an style that only applies to #chartdiv element, I didn't post in the question because I didn't figure that code until now. Now I'm applying the same style for every component and now the charts are renderized

Google Maps showing grey box in Vue modal

I have a <b-modal> from VueBootstrap, inside of which I'm trying to render a <GmapMap> (https://www.npmjs.com/package/gmap-vue)
It's rendering a grey box inside the modal, but outside the modal it renders the map just fine.
All the searching I've done leads to the same solution which I'm finding in some places is google.maps.event.trigger(map, 'resize') which is not working. Apparently, it's no longer part of the API [Source: https://stackoverflow.com/questions/13059034/how-to-use-google-maps-event-triggermap-resize]
<template>
<div class="text-center">
<h1>{{ title }}</h1>
<div class="row d-flex justify-content-center">
<div class="col-md-8">
<GmapMap
ref="topMapRef"
class="gmap"
:center="{ lat: 42, lng: 42 }"
:zoom="7"
map-type-id="terrain"
/>
<b-table
bordered
dark
fixed
hover
show-empty
striped
:busy.sync="isBusy"
:items="items"
:fields="fields"
>
<template v-slot:cell(actions)="row">
<b-button
size="sm"
#click="info(row.item, row.index, $event.target)"
>
Map
</b-button>
</template>
</b-table>
<b-modal
:id="mapModal.id"
:title="mapModal.title"
#hide="resetInfoModal"
ok-only
>
<GmapMap
ref="modalMapRef"
class="gmap"
:center="{ lat: 42, lng: 42 }"
:zoom="7"
map-type-id="terrain"
/>
</b-modal>
</div>
</div>
</div>
</template>
<script>
// import axios from "axios";
import { gmapApi } from 'gmap-vue';
export default {
name: "RenderList",
props: {
title: String,
},
computed: {
google() {
return gmapApi();
},
},
updated() {
console.log(this.$refs.modalMapRef);
console.log(window.google.maps);
this.$refs.modalMapRef.$mapPromise.then((map) => {
map.setCenter(new window.google.maps.LatLng(54, -2));
map.setZoom(2);
window.google.maps.event.trigger(map, 'resize');
})
},
data: function () {
return {
items: [
{ id: 1, lat: 42, long: 42 },
{ id: 2, lat: 42, long: 42 },
{ id: 3, lat: 42, long: 42 },
],
isBusy: false,
fields: [
{
key: "id",
sortable: true,
class: "text-left",
},
{
key: "text",
sortable: true,
class: "text-left",
},
"lat",
"long",
{
key: "actions",
label: "Actions"
}
],
mapModal: {
id: "map-modal",
title: "",
item: ""
}
}
},
methods: {
// dataProvider() {
// this.isBusy = true;
// let promise = axios.get(process.env.VUE_APP_LIST_DATA_SERVICE);
// return promise.then((response) => {
// this.isBusy = false
// return response.data;
// }).catch(error => {
// this.isBusy = false;
// console.log(error);
// return [];
// })
// },
info(item, index, button) {
this.mapModal.title = `Label: ${item.id}`;
this.mapModal.item = item;
this.$root.$emit("bv::show::modal", this.mapModal.id, button);
},
resetInfoModal() {
this.mapModal.title = "";
this.mapModal.content = "";
},
},
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1 {
margin-bottom: 60px;
}
.gmap {
width: 100%;
height: 300px;
margin-bottom: 60px;
}
</style>
Does anyone know how to get the map to display properly in the modal?
Surely, I'm not the first to try this?
Had this problem, in my case it was solved by providing the following options to google maps:
mapOptions: {
center: { lat: 10.365365, lng: -66.96667 },
clickableIcons: false,
streetViewControl: false,
panControlOptions: false,
gestureHandling: 'cooperative',
mapTypeControl: false,
zoomControlOptions: {
style: 'SMALL'
},
zoom: 14
}
However you can probably make-do with just center and zoom.
Edit: Try using your own google maps components, follow this tutorial:
https://v2.vuejs.org/v2/cookbook/practical-use-of-scoped-slots.html#Base-Example
You can use the package described in the tutorial to load the map, dont be scared by the big red "deprecated" warning on the npm package page.
However for production, you should use the package referenced by the author, which is the one backed by google:
https://googlemaps.github.io/js-api-loader/index.html
The only big difference between the two:
The 'google' object is not returned by the non-deprecated loader, it is instead attached to the window. See my answer here for clarification:
'google' is not defined Using Google Maps JavaScript API Loader
Happy coding!

Error: Cannot find module - Local path of image won't load in vue.js

I'm making a movie library using electron.js + vue.js with json as my database. All data has been loaded from the database except the image path inside won't load.
I tried to use require() to load the local path of the image but it always throws me an error of Error in render: Error: Cannot find module file path.
<v-card v-for="movie in movies" :key="movie.id" class="pa-5">
<v-card-title primary-title>
{{ movie.id }} - {{ movie.title }}
</v-card-title>
<v-card-text>
{{ movie.year }}
</v-card-text>
<v-img :src="getImage(movie.poster)" />
</v-card>
import axios from 'axios'
export default {
components: {},
data() {
return {
movies: [],
}
},
methods: {
fetchData() {
axios.get('db.json').then(res => {
return this.movies = res.data.movies
})
},
getImage(poster) {
return poster ? require(`${poster}`) : ''
}
},
async created() {
this.fetchData()
}
};
{
"movies": [
{
"id": 0,
"title": "Aladdin",
"year": 2019,
"poster": "../../../posters/aladdin_2019.jpg"
},
{
"id": 1,
"title": "Alita Battle Angel",
"year": 2019,
"poster": "../../../posters/alita.jpg"
}
]
}
In your methods inside require use empty string to concatenate your path and get string as a result, which require expects:
getImage(poster) {
return poster ? require("" + poster) : ''
}
You can find more information about that if you read require with expression of the official docs.

React api call. I am able to fetch data but how to populate in the front end

https://github.com/sidhemu/menu_food
As I am new in react
In Featured.js file I am doing get request and I am getting data back. The problem I am facing is on to display those data in loop. I tried map() but I am getting error "Cannot read property 'map' of undefined(…)". Can anyone please look at the code and please let me know where I am missing something or doing something wrong.
The file is in src>js>Featured.js
export default class Featured extends React.Component {
constructor(){
super();
this.state = { }
}
componentWillMount(){
var url = 'http://ec2-54-165-240-14.compute-1.amazonaws.com:3000/api/foodItem';
Request.get(url).then((response) => {
this.setState({
foodinfo: response.body
})
})
}
render() {
console.log(this.state.foodinfo);
return(
<div className="container">
<div className="row">
<h1>Featured</h1>
<Card className="col-xs-12 col-sm-4 eachCard">
<CardImg top width="100%" src="https://tabletopmenu.s3-us-west-2.amazonaws.com/easyPie/Pasta.jpg?AWSAccessKeyId=AKIAJBLST2F5EFKIZGXQ&Expires=2079704677&Signature=eSjrIw32apC0gCGpF92%2FxgnELNA%3D" alt="Card image cap" />
<CardBlock className="cardBlock">
<CardTitle>Boom Boom Chicken</CardTitle>
<CardSubtitle>$8.50</CardSubtitle>
<span class="glyphicon glyphicon-plus-sign btnClass"></span>
</CardBlock>
</Card>
</div>
</div>
)
}
}
So the data I am getting the data like this
[
{
"food_item_id": "a095eca7-3dcf-11e6-a9f9-28e347",
"food_group_id": "eb9fa7e9-3dc9-11e6-a9f9-28e347",
"food_item_name": "Don't know jack",
"food_item_pic": "https://tabletopmenu.s3-us-west-2.amazonaws.com/easyPie/dont-know-jack.jpg?AWSAccessKeyId=AKIAJBLST2F5EFKIZGXQ&Expires=2080062718&Signature=1OFv2yjaLYBp4lBflKoCOTHl9NQ%3D",
"food_item_price": 8.5,
"food_item_price_s": 0,
"food_item_price_l": 0,
"food_item_short_desc": "Our signature all beef patty topped with pepper jack cheese, jalapenos, lettuce and mango salsa",
"food_item_long_desc": "",
"allergy_profile1": "",
"allergy_profile2": "",
"allergy_profile3": "",
"allergy_profile4": "",
"drink_pairing1": "",
"drink_pairing2": "",
"drink_pairing3": "",
"drink_pairing4": "",
"drink_pairing5": "",
"createdAt": null,
"updatedAt": null
},
{
"food_item_id": "a09b073d-3dcf-11e6-a9f9-28e347",
"food_group_id": "ebaeef2c-3dc9-11e6-a9f9-28e347",
"food_item_name": "Oreo cookie monster",
"food_item_pic": "https://tabletopmenu.s3-us-west-2.amazonaws.com/easyPie/oreo_cookie_monster.jpg?AWSAccessKeyId=AKIAJBLST2F5EFKIZGXQ&Expires=2080062718&Signature=4OXMof1S%2BDN1pmdQ%2BSHYyWdevvM%3D",
"food_item_price": 0,
"food_item_price_s": 11,
"food_item_price_l": 15,
"food_item_short_desc": "Oreo cookie filling, crushed oreo topping, powdered sugar",
"food_item_long_desc": "",
"allergy_profile1": "",
"allergy_profile2": "",
"allergy_profile3": "",
"allergy_profile4": "",
"drink_pairing1": "",
"drink_pairing2": "",
"drink_pairing3": "",
"drink_pairing4": "",
"drink_pairing5": "",
"createdAt": null,
"updatedAt": null
}
]
Now i need to fill with these data
food_item_name
food_item_pic
food_item_price
It is because React is trying to access the variable before it was instantiate...
You're doin a async call so... it is available ONLY after it was received...
Try instantiate state in your constructor with an empty array:
constructor(){
super();
this.state = { foodinfo: [] }
}