2

I used the vue 2. I had a data from ajax, this is my code example:

<template>
    <div>
        <input type="input" class="form-control" v-model="siteInfo.siteId">
        <input type="input" class="form-control" v-model="siteInfo.info.name">
        <input type="input" class="form-control" v-model="siteInfo.accountData.name">
    </div>
</template>

<script>
export default {
    name: 'Site',
    data() {
        return {
            siteInfo: {},
            /* siteInfoName: '', */
        }
    },
    /*computed: {
        siteInfoName: function() {
            return siteInfo.info.name || '';
        },
        ...
    },*/
    methods: {
        getData() {
            // do ajax get data
            this.$http.post('URL', {POSTDATA}).then(response => {
                /*
                   response example
                   { body: 
                       data: {
                           sitdeId: 1,
                           info: { name: 'test'},
                           accountData: { name: 'accountTest'},
                       }
                   }
                */
                this.siteInfo = response.body.data;
            })
        }
    },
    mounted() {
        this.getData();
    }
}
</script>

I got a warring message

[Vue warn]: Error in render: "TypeError: Cannot read property 'name' of undefined"

  1. I can use computed to fix it, but if I had a lot model, I should write a lot computed.
  2. I should create a lot data for those model?
  3. I should not use an object to bind a lot model?

Does it have another solution for this situation? Thanks your help.

3
  • is 'URL' supposed to be like that? Or is it just to hide from SO? Just in case. Commented Oct 5, 2019 at 8:59
  • I added the response data samepl Commented Oct 5, 2019 at 9:03
  • I just want to know what is the good solution for this case. Commented Oct 5, 2019 at 9:07

2 Answers 2

5

Before the data loads siteInfo.info will be undefined, so you can't access name in the v-model:

v-model="siteInfo.info.name"

Likewise for siteInfo.accountData.name.

My suggestion would be to set the initial value of siteInfo to null and then put a v-if="siteInfo" on the main div. Alternatively you could put a v-if on the individual input elements that checks for siteInfo.info and siteInfo.accountData.

You may also want to consider showing alternative content, such as a load mask, while the data is loading.

Sign up to request clarification or add additional context in comments.

Comments

0

Don't be worried about too many v-models - you can do an iteration on the Object - like with Object.entries().

Vue.component('list-input-element', {
  props: ['siteLabel', 'siteInfo'],
  template: '<div><label>{{siteLabel}}<input type="input" class="form-control" v-model="siteInfo"></label></div>'
})

new Vue({
  name: 'Site',
  el: '#app',
  data() {
    return {
      siteInfo: {},
    }
  },
  methods: {
    getData() {
      // using mockup data for this example
      fetch('https://jsonplaceholder.typicode.com/todos/1')
        .then(response => response.json())
        .then(json => {
          console.log(json)
          this.siteInfo = json
        })
      // do ajax get data
      /*this.$http.post('URL', {
        POSTDATA
      }).then(response => {
        this.siteInfo = response.body.data;
      })*/
    }
  },
  mounted() {
    this.getData();
  }
})
div {
  display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <list-input-element v-for="siteInfo in Object.entries(siteInfo)" :site-label="siteInfo[0]" :site-info="siteInfo[1]" />
</div>

Rounding up

So, when you do the single file template, use a computed value, and return an Object from that.

Base your v-for on that computed, and you'll have no problems.

Something like this:

<template>
    <div>
        <input type="input" class="form-control" v-for="infoEl in siteInfoComputed" v-model="infoEl">
    </div>
</template>

<script>
export default {
    name: 'Site',
    data() {
        return {
            siteInfo: {},
        }
    },
    computed: {
      siteInfoComputed: function() {
          // you could check for all the keys-values you want here, and handle
          // 'undefined' problem here
          // so, actually you "create" the Object here that you're going to use
          let ret = {}
          // checking if this.siteInfo exists
          if (Object.keys(this.siteInfo).length) ret = this.siteInfo
          return ret
      },
    },
    methods: {
        getData() {
            // do ajax get data
            this.$http.post('URL', {POSTDATA}).then(response => {
                /*
                   response example
                   { body: 
                       data: {
                           sitdeId: 1,
                           info: { name: 'test'},
                           accountData: { name: 'accountTest'},
                       }
                   }
                */
                this.siteInfo = response.body.data;
            })
        }
    },
    mounted() {
        this.getData();
    }
}
</script>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.