How to set data within VueJS lifecycle hook - javascript

I am attempting to use the created lifecycle hook to set a data property on my component. Below is my single-file component. I'm currently seeing "TypeError: Cannot read property 'summary' of undefined" in the console when running this code. This tells me that the template is working with forecastData as the empty object declared in the data property rather than the populated object from created. When I remove the data property entirely I see TypeError: Cannot read property 'currently' of undefined. Clearly, I'm missing something basic here.
<template>
<div>
<p>
<router-link to="/">Back to places</router-link>
</p>
<h2>{{forecastData.currently.summary}}</h2>
<router-link :to="{ name: 'forecast' }">Forecast</router-link>
<router-link :to="{ name: 'alerts' }">Alerts</router-link>
<hr>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'CurrentWeather',
data () {
return {
forecastData: {}
}
},
created: function () {
this.$http.get('/api/forecast/boston').then((response) => {
this.forecastData = response.data;
}, (err) => {
console.log(err)
});
}
}
</script>
<style scoped>
</style>

You are setting the data asynchronously so it doesn't exist when the object is first mounted. When you try to access forecastData.currently.summary the currently property is undefined, which results in your error.
Use a v-if to avoid the error.
<h2 v-if="forecastData.currently">{{forecastData.currently.summary}}</h2>
Alternatively, define a null summary in your initialization.
data () {
return {
forecastData: {
summary: null
}
}
},

Related

How to use the props in vue component?

I try to use a prop in a computed value and i keep getting the error:
[Vue warn]: Error in render: "TypeError: Cannot read property 'length' of undefined"
found in
---> at src/cmps/space-details/space-imgs.vue
at src/pages/space-details.vue
at src/App.vue
Maybe i'm using the prop wrong?
the component:
<template>
<div v-if="imgUrls.length" class="space-imgs" :class="pics">
<img :src="img" v-for="(img, idx) in imgUrls.slice(0, 5)" :key="idx" />
</div>
</template>
<script>
export default {
props: { imgUrls: Array },
computed: {
pics() {
return `pics-${this.imgUrls.length}`;
},
},
};
</script>
and this is how i pass the prop:
<space-imgs :imgUrls="space.imgUrls" />
Thanks
Pass the prop like below. This will work.
<space-imgs :img-urls="space.imgUrls" />
For avoiding wrong prop data in component. initialize prop with default value.
props: {
imgUrls: {
type: Array,
default: [],
required: true
}
}
Your template will be first rendered before the prop is passed, making imgUrls undefined. So just do this: v-if="imgUrls".

Vue.js - How can I solve [Vue warn]: Error in render: "TypeError: Cannot read property 'port' of undefined"?

My object looks like this :
{
"container_status": {
"name": "/dev-ms",
"port": {
"2233/tcp": [
{
"HostPort": "123"
}
]
}
}
}
I want to display value of key HostPort
I try like this :
console.log(data.container_status.port['2233/tcp'][0].HostPort)
It works
But There exist error :
[Vue warn]: Error in render: "TypeError: Cannot read property 'port' of undefined"
My vue component like this :
<template>
...
<v-flex xs4>
<p class="">{{data.container_status.port['6690/tcp'][0].HostPort}}</p>
</v-flex>
...
</template>
<script>
export default {
...
};
</script>
How can I solve this error?
I think that your data object is not ready in component loading, to solve this try this :
<p class="">{{!!data.container_status?data.container_status.port['6690/tcp'][0].HostPort:""}}</p>
or
<p class="" v-if="data.container_status">{{data.container_status.port['6690/tcp'][0].HostPort}}</p>
I would use a computed for something so complex, and the computed will update the value if data.container_status changes
computed: {
HostPort() {
if(!this.data.container_status) {
return '',
}
return this.data.container_status.port['6690/tcp'][0].HostPort
}
}
<p class="">{{HostPort}}</p>
to make sure that another property is not undefined I would use the get of lodash in the computed https://lodash.com/docs/4.17.15#get

vue.js: can't access to router parameters from computed property

I'm trying to pass a string parameter using the link. but it seems that computed or methods property cannot return the parameter value. The whole component stops rendering when I use computed property.
If I directly put {{ $route.params.**** }} on the template, everything works fine. But that's not the way I want.
<template>
<div class="container my-5 py-5">
<div class="row">{{ category }}</div>
<!-- <div class="row">{{ $route.params.category }}</div> -->
</div>
</template>
<script>
export default {
name: "shops",
data() {
return {};
},
computed: {
category: () => {
return this.$route.params.category;
}
}
};
</script>
from router.js file:
{
path: "/:category",
name: "category",
props: true,
component: () => import("./views/Shops.vue")
},
I did't get any error message in the console.
You are facing this error because an arrow function wouldn't bind this to the vue instance for which you are defining the computed property. The same would happen if you were to define methods using an arrow function.
Don't use arrow functions to define methods/computed properties, this will not work.
Just replace
category: () => {
return this.$route.params.category;
}
With:
category() {
return this.$route.params.category;
}
Refer - https://v2.vuejs.org/v2/guide/instance.html#Data-and-Methods
Try with
category(){
return this.$route.params.category;
}
or
category: function() {
return this.$route.params.category;
}
this is not the same in arrow functions than in plain functions: https://medium.freecodecamp.org/when-and-why-you-should-use-es6-arrow-functions-and-when-you-shouldnt-3d851d7f0b26

Sending an Array of Objects to a component in vuejs

I'm a begginer in web development and i'm trying to make a front end using vuejs and vuetify.
My problem is that i can't figure out why I can't pass an array of objects to a component.
My code is the following :
In my main page i got these lines to use the component :
<template>
...
<v-content>
...
<list-2 :objectsProps="clients"/>
...
</v-content>
...
</template>
-----------------------
<script>
import List2 from "./components/List2";
export default {
name: "App",
components: {
List2
},
data() {
return {
...
clients: [],
...
};
},
...
mounted() {
this.clients = [
{
title: "Client1",
description: "Unknown"
},
{
title: "Client2",
description: "Unknown"
},
{
title: "Pradier",
description: "Unknown"
}
];
}
};
</script>
And my component is like that:
<template>
<v-card>
<v-list two-line subheader>
<v-subheader>List</v-subheader>
<v-list-tile v-for="object in objects" :key="object.title" avatar>
<v-list-tile-avatar>
<v-icon x-large>account_circle</v-icon>
</v-list-tile-avatar>
<v-list-tile-content>
<v-list-tile-title>{{ object.title }}</v-list-tile-title>
<v-list-tile-sub-title>{{ object.description }}</v-list-tile-sub-title>
</v-list-tile-content>
<v-list-tile-action>
</v-list-tile-action>
</v-list-tile>
</v-list>
</v-card>
</template>
<script>
export default {
name: "List2",
props: {
objectsProps: []
},
data() {
return {
};
},
computed:{
objects: function(){
return this.objectsProps
}
}
};
</script>
At this point, i don't have enough knowledge on vue to understand what is exactly going on here, but what i'm trying to do is to give a list of objects (which can be a list of clients or a list of vehicles or anything) to my component.
The List2 component shouldn't be aware of what it is displaying as long as it gets some objects with a title and a description.
I use a computed property on the component, because i don't know if it's recommended to do a v-for on the props.
And I constantly get this error :
TypeError: Cannot read property 'filter' of undefined
at render (vuetify.js:7048)
at createFunctionalComponent (vue.runtime.esm.js:4056)
at createComponent (vue.runtime.esm.js:4246)
at _createElement (vue.runtime.esm.js:4416)
at createElement (vue.runtime.esm.js:4353)
at vm._c (vue.runtime.esm.js:4485)
at List2.vue?36c9:37
at Proxy.renderList (vue.runtime.esm.js:3701)
at Proxy.render (List2.vue?36c9:13)
at VueComponent.Vue._render (vue.runtime.esm.js:4540)
Along with these warnings :
[Vue warn]: Invalid prop: type check failed for prop "objectsProps". Expected , got Array.
found in
---> <List2> at src/components/List2.vue
<VContent>
<VApp>
<App> at src/App.vue
<Root>
vue.runtime.esm.js:587 [Vue warn]: Error in render: "TypeError: Cannot read property 'filter' of undefined"
found in
---> <List2> at src/components/List2.vue
<VContent>
<VApp>
<App> at src/App.vue
<Root>
But i have no filter property in my main page or my component, so i don't get why...
So my question are : Is my approach correct, or am i doing it the wrong way?
What should I do to in order to make it work ?
And if you have some tips/advices for a beginner, i'm definetly up to get them !
Thank you !
You probably want to define your property with a default value
props: {
objectsProps: {
type: Array,
default() {
return [];
}
}
}
BTW:
I use a computed property on the component, because i don't know if it's recommended to do a v-for on the props.
No need for a computed property
This is what's happening in your code...
Vue allows specifying a prop of a specific data type like this:
props: {
foo: String
}
or with multiple valid types like this:
props: {
foo: [String, Number] // foo can be a `String` or a `Number`
}
The type array ([String, Number] in the example above) should not be empty:
props: {
foo: [] // invalid: missing types
}
This is how to fix it...
If you were attempting to enable type checking for the prop so that Vue enforced values of type Array, the correct syntax would be:
props: {
foo: Array
}
Or if you were trying to specify an empty array as the default prop value:
props: {
foo: {
default: () => []
}
}
You could even do both:
props: {
foo: {
type: Array,
default: () => []
}
}
demo
But i have no filter property in my main page or my component, so i don't get why...
Although I wasn't able to reproduce that error with the code shown in question, I'm guessing you have a third-party library/component that perhaps uses Array#filter on your array prop.
I had this empty section in my list :
<v-list-tile-action>
</v-list-tile-action>
And that was causing the filter error, i just had to delete it, thank you for your answers !

[Vue warn]: Error in render: "TypeError: _vm.activity.activity is undefined"

I have this VueJS component that is giving me the error [Vue warn]: Error in render: "TypeError: _vm.activity.activity is undefined"
<template>
<div class="activity box">
<h1>{{activity.activity.title}}</h1>
<div>
</div>
<h2>{{activity}}</h2>
</div>
</template>
<script>
let activity = {}
export default {
data () {
return {
activity
}
},
methods: {},
created: function () {
this.$store.dispatch('show_activity', {params: {id: this.$route.params.id}}).then(activity => {
this.activity = activity.data
}, response => {
})
}
}
</script>
The line <h1>{{activity.activity.title}}</h1> is causing the error. If I change it to <h1>{{activity}}</h1> the page loads fine. The strange thing is the first one actually loads the title on the page just fine but the JS error raised causes other js on the page to not run properly. activity is a JSON object loaded from vuex_rest_api
I can't work out why this line is raising an error when it renders fine.
Since the activity object is set asynchronously by fetching some data it does not consist the property activity inside when the template is trying to access it.
It's better to render it after the data is fetched. So use a v-if directive as:
<h1 v-if="activity.activity">{{activity.activity.title}}</h1>
It would be better if you showed some sort of loading to indicate the user that the data is being loaded.
<h1 v-if="activity.activity">{{activity.activity.title}}</h1>
<p v-else> loading.....</p>
You should set an initial value (e.g. null) in the data section and also change the template to check whether activity is actually an object and has the given key defined
<template>
<div class="activity box">
<h1>{{activity && activity.activity ? activity.activity.title : 'Loading ...'}}</h1>
<div></div>
<h2>{{activity}}</h2>
</div>
</template>
<script>
let activity = {}
export default
{
data ()
{
return
{
activity:{}
}
},
methods: {},
created: function ()
{
this.$store.dispatch('show_activity',
{
params:
{
id: this.$route.params.id
}
}).then(activity =>
{
this.activity = activity.data
});
}
}
</script>

Categories

Resources