Reputation: 30005
I am learning Vue.js by writing a small script and ended up with a catch 22 kind of situation.
The JS script (explorer.js
) which handles the Vue.js part:
var vm = new Vue({
el: "#root",
data: {
posts: {},
tags: {}
}
})
qwest.get('/posts.json')
.then(function (xhr, response) {
vm.posts = response;
});
qwest.get('/tags.json')
.then(function (xhr, response) {
vm.tags = response;
});
explorer.js
early:<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/qwest/4.4.6/qwest.min.js"></script>
<link rel="stylesheet" href="/static/css/explorer.css">
<script src="/static/js/explorer.js"></script>
<div id="root">
<button v-for="(content, title) in posts" class="l1 btn">
{{ title }}
<button v-for="tag in content.tags" class="l2 btn">
{{ tag }}
<button v-for="t in tags[tag]" class="l3 btn">
{{ t }}
</button>
</button>
</button>
</div>
I get a Cannot find element: #root
error from Vue.
This is understandable: when explorer.js
runs, the <div id="root">
is not known yet.
explorer.js
late:<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/qwest/4.4.6/qwest.min.js"></script>
<link rel="stylesheet" href="/static/css/explorer.css">
<div id="root">
<button v-for="(content, title) in posts" class="l1 btn">
{{ title }}
<button v-for="tag in content.tags" class="l2 btn">
{{ tag }}
<button v-for="t in tags[tag]" class="l3 btn">
{{ t }}
</button>
</button>
</button>
</div>
<script src="/static/js/explorer.js"></script>
I get a Property or method "data" is not defined on the instance but referenced during render.
error (and other of the same style).
This is also understandable: the v-for
functions try to access data which have not been defined yet.
How (or rather - where) should I load explorer.js
?
Upvotes: 2
Views: 2549
Reputation: 5367
Vue.js should be loaded at the start.
You don't need to specify the data property in order to access it's properties, see the Hello World example:
https://jsfiddle.net/chrisvfritz/50wL7mdz/
I'm not sure what is your data structure but, you could try something like that (without the data property):
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/qwest/4.4.6/qwest.min.js"></script>
<div id="root">
<button v-for="post in posts" class="l1 btn">
{{ post.title }}
<button v-for="tag in tags" class="l2 btn">
{{ tag }}
</button>
</button>
</div>
Just work according to your data structure but without the data
Also, with Vue.js you can't have dynamically added root properties, see https://v2.vuejs.org/v2/guide/reactivity.html, so you must specify the root properties in your data as your initial structure.
The explorer.js should be loaded after your html template (at the end), the warnings you get/errors is due to not defining your model at the start, even nested roots !
other than that everything seems to be fine.
Upvotes: 0
Reputation: 82479
First, you should add explorer.js
at the bottom of your file. You could add it at the top of your file if you wrapped the instantiation of the Vue (new Vue(...)
in a function that only ran when the page was completely loaded, but it's standard practice to add the script at the bottom.
Your primary issue is that nested buttons are invalid HTML. This is the issue that is throwing
Property or method "content" is not defined on the instance but referenced during render.
This appears to mainly be Vue complaining about your invalid HTML. I've modified your template below to something that will actually render, but you'll need to tailor it to your needs.
<div v-for="(content, title) in posts" class="l1 btn">
<button>{{ title }}</button>
<span v-for="tag in content.tags" class="l2 btn" style="margin-left:1em">
<button>{{ tag }}</button>
<span v-for="t in tags[tag]" class="l3 btn">
<button>{{ t }}</button>
</span>
</span>
</div>
Here is a working example.
Upvotes: 2
Reputation: 937
I actually wrote a post that explains the Vue Cannot Find Element error. You'll get this error if you try to instantiate Vue to0 early. In my Vue.js training course, all examples load the Vue.js framework towards the end of the file. In general, I have the Vue.js framework loaded via a script
tag and then another script
block that initializes the Vue instance itself. These two items happen just before the closing body
tag.
In regards to Case #1, just move your script
elements after your <div id="root" ...
element and you should be in good shape.
You can use the v-cloak
directive to create smooth loading experience. The reason that I recommend loading your Vue last is based on recommendations from PageSpeed Insights. These may, or may not, be relevant to your scenario though.
Upvotes: 1