From the example inside the petite vue repo:
<script type="module">
import { createApp } from 'https://unpkg.com/petite-vue?module'
createApp({
// exposed to all expressions
count: 0,
// getters
get plusOne() {
return this.count + 1
},
// methods
increment() {
this.count++
}
}).mount()
</script>
<div v-scope>
<p>{{ count }}</p>
<p>{{ plusOne }}</p>
<button #click="increment">increment</button>
</div>
When I am trying to get a p tag like so:
<p ref="foobar">{{ count }}</p>
This returns an error, since this.$refs.foobar is undefined:
increment() {
console.log(this.$refs.foobar.$el)
this.count++
}
How can I get the HTML element inside my javascript through $el?
Credits to #kissu for pointing me to the right discussion form, where I found the answer.
So apparently $refs only works inside of the "component" concept within petite vue.
If you have the following snippet, from the docs, with a ref added to the p tag:
<script type="module">
import { createApp } from 'https://unpkg.com/petite-vue?module'
function Counter(props) {
return {
count: props.initialCount,
inc() {
this.count++
},
mounted() {
console.log(`I'm mounted!`)
}
}
}
createApp({
Counter
}).mount()
</script>
<div v-scope="Counter({ initialCount: 1 })" #vue:mounted="mounted">
<p ref="foobar">{{ count }}</p>
<button #click="inc">increment</button>
</div>
You'll be able to do:
this.$refs.foobar from within that function, to get the element. Note: $el is not needed.
Related
I developed a vuejs program and run the npx serve command. I go to the directory and run npx serve. I browse the http://localhost:300/myvuefile.html , I get the following output only.
{{count}} inside the button. My code :
<script src="https://unpkg.com/vue#3/dist/vue.global.js"></script>
<div id="app">
<button #click="count++">{{ count }}</button>
</div>
<script>
import { createApp } from 'vue'
const app = createApp({
data() {
return {
count: 0
}
}
})
app.mount('#app')
</script>
I have to get the value of the count and onclick the count should increment. Instead I get the output as {{count}} only. Please help to fix this issue.
According to the documentation-
When using the global build of Vue, all top-level APIs
are exposed as properties on the global Vue object.
So, either use like this-
const app = Vue.createApp({
data() {
return {
count: 0
}
}
})
app.mount('#app')
<div id="app">
<button #click="count++">{{ count }}</button>
</div>
<script src="https://unpkg.com/vue#3/dist/vue.global.js"></script>
Or use like this-
const { createApp } = Vue
const app = createApp({
data() {
return {
count: 0
}
}
})
app.mount('#app')
<div id="app">
<button #click="count++">{{ count }}</button>
</div>
<script src="https://unpkg.com/vue#3/dist/vue.global.js"></script>
I would like to use v-bind to create a "data-*" attribute but I probably misunderstood something because what I try doesn't work.
Here is my code :
<script type="module">
import { createApp } from 'https://unpkg.com/vue#3/dist/vue.esm-browser.js'
const idPartenaire = createApp({
data() {
return {
id: 2222,
test:"un_test"
}
}
}).mount('#idpartenaire')
</script>
<div id="idpartenaire" v-bind:data-test="test">ID du partenaire : {{ id }}</div>
The result I expect is this :
<div id="idpartenaire" data-test="un_test">ID du partenaire : 2222</div>
But what I get is this:
<div id="idpartenaire" v-bind:data-test="test" data-v-app="">ID du partenaire : 2222</div>
Anyone could explain me where I'm wrong ?
Apparently, it looks like you cannot have attributes with direct state on the mounted HTML element.
A solution is to nest a block inside of the element you're mounting the Vue instance on.
This works as expected
<script type="module">
import { createApp } from 'https://unpkg.com/vue#3/dist/vue.esm-browser.js'
createApp({
data() {
return {
id: 2222,
test:"un_test"
}
}
}).mount('#idpartenaire')
</script>
<div id="idpartenaire"> <!-- ❌ doesn't work here directly -->
<div :data-test="id"> <!-- ✅ okay here -->
ID du partenaire : {{ id }}
</div>
</div>
If I define a property with the name 'foobar' and then try to create a ref with the name 'foobar', Vue complains that 'foobar' is undefined when I try to access that ref. This only happens when building the vue app e.g. npm run build, but not when serving it e.g. npm run dev. I'm not sure if it happens with Vue 2.
I can fix the issue simply by naming them different things but I am curious as to why this happens as there's nothing in the docs about it?
<script setup>
defineProps({
foobar: {
type: String
}
})
</script>
<template>
<div>
<div ref="foobar">
{{ foobar }}
</div>
</div>
</template>
<script>
export default {
data() {
return {
}
},
mounted() {
// error!
const el = this.$refs.foobar;
}
}
</script>
No error:
<script setup>
defineProps({
foobar: {
type: String
}
})
</script>
<template>
<div>
<div ref="foobar2">
{{ foobar }}
</div>
</div>
</template>
<script>
export default {
data() {
return {
}
},
mounted() {
// no error!
const el = this.$refs.foobar2;
}
}
</script>
Vuepress defines some global properties than can be used in templates, like $page or $site.
https://github.com/vuejs/vuepress/blob/master/packages/docs/docs/guide/global-computed.md
I can use these within the <template> node, but trying to use them within <script> throws an error.
<template>
<div class="page">
<div class="content">
<div>{{ $page.frontmatter.description }} Works fine</div>
<div>{{ $frontmatter.description }} Does not work despite what's in docs</div>
<div>{{ description }} Doesn't work</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
description: this.$page.frontmatter.description, //not defined
description2: $page.frontmatter.description, //nor this
};
},
};
</script>
Your problem is not about using Vuepress Global Computed Properties inside <script> tag, it's actually about using Vuejs Computed Properties inside data().
If you simply create a Vue component like the code snippet below, you will find the variable testMessage is not defined either.
<template>
<div>{{ testMessage }}</div>
</template>
<script>
export default {
data() {
return {
testMessage: this.test
}
},
computed: {
test: function() {
return 'This is a test';
}
}
}
</script>
I don't know the exact reason for this, but I believe it's about the lifecycle of Vue instance. So I suggest you simply access the Global Computed Properties inside computed properties or methods:
<template>
<div>{{ description }}</div>
</template>
<script>
export default {
computed: {
description : function() {
return this.$page.frontmatter.description;
}
}
}
</script>
I'm trying to build a quiz-game with VueJs and up until now everything worked out smoothly, but now that I'm started using dynamic components I'm running into issues with displaying the data.
I have a start component (Start View) that I want to be replaced by the actual Quiz component ("In Progress") when the user clicks on the start button. This works smoothly. But then, in the second components template, the data referenced with {{ self.foo }} does not show up anymore, without any error message.
The way I implemented is the following:
startComponent:
startComponent = {
template: '#start-component',
data: function () {
return {
QuizStore: QuizStore.data
}
},
methods: {
startQuiz: function () {
this.QuizStore.currentComponent = 'quiz-component';
}
}
}
};
And the template:
<script type="x-template" id="start-component">
<div>
<button v-on:click="startQuiz()">
<span>Start Quiz</span>
</button>
</div>
</script>
Note: I'm using x-templates since it somehow makes the most sense with the rest of the application being Python/Flask. But everything is wrapped in {% raw %} so the brackets are not the issue.
Quiz Component:
quizComponent = {
template: '#quiz-component',
data: function () {
return {
QuizStore: QuizStore.data,
question: 'foo',
}
};
And the template:
<script type="x-template" id="quiz-component">
<div>
<p>{{ self.question }}</p>
</div>
</script>
And as you might have seen I'm using a QuizStore that stores all the states.
The store:
const QuizStore = {
data: {
currentComponent: 'start-component',
}
};
In the main .html I'm implementing the dynamic component as follows:
<div id="app">
<component :is="QuizStore.currentComponent"></component>
</div>
So what works:
The Start screen with the button shows up.
When I click on the Start Button, the quizComponent shows up as expected.
What does not work:
The {{ self.question }} data in the QuizComponent template does not show up. And it does not throw an error message.
it also does not work with {{ question }}.
What I don't understand:
If I first render the quizComponent with setting QuizStore.currentComponent = 'startComponent', the data shows up neatly.
If I switch back to <quiz-component></quiz-component> (rather than the dynamic components), it works as well.
So it seems to be the issue that this. does not refer to currently active dynamic component - so I guess here is the mistake? But then again I don't understand why there is no error message...
I can't figure out what the issue is here - anyone?
You may have some issues with your parent component not knowing about its child components, and your construct for QuizStore has a data layer that you don't account for when you set currentComponent.
const startComponent = {
template: '#start-component',
data: function() {
return {
QuizStore: QuizStore.data
}
},
methods: {
startQuiz: function() {
this.QuizStore.currentComponent = 'quiz-component';
}
}
};
const QuizStore = {
data: {
currentComponent: 'start-component',
}
};
new Vue({
el: '#app',
data: {
QuizStore
},
components: {
quizComponent: {
template: '#quiz-component',
data: function() {
return {
QuizStore: QuizStore.data,
question: 'foo'
}
}
},
startComponent
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
<script type="x-template" id="start-component">
<div>
<button v-on:click="startQuiz()">
<span>Start Quiz</span>
</button>
</div>
</script>
<script type="x-template" id="quiz-component">
<div>
<p>{{ question }}</p>
</div>
</script>
<div id="app">
<component :is="QuizStore.data.currentComponent"></component>
</div>
The following worked in the end:
I just wrapped <component :is="QuizStore.currentComponent"></component> in a parent component ("index-component") instead of putting it directly in the main html file:
<div id="app">
<index-component></index-component>
</div>
And within the index-component:
<script type="x-template" id="index-component">
<div>
<component :is="QuizStore.currentComponent"></component>
</div>
</script>
Maybe this would have been the right way all along, or maybe not, but it works now :) Thanks a lot Roy for your help!