Ionic not return data from variable - javascript

im creating a chart using chart.js. and i have 3 function here dataSurvey i use it to return my data from database and createBarChart to generate the chart and then handle to handle onclick chart, im want to display some info when user click the chart.
my variable and loaded function
dataSurveys:any
ionViewDidEnter() {
this.dataSurvey()
}
my dataSurvey code
dataSurvey() {
this.api.get('product/getsurvey/'+this.CekLogin.data.id)
.subscribe((result:any) => {
this.dataSurveys = result.data
if (this.dataSurveys) {
this.createBarChart()
}
})
}
my createBarChart code
createBarChart() {
this.bars = new Chart(this.barChart.nativeElement, {
type: 'pie',
data: {
labels: this.dataSurveys.prodName,
datasets: [{
data: this.dataSurveys.prodScore,
backgroundColor: this.dataSurveys.prodColor,
borderColor: 'rgb(38, 194, 129)',
borderWidth: 1
}]
},
options: {
onClick: this.handle
}
});
}
and my handle code
handle(point, event) {
let item = event[0]
console.log(item)
console.log(this.dataSurveys)
}
i try this command console.log(this.dataSurveys) on dataSurvey and createBarChart function, it return the data, but when i run it from handle function it return me 'undefined'.
how i can fix this issue?

Most probably this in the context of handle method is something else ... not your Ionic Page. You can console.log(this) and see what it actually is.
If you actually need to use the variables logic from your page you can use the JS method apply. It will basically substitute the context with the one you need.
options: {
onClick: this.handle.apply(this)
}
See more information here https://www.w3schools.com/js/js_function_apply.asp

Related

Unexpected error when attempting to update chart data in Chart.js, in a Vue app

I am using Chart.js 3.5 and Vue 3.
I was successfully able to draw a chart, and I am trying to trigger a data change, inside a Vue method. Unfortunately, I encounter the following issue: "Uncaught TypeError: Cannot set property 'fullSize' of undefined".
Edit2: Added a missed }. Code should now be runnable
MyChart.vue:
<template>
<canvas id="chartEl" width="400" height="400" ref="chartEl"></canvas>
<button #click="addData">Update Chart</button>
</template>
<script>
import Chart from 'chart.js/auto';
export default {
name: "Raw",
data() {
return {
chart: null
}
},
methods: {
createChart() {
this.chart= new Chart(this.$refs["chartEl"], {
type: 'doughnut',
data: {
labels: ['VueJs', 'EmberJs', 'ReactJs', 'AngularJs'],
datasets: [
{
backgroundColor: [
'#41B883',
'#E46651',
'#00D8FF',
'#DD1B16'
],
data: [100, 20, 80, 20]
}
]
},
options: {
plugins: {}
}
})
},
addData() {
const data = this.chart.data;
if (data.datasets.length > 0) {
data.labels.push('data #' + (data.labels.length + 1));
for (var index = 0; index < data.datasets.length; ++index) {
data.datasets[index].data.push(123);
}
// Edit2: added missed }
this.chart.update(); } // this line seems to cause the error}
}
},
mounted () {
this.createChart()
},
}
</script>
Edit1: Adding the following to the options makes the chart update successfully, but the error is still present and the animation does not work. The chart flickers and displays the final (updated) state. Other animations, such as hiding/showing arcs do not seem to be afected
options: {
responsive: true,
}
Edit3: Adding "maintainAspectRatio:false" option seems to again stop chart from updating (the above mentioned error is still present)
By walking through the debugger, the following function from 'chart.esm.js' seems to be called successfully a few times, and then error out on last call:
beforeUpdate(chart, _args, options) {
const title = map.get(chart); // this returns null, which will cause the next call to error with the above mentioned exception.
layouts.configure(chart, title, options);
title.options = options;
},
//////////////////////
configure(chart, item, options) {
item.fullSize = options.fullSize;
item.position = options.position;
item.weight = options.weight;
},
This may be a stale post but I just spent several hours wrestling with what seems like the same problem. Perhaps this will help you and/or future people with this issue:
Before assigning the Chart object as an attribute of your Vue component, call Object.seal(...) on it.
Eg:
const chartObj = new Chart(...);
Object.seal(chartObj);
this.chart = chartObj;
This is what worked for me. Vue aggressively mutates attributes of objects under its purview to add reactivity, and as near as I can tell, this prevents the internals of Chart from recognising those objects to retrieve their configurations from its internal mapping when needed. Object.seal prevents this by barring the object from having any new attributes added to it. I'm counting on Chart having added all the attributes it needs at init time - if I notice any weird behaviour from this I'll update this post.
1 year later, Alan's answer helps me too, but my code failed when calling chart.destroy().
So I searched and found what seems to be the "vue way" of handling it: markRaw, here is an example using options API:
import { markRaw } from 'vue'
// ...
export default {
// ...
beforeUnmount () {
if (this.chart) {
this.chart.destroy()
}
},
methods: {
createChart() {
const chart = new Chart(this.$refs["chartEl"], {
// ... your chart data and options
})
this.chart = markRaw(chart)
},
addData() {
// ... your update
this.chart.update()
},
},
}

Unable to get data from created() to data() in VueJS 2

I am fetching data from API inside the created method and i want to use these data in the page.
Here is my code.
created(){
let id = this.$route.params.id
let videos;
this.$axios.get(this.$axios.defaults.apiURL + 'v1.0.0/tips/' +id,).then((response) => {
this.videos = response.data.data;
}, (error) => {
toast.$toast.error('Something went wrong! Please try again', {
position: 'top'
})
});
},
data(){
let videos = this.videos;
return {
video: {
sources: [{
src: videos.video_url,
type: 'video/mp4'
}],
options: {
autoplay: true,
volume: 0.6,
poster: videos.thumbnail
}
}
}
}
I am getting error that thumbnail and video_url is not defined. This 2 values are coming from API response. How can i solve this? Thanks
I can see two obvious issues with your code (without seeing it in action):
created is a synchronous hook, but your axios request is returning a promise. Instead of waiting for the promise, you are immediately trying to show the result, hence the issue you are encountering - the data just hasn't arrived yet.
Your use of this seems a bit chaotic (i.e. let videos = this.videos - where would this.videos come from? The only other 'videos' is declared inside of a different function with let)
There are multiple ways to solve this, depending on what you want to show while you are fetching the data and what type of component this is - if you want to show a spinner while you are waiting for the request to be answered, or if you just want to show some progress bar on the previous page and only enter this one once it's loaded.
In-component loading
In the first case, I would suggest setting a variable or using a loader management solution like vue-wait. Your code could look like this then:
data() {
return {
loading: true,
videos: null,
}
},
computed: {
video() {
return this.videos ? {
sources: [{
src: this.videos.video_url,
type: 'video/mp4'
}],
options: {
autoplay: true,
volume: 0.6,
poster: this.videos.thumbnail
}
} : null
}
},
methods: {
fetch() {
let id = this.$route.params.id
this.$axios.get(this.$axios.defaults.apiURL + 'v1.0.0/tips/' + id, ).then((response) => {
this.videos = response.data.data;
}, (error) => {
toast.$toast.error('Something went wrong! Please try again', {
position: 'top'
})
}).finally(() => (this.loading = false));
},
},
created() {
this.fetch()
},
In your template, you would add somewhere v-if=!loading to make sure that the request has finished before you try to show something
Data-fetching before entering page
If this is a page though, you could request the data in beforeRouteEnter - there's a whole article that explains the principle on the vue site

Can't change my array, because I've got Scope Problems

I don't know why but I have some problems with my Dashboard.
So basically I want to create some fancy Donut Charts.
For that I've prepared a dataset-Array where I put my numbers in. All that works.
But when I get my data from the database I want to change the array, to update the Chart.
This is where I have problems.
So my data() looks like this:
data() {
return {
disturbances_category_0: [],
disturbances_category_1: [],
disturbances_category_2: [],
disturbances_category_3: [],
datasets: [
{
data: [20, 20, 10, 50], //HERE I HAVE TO CHANGE THE NUMBERS <-------------
backgroundColor: ["#A40000", "#580000", "#EC4A3B", "#179C7D"],
hoverBackgroundColor: ["#ff1a1a", "#b30000", "#f4948b", "#66bfac"]
}
],
labels: ["Banana", "Apple", "Strawberry", "Cherry"],
option: {}
};
},
And then there is my created()-Block, where I use Axios + Sequelize and Feathers to get my data:
created() {
axios.get('http://localhost:3030/disruptions/', {
params: {
DisruptionCategory: 0
}
})
.then((response) => {
this.disturbances_category_0 = response.data.data; //HERE IS THE COMPLETE ARRAY
this.datasets[0].data[0] = this.disturbances_category_0.length; //HERE I WANT TO SET THE LENGTH
})
.catch((error) => {
console.log(error.data);
});
//imagine that for the other fruits as well...
console.log(this.datasets[0].data[0]);
}
If I test this script I always get "20" as printout.
I don't know why it doesn't change the datasets.data-Array ... I also tried out to use Array.push but... nothing happened..
I'm sure I forgot something obvious...
It is because the console log likely happened long before your then block executed. Its initial value is an array of four integers before you overwrite it with a length. Try making the created function async and await the axios promise chain to resolve.
async function created() {
await axios.get('http://localhost:3030/disruptions/', { // await the resolve
params: {
DisruptionCategory: 0
}
})
.then((response) => {
this.disturbances_category_0 = response.data.data; //HERE IS THE COMPLETE ARRAY
this.datasets[0].data[0] = this.disturbances_category_0.length; //HERE I WANT TO SET THE LENGTH
})
.catch((error) => {
console.log(error.data);
});
//imagine that for the other fruits as well...
console.log(this.datasets[0].data[0]); // now this should be updated
}
console.log(this.datasets[0].data[0]);
The above will run before the response to your request has been handled since it is asynchronous. Your code will just keep executing while the .then() part will execute on another thread once you get a response from the server.

How to use async data for use with chart.js in ionic

I am calling some data in via an api for an ionic app I'm making. The data is being called asynchronously and I need to assign the data to different variables for use in a chart that gets presented to the user. I'm struggling to assign the data to a variable that I can then access from the function which creates the chart (I'm using chart.js). Initially I've been trying to grab a list of dates from the data for use as the X axis scale, just to get things working.
Been trying quite a few things and failing. I initially thought it was because my variable was block scoped, but now I think its an async issue. Been reading about promises for hours, but although I understand the concept I can't see away to apply it to my current code (presuming the issue is async! I'm a noob on a self teaching mission here).
So this the code which handles pulling in the data from the api
async getData() {
const loading = await this.loadingController.create({
message: 'Loading'
});
await loading.present();
this.api.getData()
.subscribe(res => {
console.log(res);
this.data1 = res[0];
loading.dismiss();
console.log(this.data1);
const datelabel = this.data1.result[1].date;
}, err => {
console.log(err);
loading.dismiss();
});
}
And this is the code which creates the chart
useAnotherOneWithWebpack() {
var ctx = (<any>document.getElementById('canvas-linechart')).getContext('2d');
console.log('GotData', this.datelabel); //just to see what data I've got here if any in the console
var chart = new Chart(ctx, {
// The type of chart we want to create
type: 'line',
// The data for our dataset
data: {
labels: this.datelabel,
datasets: [{
data: [86,114,106],
label: "Africa",
borderColor: "#3e95cd",
fill: false
}, {
data: [282,350,411],
label: "Asia",
borderColor: "#8e5ea2",
fill: false
}, {
data: [168,170,178],
label: "Europe",
borderColor: "#3cba9f",
fill: false
}
]
},
options: {
title: {
display: true,
text: 'World population per region (in millions)'
}
}
});
}
So I'm calling the datalabel variable against labels, but its displaying as undefined on the axis and in the console. I'm expecting to see three months (which are saved as strings in the variable). Tried all sorts now and its driving me a bit mad. I'm not even sure its an async issue, but from what I've done so far it feels like the issue.
Any help really appreciated!!
Not sure when/where you're calling the useAnotherOneWithWebpack() method but one issue from your code is that you're assigning some values to the local constant datelabel but not to the property from the component:
// The following line just creates a local const available only in that scope
const datelabel = this.data1.result[1].date;
Instead, you should be initializing the component's property:
this.datelabel = this.data1.result[1].date;
Keeping that in mind, please try the following:
async getData() {
const loading = await this.loadingController.create({
message: 'Loading'
});
await loading.present();
this.api.getData().subscribe(
res => {
// This line will be executed when getData finishes with a success response
console.log('Inside of the subscribe - success');
console.log(res);
this.data1 = res[0];
this.datelabel = this.data1.result[1].date;
// Now that the data is ready, you can build the chart
this.useAnotherOneWithWebpack();
loading.dismiss();
},
err => {
// This line will be executed when getData finishes with an error response
console.log('Inside of the subscribe - error');
console.log(err);
loading.dismiss();
});
// This line will be executed without waiting for the getData async method to be finished
console.log('Outside of the subscribe');
}

How to refresh the json I get through $http.get without drawing my highchart again and again

As you can see in my code I am calling my Highcharts function inside the $http.get itself and pass the JSON as parameters since my variable becomes undefined if I use it outside the $http.get. Now I want to refresh my data every 30 seconds but since I use drilldown I don't want my graph to be redrawn every single time.
var getChartData = function() {
return $http.get("./AlertsJsonCreation").success(function(response) {
$scope.jsonChart = response;
console.log("Inside refresh", $scope.jsonChart);
});
};
$interval(function() {
getChartData();
}, 5000);
getChartData().then(function(response){
console.log("Refresh then", $scope.jsonChart);
DealerChart($scope.jsonChart.dealer, $scope.jsonChart.dealerDrilldown);
});
function DealerChart(dealer, drilldown) {
...
series: [{
name: 'Regions',
colorByPoint: true,
data: dealer
}],
drilldown: {
series: drilldown
},
....
}

Categories