I am new to Vue js, working with examples in docs on Codesandbox. This code showing me error
[Vue warn]: Property or method "todos" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
I couldn't detect where is the problem exactly.
<template>
<div id="app">
<ol>
<li v-bind:key="todo.text" v-for="todo in todos">{{ todo.text }}</li>
</ol>
</div>
</template>
<script>
import Vue from "vue";
var app = new Vue({
el: "#app",
data: {
todos: [
{ text: "Learn JavaScript" },
{ text: "Learn Vue" },
{ text: "Build something awesome" }
]
}
});
</script>
<style>
style here
</style>
Here is a live example of the code and the problem
Here is the updated code.
The todos variable you declared was not in the instance of vue.
You should declare your data property as below.
<template>
<div id="app">
<ol>
<li v-bind:key="todo.text" v-for="todo in todos">{{ todo.text }}</li>
</ol>
</div>
</template>
<script>
import HelloWorld from "./components/HelloWorld";
export default {
name: "App",
components: {
HelloWorld
},
data() {
return {
todos: [
{ text: "Learn JavaScript" },
{ text: "Learn Vue" },
{ text: "Build something awesome" }
]
};
}
};
https://codesandbox.io/s/9o2036km1r
Related
I am trying to replicate the vue tutorial example (found here: https://v3.vuejs.org/guide/component-basics.html#passing-data-to-child-components-with-props ), but with no success. Below is my code. I have a view called TA.vue, that i would like to import the component into and render. Any ideas what I am doing wrong?
TA.vue (the view):
<template id="front">
<b-container style="margin-top: 9rem;">
<b-row>
<div id="blog-posts-events-demo" class="demo">
<div>
<blog_post
v-for="post in posts"
:key="post.id"
:title="post.title"
></blog_post>
</div>
</div>
</b-row>
</b-container>
</template>
<script>
import blog_post from '../components/blog_post' // import the Header component
export default {
name: 'talent-acquisition',
components: {
blog_post
}
}
</script>
blog_post component:
Vue.component('blog_post', {
el: '#front',
data() {
return {
posts: [
{ id: 1, title: 'My journey with Vue'},
{ id: 2, title: 'Blogging with Vue'},
{ id: 3, title: 'Why Vue is so fun'}
]
}
},
props: ['title'],
template: `
<div class="blog_post">
<h4>{{ title }}</h4>
</div>
`
})
app.mount('#blog-posts-events-demo')
EDIT:
After following Amaarrockz suggestion, I have the following error:
vue.runtime.esm.js?2b0e:619 [Vue warn]: Failed to mount component: template or render function not defined.
found in
---> <BlogPost> at src/components/blog_post.vue
<TalentAcquisition>
<App> at src/App.vue
<Root>
The thing is you have array 'posts' defined in your child component('blog_post') which you are trying to iterate from the parent.
The better implementation would be to define the array in the parent component .
Please find the modifications below
TA.vue
<template id="front">
<b-container style="margin-top: 9rem;">
<b-row>
<div id="blog-posts-events-demo" class="demo">
<div>
<blog_post
v-for="post in posts"
:key="post.id"
:title="post.title"
></blog_post>
</div>
</div>
</b-row>
</b-container>
</template>
<script>
import blog_post from '../components/blog_post' // import the Header component
export default {
name: 'talent-acquisition',
components: {
blog_post
},
data() {
return {
posts: [
{ id: 1, title: 'My journey with Vue'},
{ id: 2, title: 'Blogging with Vue'},
{ id: 3, title: 'Why Vue is so fun'}
]
}
},
}
</script>
blog_post component:
Vue.component('blog_post', {
el: '#front',
props: ['title'],
template: `
<div class="blog_post">
<h4>{{ title }}</h4>
</div>
`
})
app.mount('#blog-posts-events-demo')
What I want to achieve is something like:
<li v-for="(item, index) in items" :key="index>
<div v-if="item.Component">
<item.Component :value="item.value" />
</div>
<div v-else>{{ item.value }}</div>
</li>
But anyway I don't like at all this solution. The idea of defining Component key for an item in items list is hard to maintain since at least it is hard to write it in template-style way (usually we are talking about too long HTML inside). Also I don't like to wrap item.Component inside div.
data() {
return {
list: [{
value: 'abc',
Component: {
props: ['value'],
template: `123 {{ value }} 312`
}
}]
};
}
Does anyone know the best-practice solution for this and where Vue describes such case in their docs?
You can use Vue's <component/> tag to dynamically set your component in your list.
<li v-for="(item, index) in items" :key="index>
<component v-if="item.Component" :is="item.Component" :value="item.value"></component>
<div v-else>{{ item.value }}</div>
</li>
<script>
...,
data: () => ({
list: [{
value: 'abc',
Component: {
props: ['value'],
template: `<div>123 {{ value }} 312</div>` // must be enclosed in a element.
}
}]
})
</script>
You can also import a component too so you can create a new file and put your templates and scripts there.
Parent.vue
<script>
import SomeComponent from "#/components/SomeComponent.vue"; //import your component here.
export default {
data() {
return {
list: [
{
value: "abc",
Component: SomeComponent // define your imported component here.
},
]
};
}
};
</script>
SomeComponent.vue
<template>
<div>123 {{ value }} 312</div>
</template>
<script>
export default {
name: "SomeComponent",
props: ["value"]
};
</script>
Here's a demo.
I've recently hit a wall with vue. Currently we three components Parent.vue ChildOne.vue and ChildTwo.vue. Parent Passes some object data (from a state) to the ChildOne component.
The ChildOnecomponent has the ChildTwo component as a custom element. On that custom element <ChildTwo></ChildTwo> we have a v-for loop that loops through the data and the ChildTwo component is just for html formatting the data.
What I want to is on a click add a custom class .selected to a div and remove it from the other div if selected, much like my example here.
https://codepen.io/david-wh/pen/gOrzQVR
Here is a sandbox of the full app I'm using:
https://codesandbox.io/s/onclick-forked-tkkre
Parent
<template>
<div>
<ChildOne :container-slot-data="ObjectData"></ChildOne>
</div>
</template>
<script>
import ChildOne from "./childComponentOne.vue";
export default {
name: "HelloWorld",
components: {
ChildOne
},
data() {
return {
ObjectData: [
{
id: "1",
name: "foo",
type: "aug",
subType: "1"
},
{
id: "2",
name: "bar",
type: "aug",
subType: "2"
},
{
id: "3",
name: "foobar",
type: "gear",
subType: "6"
}
]
};
}
};
</script>
ChildOne
<template>
<div class="Testing">
<ChildTwo v-for="(itemData, index) in containerSlotData" :key="index" :item-data="itemData"></ChildTwo>
</div>
</template>
<script>
import ChildTwo from "./childComponentTwo.vue";
export default {
name: "ChildOne",
components: {
ChildTwo
},
data() {
return {
current: null
};
},
props: {
containerSlotData: {
type: Array,
default: null
}
}
};
</script>
ChildTwo
<template>
<!-- <div class="selected"> -->
<div>
<ul>
<li>{{ itemData.id }}</li>
<li>{{ itemData.name }}</li>
<li>{{ itemData.subType }}</li>
</ul>
<hr>
</div>
</template>
<script>
export default {
name: "Childtwo",
data() {
return { current: null };
},
props: {
itemData: {
type: Object,
default: null
}
}
};
</script>
If all you want to do is to toggle the class on the elements, I suggest:
In ChildOne add a selectedItem to data and set it with #click handler.
In ChildTwo add a #click hanlder that will emit click event to the ChildOne compontent.
You can see a working example forked from your CodeSandbox here
I have added font-weight: bold to the .selected class to make it visible.
in my app i need to add components to the dom after fetching data from an api
i have a component called Carousel and a component called Home
so i don't know how many carousels i need in my Home component
the question is : how can i add components using for loop from inside methods:{}
My Code :
Home.vue
<template>
<div>
<template
v-for="widget in widgets"
v-bind:is="Carousel">
{{ widget }}
</template>
</div>
</template>
<script>
import Carousel from './widgets/Carousel.vue'
export default {
components: {
Carousel
},
data() {
return {
page_content: [],
widgets: [],
}
},
created() {
this.getHomeContent();
},
methods:
{
addWidget() {
this.widgets.push('Carousel')
},
getHomeContent() {
window.axios.get(window.main_urls["home-content"]).then(response => {
this.page_content = JSON.parse(JSON.stringify(response.data));
this.addWidget()
});
}
}
}
</script>
Carousel.vue
<template>
<div>
<div :class="this.type == 'full' ? '' : 'container'">
Slider
</div>
</div>
</template>
<script>
export default
{
name:'Carousel',
props:[
'type',
'showTitle',
'dots',
'controls',
'data'
],
methods:
{
}
}
</script>
How to create as much carousels is i need using loop
the above code just give me a string 'carousel'
i want the component to be rendered
Here is a working example of dynamic components with properties
<div>
<template v-for="item in widgets">
<component :is="item.name" :name="item.name" v-if="item.name==='carousel'"></component>
</template>
</div>
The data in widgets
widgets: [
{name: 'carousel'},
{name: 'carousel'},
{name: 'test'},
{name: 'carousel'},
]
then it will create three components.
I created a test component like this to check this
components: {
'carousel': {
template: "<div>Dynamic component {{name}}</div>",
props: ["name"]
}
},
Given the following Vue code, how does it know to render the v-for again when selected is changed?
It makes complete sense to me when todos is changed.
So, Vue notices that there's a method isSelected involved and then uses "reflection" to watch the selected value, since it's an instance value?
Is that what's happening under the hood?
<div id="app">
<ol>
<li v-for="todo in todos" :class="{ 'selected': isSelected(todo.text) }">
{{ todo.text }}
</li>
</ol>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
todos: [
{ text: 'foo' },
{ text: 'bar' },
{ text: 'quz' }
],
'selected': 'bar'
},
methods: {
isSelected: function(text) {
return text != this.selected;
}
}
})
app.todos.push({ text: 'test' });
app.todos[0].text = 'change';
app.selected = 'foo';
</script>