添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

vue component won't wait for data from controller using axios get, it prompt error:

index.vue?d4c7:200 Uncaught (in promise) TypeError: Cannot read property 'ftth' of undefined

my code are below:

<template>
    <div class="dashboard-editor-container">
        <el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;">
            <line-chart :chart-data="lineChartData"/>
        </el-row>
</template>
<script>
    import LineChart from './components/LineChart';
    import axios from 'axios';
    const lineChartData = {
        all: {
            FTTHData: [],
            VDSLData: [],
            ADSLData: [],
    export default {
        name: 'Dashboard',
        components: {
            LineChart,
        data() {
            return {
                lineChartData: lineChartData.all,
        created() {
            this.getData();
        methods: {
            handleSetLineChartData(type) {
                this.lineChartData = lineChartData[type];
            async getData() {
                axios
                    .get('/api/data_graphs')
                    .then(response => {
                        console.log(response.data);
                        var data = response.data;
                        var i = 0;
                        for (i = Object.keys(data).length - 1; i >= 0; i--) {
                            lineChartData.all.FTTHData.push(data[i]['ftth']);
                            lineChartData.all.VDSLData.push(data[i]['vdsl']);
                            lineChartData.all.ADSLData.push(data[i]['adsl']);
</script>
  

Do I have to use watch method?

Use v-if and v-else to determine whether to show components or not. I show a loading component prior to data being retrieved from server – Savlon Apr 24, 2020 at 5:08 when console.log "data[i]['ftth']" it says "index.vue?d4c7:207 Uncaught (in promise) TypeError: Cannot read property 'ftth' of undefined at eval". Maybe because I use foreach in my controller that is why it takes time to pass data to vue? – Sen Apr 24, 2020 at 5:26

First, because you have such a nested data structure you'll want a computed property to return whether the data is loaded or not. Normally, you could do this check in the template.

computed: {
  isDataLoaded() {
    const nestedLoaded = Object.keys(this.lineChartData).map(key => this.lineChartData[key].length !== 0)
    return this.lineChartData && nestedLoaded.length !== 0

You can use v-if="isDataLoaded" to hide the element until the data has been loaded.

do you know how to let vue-component wait for more than a minute before rendering data? my query to database takes more than 1 minute. – Sen Apr 29, 2020 at 1:16 I'm not sure if any user would sit around for 1 minute waiting for your data to load. You'd better look at ways to optimize your query, and/or handle it in the background while letting the user do other things in your app. – Excalibaard Apr 30, 2020 at 9:11

It is not exactly clear how response.data looks like, but because you're using Object.keys I'm assuming it's an object.

If you need to loop over the keys then when using numeric indexes you most likely won't get an object. So you need to get the key and index i and use that value to access the object. Change this:

for (i = Object.keys(data).length - 1; i >= 0; i--) {
  lineChartData.all.FTTHData.push(data[i]['ftth']);
  lineChartData.all.VDSLData.push(data[i]['vdsl']);
  lineChartData.all.ADSLData.push(data[i]['adsl']);

to this:

const keys = Object.keys(data)
for (i = keys.length - 1; i >= 0; i--) {
  lineChartData.all.FTTHData.push(data[keys[i]]['ftth']);
  lineChartData.all.VDSLData.push(data[keys[i]]['vdsl']);
  lineChartData.all.ADSLData.push(data[keys[i]]['adsl']);

But for looping over object's keys is easier to use this:

for (let key in data) {
  lineChartData.all.FTTHData.push(data[key]['ftth']);
  lineChartData.all.VDSLData.push(data[key]['vdsl']);
  lineChartData.all.ADSLData.push(data[key]['adsl']);

The alternative syntax will feed you keys and in my opinion is easier to read.

var i = 0; for (i = Object.keys(data).length - 1; i >= 0; i--) { lineChartData.all.FTTHData.push(data[i]['ftth']); lineChartData.all.VDSLData.push(data[i]['vdsl']); lineChartData.all.ADSLData.push(data[i]['adsl']); this.lineChartIsLoaded = true;

Use v-if in vue component

<line-chart v-if="lineChartIsLoaded" :chart-data="lineChartData" :date-data="dateData" />
  

Set lineChartIsLoaded to false at default

const lineChartIsLoaded = false;
                Using a 5 second timer is a race condition; not inherently solving the problem if it takes longer than 5 seconds, and a big hit to your user experience.
– Excalibaard
                Apr 24, 2020 at 6:36
                that is also what I experience but for now I will use it since I'm still looking for solutions about it.
– Sen
                Apr 24, 2020 at 7:00
                I misread, I thought you were using setTimeout. The axios setting timeout is just when axios decides to stop trying to get the data. You should be able to remove it without problem. Using v-if and a isLoaded variable is the correct solution.
– Excalibaard
                Apr 24, 2020 at 7:06

You can write dummy data in your data properties before real ones are loading

all: {
  FTTHData: ["Loading..."],
  VDSLData: ["Loading..."],
  ADSLData: ["Loading..."],
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.