Vue 3 - cannot name ref same as prop - why? - vue.js

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>

Related

Why isn't this list render working in Vue 3?

My App.vue looks like this:
<template>
<HelloWorld />
</template>
<script setup>
import HelloWorld from './components/HelloWorld.vue'
// This starter template is using Vue 3 experimental <script setup> SFCs
// Check out https://github.com/vuejs/rfcs/blob/script-setup-2/active-rfcs/0000-script-setup.md
</script>
As you can see, I've imported the Component HelloWorld.
And HelloWorld.vue looks like this:
<template>
<ul>
<li v-for="item in items" :key="item.message">
{{ item.message }}
</li>
</ul>
<h1>OK</h1>
</template>
<script>
const Viewer = {
data() {
return {
items: [{ message: 'Foo' }, { message: 'Bar' }]}
},
}
</script>
The header element "OK" is rendering, but the list messages are not.
I do not know what that Viewer object is. Your template cannot access the items object.
You can use the script setup :
<script setup>
import { ref } from 'vue'
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
</script>
or the default script :
<script>
import { ref } from 'vue'
export default {
setup (props) {
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
return { items }
}
}
</script>
In HelloWorld.vue, your script block should be like
<script setup>
import { ref } from 'vue'
export const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
</script>
As you are using <script setup> syntax, you only need this code to make it works:
<script setup>
import { ref } from 'vue'
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
</script>
No data or return statements are required

Prop Sent to Component is Undefined

i'm really stuck in this silly problem. i worked with many props but this one is a headache. maybe i'm missing something...!!!
i'm sending an object as prop from my page to a component (as i did many times!!) but on my component it's undefined!! i tried many ways (some simple data instead of obj, not bind prop, ...) but nothing!
BTW i'm on nuxt 2.13
here's my code:
page:
<template>
<mycomp :err="inputError" />
<template>
<script>
import mycomp from '~/components/mycomp'
export default{
components:{
'mycomp': mycomp
}
data(){
return{
inputError: {
error: false,
msg: null
}
}
},
}
</script>
and my component:
<template>
<div>
{{err}} --> this show nothing too
</div>
<template>
<script>
export default{
props:['err']
data(){
return{
//
}
},
create(){
console.log(this.err) // undefined
}
}
</script>
You are making many typo mistakes. like kerbh0lz mentioned. I urge you to validate the incoming props. It will save you a lot of time in debugging.
Anyway here is the working snippet
//App.vue
<template>
<div id="app">
<HelloWorld :err="inputError"/>
</div>
</template>
<script>
import HelloWorld from "./components/HelloWorld";
export default {
name: "App",
components: {
HelloWorld
},
data() {
return {
inputError: {
error: false,
msg: null
}
};
}
};
</script>
//HelloWorld.vue
<template>
<div class="hello">
<h1>{{ err }}</h1>
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
err: {
type: Object
}
},
created() {
console.log(this.err);
}
};
</script>
Sandbox

Access global computed properties in <script> tag

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>

Vue-cli change object value globally

I have this code in file app.vue :
<template>
<div id="app">
<button v-on:click="component = 'login'">aa</button>
<component v-bind:is="component"></component>
</div>
</template>
<script>
import acceuil from './components/acceuil.vue'
import login from './components/login.vue'
export default {
name: 'app',
components: {
acceuil,
login
},
data(){
return {
component: 'acceuil'
}
}
}
</script>
How can I toggle between acceuil/login in component from a different vue file ?
You need to pass the imported dependency (the object or the name of the component as a string) to v-bind:is. You can do this by returning it in a computed function and pass it to a computed property, which you then can use in the template.
<template>
<div id="app">
<button v-on:click="isLogin = true">Show Login</button>
<component v-bind:is="currentComponent"></component>
</div>
</template>
<script>
import acceuil from './components/acceuil.vue';
import login from './components/login.vue';
export default {
name: 'app',
data () {
return {
isLogin: false
};
},
computed: {
currentComponent () {
return this.isLogin ? login : acceuil;
}
},
};
</script>
See also the documentation of dynamic components in the official docs.

Global check user Logged In - NuxtJS

I config a global check user if LoggedIn or not to rendering components in NuxtJS but I cant do it. Please help me.
I write computed to wrapper components (layouts/default.vue)
~/layouts/default.vue
<template>
<router-view></router-view>
</template>
<script>
import { mapState } from 'vuex'
export default {
computed: {
computed: {
...mapGetters({
LoggedIn: 'authUser'
})
}
}
}
</script>
But I cant use it on children components / pages.
~/pages/index.vue
<template>
<div class="index-page">
<div class="" v-if="LoggedIn">
asdasd
</div>
</div>
</template>
<script>
export default {
mounted() {
console.log(this.LoggedIn)
// Result: Undefined
}
}
</script>