maximum calstack size exceeded on vuex commit - javascript

I have this error here
I could limit the error to this line here
mounted() {
this.$nextTick(() => {
let ctx = this.$refs.canvas.getContext('2d')
let { chartType, dataOptions } = this.module
this.chart = new Chart(ctx, {
type: chartType,
data: dataOptions,
options: minimizeOptions,
})
})
},
The error comes from dataOptions. If i set data to {} everything works ok, but obviously my chart has no data then.
this.module is an prop that is being passed to my component. The component itself gets rendered in an v-for loop
<module
v-for="mod in modules"
:module="mod"
:key="mod._id.toString()"
/>
I am using here Chart.js.
I cannot find the reason for this call stack exceed error.
Maybe somebody had similar problems?
I also need to mention that this error happens when i want to toggle an global component that is placed in an layout layout
dataOptions:
{
datasets: [
{
backgroundColor: "#34495e",
borderColor: "bdc3c7",
data: [0],
label: "My first dataset"
}
],
labels: ["Start"]
}

I actually does not need reactivity on this prop, so i decided to freeze it up.
let { chartType, dataOptions } = Object.freeze(this.module);
Reactivity is gone an the error aswell. This fixed my problem.
Maybe somebody has an solution for reactive data

Related

Cannot read properties of null (reading 'transition'). What does it mean?

I am created graphs with dynamic data from axios by chartjs library.
But when I refresh browser graphs at first nothing available, like this:
If I change dimensions for browser window - all graphs appears:
Error from concole:
Uncaught TypeError: Cannot read properties of null (reading 'transition')
at Chart.transition (Chart.js?473e:9865:1)
at Chart.draw (Chart.js?473e:9827:1)
at Chart.render (Chart.js?473e:9799:1)
at Object.callback (Chart.js?473e:2208:1)
at Object.advance (Chart.js?473e:3544:1)
at Object.startDigest (Chart.js?473e:3517:1)
at eval (Chart.js?473e:3506:1)
I don't have idea, why it can be so, and what to do.
It's look like firstly browser tried build graphs (but data didn't received yet).
During all calculation approximately 580ms.
This MainChart.vue for build charts:
<template>
<div>
<canvas id="main-chart" height="400"></canvas>
</div>
</template>
<script>
import Chart from 'chart.js'
export default {
name: 'MainChart',
props: ['chartData'],
mounted() {
const ctx = document.getElementById('main-chart');
new Chart(ctx, this.chartData);
}
}
</script>
This common page Analytics-test.vue.
I skipped all methods.
<template>
<div> Прибыль/посещаемость <div class="small">
<MainChart :chart-data="datacollection" />
</div>
</div>
</template>
<script>
import MainChart from '../MainChart.vue'
export default {
components: { MainChart },
data: () => ({
flagStartDate: false,
chartData: null,
labels: [],
datasets: {},
draftData: null,
data: [],
datacollection: { type: 'line', },
clubsId: ['5c3c5e12ba86198828baa4a7', '5c3c5e20ba86198828baa4c5', '60353d6edbb58a135bf41856', '61e9995d4ec0f29dc8447f81', '61e999fc4ec0f29dc844835e'],
}),
methods: {
...some a lot of code..},
async mounted() {
await this.loadIncomings(this.clubsId),
await this.loadAvgIncomings(this.clubsId),
await this.loadAvgPayments(this.clubsId),
await this.loadAvgSchedule(this.clubsId),
await this.loadTrainings(this.clubsId)
},
</script>
There are 19 functions in methods, and I decided don't input here.
This error seems similar to the one described in this GitHub issue: https://github.com/chartjs/Chart.js/issues/5149 It sounds like it could be caused due to the fact that the chart is immediately loaded with data, but there are a couple of solutions in the comments on that issue.

Vue.js infinite loop on component re-render [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
I'm trying to build tables based off a few selected properties from a previous component:
I'm rendering a component called 'branch-comparison' to compare XML files and their properties and values. This component takes in two props:
selectedEnvs: An array of objects with a name and object
commonFiles: An array of files with a name and object
I'm using vue-tables-2 to build these tables. At the top of the template it runs a function called getProps() to generate a set of all possible properties from each file. I've hard coded 0 because currently I'm only letting the user choose 1 file at a time. It then goes through each file (only 1) and gets data for the main table and the comparison tables. They are virtually the same function (getHeadData and getTableData) but I've seperated them for now for further customization. The code is not that important for actually generating the tables, however something inside of them is causing my code to go in an infinite loop.
On the initial render of the component, there is never an infinite loop. Everything runs through, and doesn't break at all and works wonderfully. Once however the component has been rendered, and I make a change to the props, or even simply save the file in the editor and vue-cli hot reloads it, it goes into and infinite loop. All the data still get's generate fine and the component does as it's supposed to. But it loops through 101 times no matter what.
Things I've looked into:
Changing the data: I fully understand a component re renders on data change... however I don't believe I am changing any reactive data in any method call. I'm simply declaring it locally inside the function and returning it to that temporary variable. Also if this was the case, I believe it would go into an infinite loop on the initial component load, but this is not the case. It goes into the infinite loop only on a refresh or prop change.
Mutating the Vuex state: I looked into this but I am never changing the state of anything. I am simply accessing it in the getTableData and getHeadData methods. I then thought, perhaps assigning a variable to point to this state object is causing it to re render based on something accessing the state, so I tried instead of
this.$store.state.branchesToCompare[branchIdx].obj[env.name].app_config[this.commonFiles[fileIdx]].forEach(envProp
=> {
to use
var x = JSON.parse(JSON.stringify(this.$store.state.branchesToCompare[branchIdx].obj[env.name].app_config[this.commonFiles[fileIdx]])
then
x.forEach(envProp =>
but this still does not work.
If I comment out the code that calls getHeadData() and getTableData() it loops through the appropriate amount of times.
Here is the code.. I am still new to Vue so any more general suggestions I am more than open to:
<template>
<div id="BranchComparison">
<div :set="info = getProps(0)">
<div class="file" v-for="(file, fileIdx) in commonFiles" :key="(file, fileIdx)">
<h3>{{ file }} </h3>
<b-row :set="mainTable = getHeadData(fileIdx, info.props, info.columns)">
<b-col class="mainBranch">
<h5 class="fileName"> {{ $store.state.branchSelection.split('.').slice(0, -1).join('.') }} <span style="font-size: 14px;">vs </span> </h5>
<v-client-table
:data="mainTable.data"
:columns="mainTable.columns"
:options="mainTableOptions"
size="small"
></v-client-table>
</b-col>
<b-col class="compareBranch" v-for="(branch, branchIdx) in $store.state.branchesToCompare" :key="(branch, branchIdx)">
<h5> {{ branch.name.split('.').slice(0, -1).join('.') }} </h5>
<v-client-table
:set="temp = getTableData(fileIdx, branchIdx, info.props, info.columns, mainTable)"
:data="temp.data"
:columns="temp.columns"
:options="temp.options"
size="small"
></v-client-table>
</b-col>
</b-row>
</div>
</div>
</div>
</template>
<script>
export default {
props: ['selectedEnvs', 'commonFiles'],
data(){
return{
mainTableOptions:{
filterable: false,
filterByColumn: false,
perPage: 200,
pagination: {
show: false,
dropdown: false
},
sortable: [''],
resizableColumns: false,
},
}
},
methods: {
getTableData(fileIdx, branchIdx, props, columns, mainTable){
var data = []
var compareTableOptions = {
filterable: false,
perPage: 200,
pagination: {
show: false,
},
sortable: [''],
hiddenColumns: ['Property'],
resizableColumns: false,
cellClasses: {}
}
props.forEach(prop => {
var temp = { Property: prop }
this.selectedEnvs.forEach(env => {
var found = false;
this.$store.state.branchesToCompare[branchIdx].obj[env.name].app_config[this.commonFiles[fileIdx]].forEach(envProp => {
if(envProp){
if (prop == envProp["#name"]) {
compareTableOptions.cellClasses[env.name] = []
compareTableOptions.cellClasses[env.name].push({
class: 'same',
condition: row => {
try{
return row[env.name] == mainTable.data[i][env.name]
} catch{
console.log('This is a different problem ')
}
}
})
found = true;
temp[env.name] = envProp["#value"]
}
}
});
if (!found){
temp[env.name] = 'Not found'
}
})
data.push(temp)
});
return {
columns: columns,
data: data,
options: compareTableOptions
}
},
getHeadData(fileIdx, props, columns){
var data = []
props.forEach(prop => {
var temp = { Property: prop }
this.selectedEnvs.forEach(env => {
var found = false;
this.$store.state.jsonObject[env.name].app_config[this.commonFiles[fileIdx]].forEach(envProp => {
if(envProp){
if (prop == envProp["#name"]) {
found = true;
temp[env.name] = envProp["#value"]
}
}
});
if (!found){
temp[env.name] = 'Not found'
}
})
data.push(temp)
});
return {
columns: columns,
data: data
}
},
getProps(fileIdx){
if(this.commonFiles.length == 0) return
var columns = ['Property']
var props = new Set()
this.selectedEnvs.forEach((env, idx) => {
columns.push(env.name)
this.$store.state.branchesToCompare.forEach(branch => {
branch.obj[env.name].app_config[this.commonFiles[fileIdx]].forEach(prop => {
if(prop){
props.add(prop["#name"])
}
})
});
this.$store.state.jsonObject[env.name].app_config[this.commonFiles[fileIdx]].forEach(prop => {
if(prop){
props.add(prop["#name"]);
}
});
});
var ret = { props: props, columns: columns }
return ret;
}
}
}
</script>
I've solved it. The code above is actually fine. Shortly before I posted the code, I was using a computed property in the v-for AND in the getHeadData(), what I think was happening was it was a nested computed property, and on the inner loop it recomputed it and then tried the outer loop again, and so forth. I'm still puzzled why it work on the initial render, but oh well. It is working now.

Working with Vuex with Vue and displaying data

This is kind of a long explanation of an issue that I'm having on a personal project. Basically, I want to set a data property before my page loads when I read in data from a CSV file using D3.JS. I almost have it done but running into a small issue. Please read on to get more detail.
Basically, when the user comes to a page in my application, I want to display weather graphs. Like I said, I'm using D3.js to read in the data and created an action to do that. It works perfectly fine-I can console.log the data and I know its been read. However, in my vue instance I have a data property, which would hold the data set like this:
data() {
return {
name: this.$store.state.name
weatherData: this.$store.state.yearData
}
}
I then want to ensure that the weatherData is filled, with data from the csv file so I display it on the page like this:
<p>{{ weatherData }}</p>
Nothing special here. When the page loads, weatherData is blank. But I have a beforeMount life cycle hook and if I comment out the only line in it then it will display the data. If I then refresh the page, fire the action to get the data and then uncomment out the line in the beforeMount hook then the data appears! So before I continue this is my full code for the store:
export const store = new Vuex.Store({
state: {
name: 'Weather Data'
yearData: []
},
getters: {
},
mutations: {
setYearData(state, data) {
state.yearData = data
}
},
actions: {
getYearData: ({commit}) => {
d3.csv("../src/components/data/alaska.csv")
.then(function(data){
let yearData = []
for (let i = 0; i < data.length; i++){
let day = data[i].AKST
yearData.push(day)
}
//console.log(yearData)
commit('setYearData', yearData)
})
}
})
Here are parts of the vue file: The template:
<p>{{ weatherData }}</p>
The Vue Intance:
export default {
name: 'Weather',
data() {
return {
name: this.$store.state.name,
weatherData: this.$store.state.yearData
}
},
methods: {
...mapActions([
'getYearData'
])
},
beforeMount(){
this.$store.dispatch('getYearData') //(un)Commenting out this line will make my data appear
}
}
Page when it loads: Notice empty array:
Then either comment out or comment the one line in the beforeMount hook and get this: THE DATA!!!
Again, my end goal is to have the action called and the data set before the page finishes loading. Finally, I know that I don't need VUEX but this project is further helping me understand it. Any guidance on why this is happening would be great.
use mapState instead of putting your data in the data object, which sometimes being late on updating the template.
just make your Vue instance to look like:
import {mapState} from 'vuex'
export default {
name: 'Weather',
data() {
return { }
},
computed:{
...mapState({
name: state=>state.name,
weatherData: state=>state.yearData
})
},
methods: {
...mapActions([
'getYearData'
])
},
beforeMount(){
this.$store.dispatch('getYearData') //(un)Commenting out this line will make my data appear
}
thats way, you work directly with one source of truth-the store, and your name and weatherData will be reactive as well.
more about mapState here: https://vuex.vuejs.org/guide/state.html#the-mapstate-helper

When does angular2 #output resolve?

Consider this plunker
HTML
<chart [options]="options"
(load)="saveGraphInstance($event.context)"></chart>
<div (click)="switchGraph()">switch</div>
<div (click)="showLoadingForce()">show loading</div>
Typescript
class AppComponent {
constructor() {
this.options = {
title : { text : 'simple chart' },
series: [{
data: [29.9, 71.5, 106.4, 129],
}],
lang:{
loading: 'your text here',
},
};
}
options: Object;
graph: any;
switchGraph() {
this.options = {
title : { text : 'different chart' },
series: [{
data: [129.9, 171.5, 106.4, 129],
}],
lang:{
loading: 'your text here',
},
};
this.graph.showLoading() // This doesn't work
setTimeout(function() {
this.graph.showLoading() // This also doesn't work
}, 4000);
}
showLoadingForce() {
this.graph.showLoading() // User clicked work
}
saveGraphInstance(graph) {
this.graph = graph;
//this.graph.showLoading() // after loading work
}
}
We see from the above code that in the same function that option change, show loading does not work even if I set time out for more than 4 second
But if its done after load trigger or user initiated, then it always work.
This is very interesting, so my question is the following
If I click switch div and immediately click show loading div, the loading text will show, then the setimeout will execute (because 4 sec delay), but only the setimeout will run into error ERROR TypeError: Cannot read property 'showLoading' of undefined. How is that possible? If showLoadingForce is successful that means saveGraphInstance must have happened
When is (load) execute and resolve? I cannot find the relevant information in github source code
Regarding Q1,
ERROR TypeError: Cannot read property 'showLoading' of undefined
This is an issue with accessing this inside setTimeout(). Inside the setTimeout method this default to window object. To fix this pass the save the the reference to this then access it in setTimeout method.
Refer to the "this" problem.
Regarding Q2, load is defined as output ChartEvent binding in the ChartComponent. This will invoke new instance of EventEmitter.
Use following code to hide the loading image after setTimeout: Updated plunker
saveGraphInstance(graph) {
this.graph = graph;
this.graph.showLoading();
var that = this;
setTimeout(function(graph) {
that.graph.hideLoading();
}, 4000);
}
JS API Reference

setData is not a function + Angular2-Highcharts

I was following simple example to set data to Highcharts using this Angular2-Highcharts module
As shown in the following example, i have made small tweak to dynamically set data to Highcharts. Following is the code snippet :
constructor() {
this.options = {
chart: { type: 'spline' },
title: { text : 'dynamic data example'},
series: [{ data: [2,3,5,8,13] }]
};
setTimeout(() => {
this.chart.series[0].setData([21,31,51,81,13]);
}, 3000);
setTimeout(() => {
this.chart.series.push({data:[]});
this.chart.series[1].setData([100,200,300]);
}, 5000);
}
Plunker link for the same .
Error :
ERROR TypeError: _this.chart.series[1].setData is not a function
at eval (run.plnkr.co/QZBbWi3BVy3DeOzT/app/main.ts!transpiled:28)
My Observation :
What is evident with that error is there is no setData function in the series array in the 1st element. Alternate approach to resolve this is, initializing this.options with empty object with data property :
constructor() {
this.options = {
chart: { type: 'spline' },
title: { text : 'dynamic data example'},
series: [{ data: [2,3,5,8,13] },
{ data: [] },
]
};
}
This is very crude way as i need to do the same for 50 elements in this.options.series if i see them coming dynamically
Is there any efficient and better approach to resolve this error ?
PS : Am new to Highcharts, so please bear with me if am doing something completely wrong at basic level.
setData modifies a series which already exists - if you do not have the series you cannot modify it.
If you want to add a new series, you should use chart.addSeries() method like this:
setTimeout(() => {
this.chart.addSeries({
data: [21,31,51,81,13]
});
}, 5000);
example: http://plnkr.co/edit/61IgH8t3YKjtIOgzpUPB?p=preview

Categories

Resources