I am new to Vue and I am trying to bind an element with a fairly complex data object using Vue with a nested component.
I believe I have set this up correctly according to the documentation but I’m not seeing any examples that match my situation exactly.
The error I’m getting is vue.js:584 [Vue warn]: Property or method "factions" is not defined on the instance but referenced during render.
This message is displayed for every json object property that is referenced in the markup. I’m guessing there is something relatively simple here that I’m missing but I cannot determine what that is. Any help is appreciated, thank you!
Here is a fiddle: https://jsfiddle.net/rjz0gfLn/7/
And the code:
var x = { "factions": [ { "id": 0, "name": "Unknown", "img": "Unknown.png" }, { "id": 1, "name": "Light", "img": "Light.png" }, { "id": 2, "name": "Dark", "img": "Dark.png" } ], "roles": [ { "id": 0, "name": "Unknown", "img": "Unknown.png" }, { "id": 1, "name": "Assassin", "img": "Assassin.png" }, { "id": 2, "name": "Mage", "img": "Mage.png" } ], "cacheDate": 1521495430225 }; console.log("data object", x); Vue.component("filter-item", { template: `<li class="fitem"> <input type="checkbox" class="fcheck" /> <img :src="img" class="fimg" /> <span class="fname"> {{name}} </span> </li>`}); Vue.component("filter-items", { template: `<ul class="flist"> <filter-item v-repeat="factions"></filter-item> <li class="fseperator"/> <filter-item v-repeat="roles"></filter-item> </ul>`}); var v = new Vue({ el: "#filters", data: x });
<nav id="filter-drawer"> <ul id="filters" class="flist"> <filter-items></filter-items> </ul> </nav>
Advertisement
Answer
You have to declare every data you want to pass to the children as props
in those child components. Additionally you need to pass each prop from the parent using :fieldnameinchild="value"
(shorthand for v-bind:fieldnameinchild="value"
.
In your case, you’ll need to do that in several places:
Parent:
<filter-items :factions="factions" :roles="roles"></filter-items>
And child:
<filter-item v-for="f in factions" :img="f.img" :fimg="f.fimg" :name="f.name" :key="'f'+f.id"></filter-item> <filter-item v-for="r in roles" :img="r.img" :fimg="r.fimg" :name="r.name" :key="'r'+r.id"></filter-item>
Notice, in vue2 you want to use v-for
instead of v-repeat
.
Also, add :key
to the v-for
:
[Vue tip]: : component lists rendered with
v-for
should have explicit keys. See https://vuejs.org/guide/list.html#key for more info.
See updated fiddle: https://jsfiddle.net/acdcjunior/rjz0gfLn/21/
var x = { "factions": [ { "id": 0, "name": "Unknown", "img": "img.png" }, { "id": 1, "name": "Light", "img": "/a/a6/Light.png" }, { "id": 2, "name": "Dark", "img": "/0/0e/Dark.png" } ], "roles": [ { "id": 0, "name": "Unknown", "img": "img.png" }, { "id": 1, "name": "Assassin", "img": "/6/69/Assassin.png" }, { "id": 2, "name": "Mage", "img": "/2/20/Mage.png" } ], "cacheDate": 1521495430225 }; console.log("data object", x); Vue.component("filter-item", { template: `<li class="fitem"> <input type="checkbox" class="fcheck" /> <img :src="img" class="fimg" /> <span class="fname"> {{name}} </span> </li>`, props: ['img', 'fimg', 'name'] }); Vue.component("filter-items", { template: `<ul class="flist"> <filter-item v-for="f in factions" :img="f.img" :fimg="f.fimg" :name="f.name" :key="'f'+f.id"></filter-item> <li class="fseperator"/> <filter-item v-for="r in roles" :img="r.img" :fimg="r.fimg" :name="r.name" :key="'r'+r.id"></filter-item> </ul>`, props: ['factions', 'roles'] }); var v = new Vue({ el: "#filters", data: x });
<script src="https://unpkg.com/vue"></script> <nav id="filter-drawer"> <ul id="filters" class="flist"> <filter-items :factions="factions" :roles="roles"></filter-items> </ul> </nav>