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 !
Related
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".
I try to use a v-select input that uses the data I receive from my Vuex store. I have to use a computed property, since my data gets passed from an API.
My template looks like this.
<template>
<v-card v-if="isMounted">
<v-select
v-model="chartData.selected"
:items="chartData.items"
label="Select Item"
multiple
>
</v-select>
{{chartData.selected}}
</v-card>
</template>
<script>
import {mapState} from "vuex"
export default {
data: function () {
return {
isMounted: false,
value: []
}
},
computed: {
...mapState(["clusterValues"]),
chartData() {
return {
items: this.clusterValues.data,
selected: this.clusterValues.data,
}
}
}
}
</script>
I binded this computed property to v-model. However it does not update accordingly. I guess it does not work out with a computed property. (Vue.js - Input, v-model and computed property)
v-model="value". This works, but I it does not allow me to start with every item selected.
Starting like this does not work out: value: this.$store.state.clusterValues
How can I solve this problem?
I am trying to build a component that creates filter buttons and then sends the type attribute in the filters object through the event bus to be handled elsewhere in my app. However, when I added the array of objects (filters) in the data section, I am getting an error of this.filter is not defined when I click on a button.
I would like to keep the filters array in this component because I am also trying to dynamically change the active class to whichever button has been clicked.
Am I missing something that has to do with props? Why am I unable to display the buttons when the data and v-for was on another component? These were the questions I have been asking myself in order of solving this issue.
<template>
<div>
<button
v-for="(filter, index) in filters"
:key="index"
:class="{ active: index === activeItem }"
#click="emitFilter(), selectItem(index)"
:filter="filter"
>
{{ filter.name }}
</button>
</div>
</template>
<script>
import EventBus from '#/components/EventBus'
export default {
props: {
filter: { type: String }
},
data() {
return {
activeItem: 0,
filterResult: '',
filters: [
{ name: 'All', type: 'all' },
{ name: 'Holidays', type: 'holiday' },
{ name: 'Seasons', type: 'season' },
{ name: 'Events', type: 'custom' }
]
}
},
methods: {
emitFilter() {
this.filterResult = this.filter
EventBus.$emit('filter-catagories', this.filterResult)
},
selectItem(index) {
this.activeItem = index
}
}
}
</script>
My button component is used in a filters component
<template>
<div>
<span>filters</span>
<FilterBtn />
</div>
</div>
</template>
<script>
import FilterBtn from '#/components/FilterBtn'
export default {
components: {
FilterBtn
}
// data() {
// return {
// filters: [
// { name: 'All', type: 'all' },
// { name: 'Holidays', type: 'holiday' },
// { name: 'Seasons', type: 'season' },
// { name: 'Events', type: 'custom' }
// ]
// }
// }
}
</script>
As you can see, the commented section is where I had my filters originally, but I had to move them to the button component in order to add the active class.
I'm assuming you were actually trying to access the filter iterator of v-for="(filter, index) in filters" from within emitFilter(). For this to work, you'd need to pass the filter itself in your #click binding:
<button v-for="(filter, index) in filters"
#click="emitFilter(filter)">
Then, your handler could use the argument directly:
export default {
methods: {
emitFilter(filter) {
this.filterResult = filter
//...
}
}
}
You are passing a prop called filter typed string to your component. When you output {{ filter.name }} you are actually referring to this property instead of the variable filter you create within the v-for loop.
Unless you passed a property called "filter" to your component, this property will be undefined. Therefore outputting filter.name will result in this error message.
Yea you dont pass an prop to your component thats why its undefined.
<FilterBtn filter="test" />
Here i pass an prop named filter with the value of test.
Sure you could pass dynamic props. Just bind it.
<FilterBtn :filter="yourData" />
I need to ask: Are you passing an object or an string?
Because you defined your prop to be a string, but you actually use it as an object
{{ filter.name }}
Maybe you should also set the type to Object.
props: {
filter: { type: Object }
},
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
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
}
}
},