Related
I am trying to use a method to fetch data from a json file and add it to my chart.js chart. I keep getting a "Maximum call stack size exceeded", this is specifically caused by the this.chartData.push(el.value); line, I've tried changing naming around to no success as well as using this.$data.chartData.
I am using vue3, chart.js v3 and j-t-mcc/vue3-chartjs
here is a codesandbox.io of the code with the error.
Child (chart) component
<template>
<div class="card card-body bg-dark">
<div class="col" id="chart">
<vue3-chart-js
ref="chartRef"
:id="sampleChart.id"
:type="sampleChart.type"
:data="sampleChart.data"
:options="sampleChart.options"
></vue3-chart-js>
</div>
</div>
</template>
<script>
import { ref } from 'vue'
import Vue3ChartJs from "#j-t-mcc/vue3-chartjs"
import 'chartjs-adapter-date-fns';
var chartOptions = {
maintainAspectRatio: true,
responsive: true,
animation: {
duration: 500
},
plugins: {
legend: {
display: false,
},
tooltip: {
yAlign: "bottom",
},
},
interaction: {
mode: "index",
intersect: false,
axis: "x",
},
scales: {
x: {
type: "time",
time: {
unit: "minute"
}
},
y: {
beginAtZero: true,
},
},
elements: {
point: {
pointRadius: 5.0,
},
},
layout: {
padding: {
top: 20,
left: 10,
right: 10,
bottom: 10,
},
},
}
export default {
name: "Chart",
components: {
Vue3ChartJs,
},
props: {
chartData: Array,
chartLabels: Array
},
setup(props) {
const chartRef = ref(null)
console.log("area chart data", props.chartData)
const chartDetails = {
labels: props.chartLabels,
fill: true,
datasets: [
{
label: "",
data: props.chartData,
borderColor: "rgb(24, 144, 255)",
tension: 0.1,
fill: true,
},
],
}
const sampleChart = {
id: "line",
type: "line",
data: chartDetails,
options: chartOptions,
}
return {
sampleChart,
chartRef
}
},
watch: {
chartLabels: {
deep: true,
handler() {
this.chartRef.update(250)
}
}
},
}
</script>
<style>
#chart {
position: relative;
margin: auto;
height: 100%;
width: 100%;
}
</style>
Parent component
<template>
<div>
<div class="container-fluid">
<SampleChart :chart-data="chartData" :chart-labels="chartLabels" />
</div>
</div>
</template>
<script>
import SampleChart from "./SampleChart.vue";
export default {
components: { SampleChart },
data() {
return {
chartData: [],
chartLabels: [],
};
},
async beforeMount() {
this.getTimelineData();
},
methods: {
getTimelineData: function () {
fetch("http://localhost:8080/sample.json")
.then((res) => res.json())
.then((data) => {
data.data.forEach((el) => {
this.chartData.push(el.value);
this.chartLabels.push(el.timestamp);
});
});
},
},
};
</script>
Package.json dependencies
"dependencies": {
"#j-t-mcc/vue3-chartjs": "^1.1.2",
"bootstrap": "^5.0.2",
"chart.js": "^3.3.2",
"chartjs-adapter-date-fns": "^2.0.0",
"core-js": "^3.6.5",
"date-fns": "^2.23.0",
"leaflet": "^1.7.1",
"vue": "^3.1.5"
}
The Error Message
Uncaught (in promise) RangeError: Maximum call stack size exceeded
at Object.get (reactivity.esm-bundler.js?a1e9:231)
at toRaw (reactivity.esm-bundler.js?a1e9:743)
at Proxy.instrumentations.<computed> (reactivity.esm-bundler.js?a1e9:223)
at Proxy.value (helpers.segment.js?dd3d:1531)
at Proxy.instrumentations.<computed> (reactivity.esm-bundler.js?a1e9:223)
at Proxy.value (helpers.segment.js?dd3d:1531)
at Proxy.instrumentations.<computed> (reactivity.esm-bundler.js?a1e9:223)
at Proxy.value (helpers.segment.js?dd3d:1531)
at Proxy.instrumentations.<computed> (reactivity.esm-bundler.js?a1e9:223)
at Proxy.value (helpers.segment.js?dd3d:1531)
Sample method without fetch that worked fine
getTestData: function () {
var labels = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
var values = [10, 25, 39, 55, 90, 202, 304, 202, 105, 33, 44, 95, 20, 39, 90];
labels.forEach((el) => {
this.chartLabels.push(el);
});
values.forEach((el) => {
this.chartData.push(el);
});
},
Json data sample
{
"data": [
{
"timestamp": 1627382793000,
"value": 121
},
{
"timestamp": 1627383698000,
"value": 203
},
{
"timestamp": 1627387917000,
"value": 15
}
]
}
it's work when adding a simple v-if with a ready property that we turn it true when we finish the foreach of pushing data,
the problem is with your SampleChart.vue componenent , you make chart data inside the setup , so when data changed sampleChart will not be changed in any case , it's already calculated.
you can learn more about computed, ref/reactive
While Hossem's answer will work for the first render, the chart still wont be updated when you add new data.
Oddly enough, downgrading Vue one version from 3.1.5 to 3.1.4 ended up resolving the issue.
I am trying to understand an error that I have and that I do not understand.
I have this array:
Array [
Object {
"cost": 0,
"created_at": "2020-12-14T15:54:50Z",
"custom_fields": Object {
"_161_": "4137",
"_162_": "48",
"_163_": "10926",
"_164_": "0",
"_165_": "FLY",
"_166_": "2020-12-14T14:54:37.737Z",
"_167_": "2020-12-31T14:54:37.737Z",
"_168_": "0",
"_171_": "0",
"_300_": "412:00",
"_301_": "45.725556|5.081111",
"_302_": "-27.7078990936|-67.0951004028",
"_303_": "Lyon Saint-Exupéry Airport",
"_304_": "Londres/Belén Airport",
"_310_": "60",
},
"description": "",
"family_id": 0,
"id": 1061,
"incl_tax": 0,
"is_visible": 1,
"name": "Lyon Saint-Exupéry Airport (14/12/2020 à 15:54) > Londres/Belén Airport (31/12/2020 à 15:54)",
"photo": "",
"quantity": 0,
"reference": "",
"stock_status": "1",
"tax_rate_id": 0,
"unit": "",
"updated_at": "2020-12-14T15:54:50Z",
"weight": 0,
},
Object {
"cost": 0,
"created_at": "2020-11-15T01:38:08Z",
"custom_fields": Object {
"_161_": "1373",
"_162_": "30",
"_163_": "4680",
"_164_": "0",
"_165_": "FLY",
"_166_": "2020-11-21T00:37:00.000Z",
"_167_": "2020-11-29T00:37:00.000Z",
"_168_": "0",
"_171_": "0",
"_300_": "190:00",
"_301_": "43.6539083949|-79.65785399079999",
"_302_": "-22.285699844399996|-62.7136993408",
"_303_": "Tarten Heliport",
"_304_": "Santa Victoria Airport",
"_310_": "-480",
},
"description": "",
"family_id": 0,
"id": 896,
"incl_tax": 0,
"is_visible": 1,
"name": "Tarten Heliport (2020-11-21 at 16:37) > Santa Victoria Airport (2020-11-29 at 16:37)",
"photo": "",
"quantity": 0,
"reference": "",
"stock_status": "1",
"tax_rate_id": 0,
"unit": "FLY",
"updated_at": "2020-11-15T01:38:08Z",
"weight": 0,
},
]
It's an array test with 2 products inside (flights) I'm trying to access the filenames, so "name", I don't understand at all why my call returns 'undefined' in console.log when I do
console.log(this.state.name)
I initialize my data in the initListData function, I update the state here so that the name gets the names from my array, I load this function from componentWillMount and then I call the names in my autocomplete.
can someone help me figure out what is wrong, and where i am making the mistake? I need constructed explanations please, there I have a real need for understanding.
Thanks for any leads or help.
Full code :
import React, { Component } from "react";
import {
View,
Text,
StyleSheet,
Button
} from "react-native";
import styles from '../../../assets/styles';
import * as Permissions from "expo-permissions";
import { getProducts } from '../../../src/common/Preferences';
import { Camera } from 'expo-camera';
import i18n from '../../../src/i18n';
import shortid from "shortid";
import {Autocomplete} from "react-native-dropdown-autocomplete";
class Tickets extends Component {
constructor(props) {
super(props);
this.state = {
Press: false,
hasCameraPermission: null,
name: '',
lastScannedUrl:null,
eventSelected: false,
displayArray: []
};
}
initListData = async () => {
let list = await getProducts(1);
if (list) {
this.setState({
displayArray: list,
name: list.name
});
}
console.log('name dans initListData =', list.name)
};
async UNSAFE_componentWillMount() {
this.initListData();
console.log('name dans le state =', this.state.name)
};
componentDidMount() {
this.getPermissionsAsync();
}
getPermissionsAsync = async () => {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({ hasCameraPermission: status === "granted" });
};
handleBarCodeScanned = ({ type, data }) => {
this.setState({ Press: false, scanned: true, name: data });
this.props.navigation.navigate('ProductDetails', {name : parseInt(this.state.state.name)})
};
renderBarcodeReader = () => {
const { hasCameraPermission, scanned } = this.state;
if (hasCameraPermission === null) {
return <Text>{i18n.t("scan.request")}</Text>;
}
if (hasCameraPermission === false) {
return <Text>{i18n.t("scan.noaccess")}</Text>;
}
return (
<View
style={{
flex: 1,
...StyleSheet.absoluteFillObject
}}
>
<Camera
onBarCodeScanned={scanned ? undefined : this.handleBarCodeScanned}
barCodeScannerSettings={[Camera.Constants.Type.qr]}
style={{flex:1}}
/>
{scanned && (
<Button
title={"Tap to Scan Again"}
onPress={() => this.setState({ scanned: false })}
disabled={this.state.selectedItem===null}
/>
)}
</View>
);
}
handleSelectItem(item, index) {
const {onDropdownClose} = this.props;
onDropdownClose();
this.setState({eventSelected: true})
console.log(item);
}
render() {
const { hasCameraPermission, scanned, Press } = this.state;
let marker = null;
const {scrollToInput, onDropdownClose, onDropdownShow} = this.props;
//console.log('displayArray', this.state.displayArray, 'name', this.state.name)
return (
<View style={{flex:1}}>
<View style={{width: "100%", zIndex: 100}}>
<Autocomplete
key={shortid.generate()}
containerStyle={{margin: 0, padding: 0, borderBottomColor: 'transparent',}}
inputStyle={{ width: '80%', borderWidth: 1, backgroundColor: '#FFF', opacity: 0.9, borderColor: '#F78400'}}
placeholder={i18n.t("tickets.event")}
placeholderColor="#F78400"
pickerStyle={styles.autocompletePicker}
scrollStyle={styles.autocompleteScroll}
scrollToInput={ev => {}}
handleSelectItem={(item, id) => this.handleSelectItem(item, id)}
onDropdownClose={() => onDropdownClose()}
onDropdownShow={() => onDropdownShow()}
data={this.state.name}
minimumCharactersCount={2}
highlightText
valueExtractor={item => item.name}
rightContent
rightTextExtractor={item => item.properties}
/>
</View>
{this.state.eventSelected ? (
<View>
{this.renderBarcodeReader()}
</View>
) : (
<Text style={{ top: '50%', zIndex:100, color: 'red', fontStyle: 'italic', fontSize: 18}}>{i18n.t("tickets.warning")}</Text>
)}
</View>
);
}
}
export default Tickets;
I have an array with two products in it. (later, the list will be more complete, for the moment it's to test the autocomplete that I did like this)
I would like to display the list of the names of these two products in an autocomplete input made with the 'react-native-dropdown-autocomplete' package.
I wanted to initialize name in the state, my concern is that when I ask to display this.state.name it returns me undefined since the two names of the two products are different in the array.
Array [
Object {
"cost": 0,
"created_at": "2020-12-14T15:54:50Z",
"custom_fields": Object {
"_161_": "4137",
"_162_": "48",
"_163_": "10926",
"_164_": "0",
"_165_": "FLY",
"_166_": "2020-12-14T14:54:37.737Z",
"_167_": "2020-12-31T14:54:37.737Z",
"_168_": "0",
"_171_": "0",
"_300_": "412:00",
"_301_": "45.725556|5.081111",
"_302_": "-27.7078990936|-67.0951004028",
"_303_": "Lyon Saint-Exupéry Airport",
"_304_": "Londres/Belén Airport",
"_310_": "60",
},
"description": "",
"family_id": 0,
"id": 1061,
"incl_tax": 0,
"is_visible": 1,
"name": "Lyon Saint-Exupéry Airport (14/12/2020 à 15:54) > Londres/Belén Airport (31/12/2020 à 15:54)",
"photo": "",
"quantity": 0,
"reference": "",
"stock_status": "1",
"tax_rate_id": 0,
"unit": "",
"updated_at": "2020-12-14T15:54:50Z",
"weight": 0,
},
Object {
"cost": 0,
"created_at": "2020-11-15T01:38:08Z",
"custom_fields": Object {
"_161_": "1373",
"_162_": "30",
"_163_": "4680",
"_164_": "0",
"_165_": "FLY",
"_166_": "2020-11-21T00:37:00.000Z",
"_167_": "2020-11-29T00:37:00.000Z",
"_168_": "0",
"_171_": "0",
"_300_": "190:00",
"_301_": "43.6539083949|-79.65785399079999",
"_302_": "-22.285699844399996|-62.7136993408",
"_303_": "Tarten Heliport",
"_304_": "Santa Victoria Airport",
"_310_": "-480",
},
"description": "",
"family_id": 0,
"id": 896,
"incl_tax": 0,
"is_visible": 1,
"name": "Tarten Heliport (2020-11-21 at 16:37) > Santa Victoria Airport (2020-11-29 at 16:37)",
"photo": "",
"quantity": 0,
"reference": "",
"stock_status": "1",
"tax_rate_id": 0,
"unit": "FLY",
"updated_at": "2020-11-15T01:38:08Z",
"weight": 0,
},
]
I would like some help figuring out how I can display the product names.
I understood that my error comes from the fact that the API returns several objects (= several products with different names), whereas I have coded so as to manage only one product.
I need some help and explanation please, I'm running around in circles, lost in my code and, frankly, a little desperate.
I want to thank you for any help and explanation.
Thank you
My code :
class Tickets extends Component {
constructor(props) {
super(props);
this.state = {
Press: false,
hasCameraPermission: null,
reference: '',
name:'',
lastScannedUrl:null,
eventSelected: false,
displayArray: []
};
}
initListData = async () => {
let list = await getProducts(1);
if (list) {
this.setState({
displayArray: list,
reference: list.reference,
name: list.name
});
}
// console.log('name dans initListData =', list.name)
// console.log('reference dans initListData =', list.reference)
};
async UNSAFE_componentWillMount() {
this.initListData();
};
componentDidMount() {
this.getPermissionsAsync();
}
getPermissionsAsync = async () => {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({ hasCameraPermission: status === "granted" });
};
handleBarCodeScanned = ({ type, data }) => {
this.setState({ Press: false, scanned: true, name: data });
this.props.navigation.navigate('ProductDetails', {name : parseInt(this.state.state.name)})
};
renderBarcodeReader = () => {
const { hasCameraPermission, scanned } = this.state;
if (hasCameraPermission === null) {
return <Text>{i18n.t("scan.request")}</Text>;
}
if (hasCameraPermission === false) {
return <Text>{i18n.t("scan.noaccess")}</Text>;
}
return (
<View
style={{
flex: 1,
...StyleSheet.absoluteFillObject
}}
>
<Camera
onBarCodeScanned={scanned ? undefined : this.handleBarCodeScanned}
barCodeScannerSettings={[Camera.Constants.Type.qr]}
style={{flex:1}}
/>
{scanned && (
<Button
title={"Tap to Scan Again"}
onPress={() => this.setState({ scanned: false })}
disabled={this.state.selectedItem===null}
/>
)}
</View>
);
}
handleSelectItem(item, index) {
const {onDropdownClose} = this.props;
onDropdownClose();
this.setState({eventSelected: true})
//console.log(item);
}
render() {
const { hasCameraPermission, scanned, Press } = this.state;
let marker = null;
const {scrollToInput, onDropdownClose, onDropdownShow} = this.props;
console.log('displayArray', this.state.displayArray, 'name', this.state.name)
console.log('this.state retourne', this.state)
return (
<View style={{flex:1}}>
<View style={{width: "100%", zIndex: 100}}>
<Autocomplete
key={shortid.generate()}
containerStyle={{margin: 0, padding: 0, borderBottomColor: 'transparent',}}
inputStyle={{ width: '80%', borderWidth: 1, backgroundColor: '#FFF', opacity: 0.9, borderColor: '#F78400'}}
placeholder={i18n.t("tickets.event")}
placeholderColor="#F78400"
pickerStyle={styles.autocompletePicker}
scrollStyle={styles.autocompleteScroll}
scrollToInput={ev => {}}
handleSelectItem={(item, id) => this.handleSelectItem(item, id)}
onDropdownClose={() => onDropdownClose()}
onDropdownShow={() => onDropdownShow()}
data={this.state.name}
minimumCharactersCount={2}
highlightText
valueExtractor={item => item.name}
rightContent
rightTextExtractor={item => item.properties}
/>
</View>
{this.state.eventSelected ? (
<View>
{this.renderBarcodeReader()}
</View>
) : (
<Text style={{ top: '33%', zIndex:100, color: 'red', fontStyle: 'italic', fontSize: 18}}>{i18n.t("tickets.warning")}</Text>
)}
</View>
);
}
}
export default Tickets;
What i have found from your Code. I guess the problem is here
data={this.state.name}
Here you have to pass your array.
data={Your_array}
This is my steps:
The Json code:
"features": [
{
"name": "size",
"selected": null,
"values": [
{
"value": "40",
"label": "40",
},
{
"value": "41",
"label": "41",
}
]
},
{
"label": "color",
"selected": "gray",
"values": [
{
"value": "gray",
"label": "gray"
},
{
"value": "black",
"label": "black",
}
]
}
]
Step2: define state
constructor(props) {
super(props);
this.state ={selectedDropDownValue:[]};
}
step3:
main render:
render{
return(
{this.printPickers()}
);
}
and
printPickers(){
const listItems = data.map((obj,index) =>
<Item picker key={'mykey1' + index}>
<Picker
selectedValue={(this.state.selectedDropDownValue[obj.label]) ?this.state.selectedDropDownValue[obj.label] : obj.selected}
onValueChange={(itemValue, itemIndex, itemName) =>this.pickerChange(itemIndex,itemValue,obj.name)}
>
{
obj1.values.map( (v)=>{
return <Picker.Item key={'mykey2' + index} label={v.label} value={v.value} />
})
}
</Picker>
</Item>
);
return (<View>{listItems}</View>);
}
and finally:
pickerChange(itemIndex,itemValue,itemName){
this.setState({
selectedDropDownValue: Object.assign(this.state.selectedDropDownValue, {[itemName]: itemValue})
});
}
My problem I can not change options of each pickers by touching them but with console.log(this.state.selectedDropDownValue), I get right data.
My problem I can not change options of each pickers by touching them but with console.log(this.state.selectedDropDownValue), I get right data.
There is some mismatch in json data. Either both should have a key label or name.
So suppose both items have key as label then you need to update your pickerChange function call like this:
this.pickerChange(itemIndex,itemValue,obj.label)
I've implemented autocomplete for my address field, but the json returned from the Google Maps Places Autocomplete doesn't include the geocoded coords for the places.
There are some answers out there that don't seem to fit. For instance, this one refers to things like google.maps.places.Autocomplete(input, options); which I don't think is a thing in React Native.
Other answers appear to be based on react-native-google-places-autocomplete, but I've implemented this myself and I'd love to not do it again using that module.
Here's my method where I call the API.
async handleAddressChange() {
const url = `https://maps.googleapis.com/maps/api/place/autocomplete/json?key=${GoogleAPIKey}&input=${this.state.address}`;
try {
const result = await fetch(url);
const json = await result.json();
this.setState({ addressPredictions: json.predictions });
} catch (err) {
console.error(err);
}
}
setAddress(prediction) {
this.setState({ address: prediction.description, showPredictions: false });
}
The API response doesn't have any place or geometry property on it:
Object {
"description": "1234 Some Avenue Northeast, Washington, DC, USA",
"id": "4c79fba1b3a5ad33478b79b54896a75a4d56ca53",
"matched_substrings": Array [
Object {
"length": 4,
"offset": 0,
},
],
"place_id": "ChIJneQ1fBO5t4kRf8mTw4ieb4Q",
"reference": "ChIJneQ1fBO5t4kRf8mTw4ieb4Q",
"structured_formatting": Object {
"main_text": "1234 Some Avenue Northeast",
"main_text_matched_substrings": Array [
Object {
"length": 4,
"offset": 0,
},
],
"secondary_text": "Washington, DC, USA",
},
"terms": Array [
Object {
"offset": 0,
"value": "1600",
},
Object {
"offset": 5,
"value": "Maryland Avenue Northeast",
},
Object {
"offset": 32,
"value": "Washington",
},
Object {
"offset": 44,
"value": "DC",
},
Object {
"offset": 48,
"value": "USA",
},
],
"types": Array [
"street_address",
"geocode",
],
}
I have found a solution for the same-
Just use like this-
<GooglePlacesAutocomplete
GooglePlacesDetailsQuery={{ fields: "geometry" }}
fetchDetails={true} // you need this to fetch the details object onPress
placeholder="Search"
query={{
key: "API_KEY_GOES_HERE",
language: "en", // language of the results
}}
onPress={(data: any, details: any = null) => {
console.log("data", data);
console.log("details", details);
console.log(JSON.stringify(details?.geometry?.location));
}}
onFail={(error) => console.error(error)} />
Once you have the place id (ChIJneQ1fBO5t4kRf8mTw4ieb4Q for the example in your question), you can do a place details request.
Make sure you include the Places library in your API call: https://maps.googleapis.com/maps/api/js?libraries=places and a valid API key.
function initialize() {
var map = new google.maps.Map(document.getElementById('map-canvas'), {
center: new google.maps.LatLng(0, 0),
zoom: 15
});
var service = new google.maps.places.PlacesService(map);
service.getDetails({
placeId: 'ChIJneQ1fBO5t4kRf8mTw4ieb4Q'
}, function(place, status) {
if (status === google.maps.places.PlacesServiceStatus.OK) {
// Create marker
var marker = new google.maps.Marker({
map: map,
position: place.geometry.location
});
// Center map on place location
map.setCenter(place.geometry.location);
}
});
}
initialize();
#map-canvas {
height: 160px;
}
<div id="map-canvas"></div>
<!-- Replace the value of the key parameter with your own API key. -->
<script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&libraries=places&callback=initialize">
</script>