I receive the following warning:
[Vue warn]: Extraneous non-emits event listeners (addData) were passed to component but could not be automatically inherited because component renders fragment or text root nodes. If the listener is intended to be a component custom event listener only, declare it using the "emits" option.
at <UserData onAddData=fn<bound dataSubmit> >
at <App>
in my Vue3 app. I use emits:["add-data"] in UserData.vue but the warning still appears.
Here are the relevant parts of the vue project:
app.vue
<template>
<div class="columns">
<div class="column">
<user-data #add-data="dataSubmit" />
</div>
<div class="column">
<active-user #delete-user="deleteUser" v-for="user in users" :key="user.id" :name="user.name" :age="user.age" :id="user.id" />
</div>
</div>
</template>
<script>
export default {
data() {
return {
users: []
}
},
methods: {
dataSubmit(name, age) {},
deleteUser(id) {}
}
}
</script>
UserData.vue
<template>
<h2>Add new user:</h2>
<form #submit.prevent="submitData">
<label>Name*</label>
<input type="text" v-model="name" placeholder="Name" />
<label>Age*</label>
<input type="text" v-model="age" placeholder="Age" />
<button>add</button>
</form>
</template>
<script>
export default {
emits: ["add-data"],
data() {
return {
name: "",
age: ""
}
},
methods: {
submitData() {
this.$emit("add-data", this.name, this.age)
}
}
}
</script>
main.js
import { createApp } from 'vue'
import UserData from './components/UserData.vue'
import ActiveUser from './components/ActiveUser.vue'
import App from './App.vue'
const app = createApp(App);
app.component("active-user", ActiveUser);
app.component("user-data", UserData);
app.mount('#app')
It works fine, but it just displays the warning.
If I change the emits part to emits: ["add-data", "addData"] the warning disappears.
There is an open bug for this:
https://github.com/vuejs/vue-next/issues/2540
For now you'll need to use emits: ['addData'] to avoid the warning.
Related
Consider the following example Vue component:
Template:
<template>
<input
id="pin"
v-model="pin"
type="password"
name="pin"
placeholder="Pin"
#input="removeSpace($event.target)"
/>
</template>
Script:
<script>
import { ref } from 'vue'
const pin = ref('')
const removeSpace = (target) => {
pin.value = target.value.replace(/\s/g, '')
}
</script>
How would I go about moving the removeSpace function in this component to VueX4 store? So I can use it in multiple components? Can't seem to get it to work, the input field doesn't update.
I have tried something as follows:
Template:
<template>
<input
id="test"
v-model="store.state.testPin"
type="text"
name="test"
placeholder="test"
#input="store.dispatch('removeSpace', $event.target)"
/>
</template>
VueX store:
import { createStore } from 'vuex'
const store = createStore({
state: {
testPin: ''
},
actions: {
removeSpace(state, target) {
state.testPin = target.value.replace(/\s/g, '')
}
}
})
export default store
I hope you are all well. I'm currently having some issues with using a component that is inside a parent component. I tried a few things but without success...
The component ModalBoxActionArticle doesn't want to show and I have the following error message :
[Vue warn]: Failed to resolve component: ModalBoxActionArticle at
at <Home
onVnodeUnmounted=fn ref=Ref< undefined > > at
at
Could you please help me with this? Thanks in advance for your time and help.
Find below the vue View that is at the root of these components:
<template>
<div class="home">
<ImageArticle class="home__component"/>
</div>
</template>
<script>
import ImageArticle from "../components/imageArticle"
export default {
name: 'Home',
components: {
ImageArticle,
}
}
</script>
Find below the ImageArticle component (I removed the style)
<template>
<div>
<article class="postWithImage">
<ModalBoxActionArticle/>
<div class="postWithImage__1div">
<picture class="postWithImage__pictureProfile">
<img class="postWithImage__imgProfile" src="../assets/EugenieProfile.jpeg" alt="photo de profile de la personne qui a publiƩ l'image">
</picture>
.... here I removed some html to make it more readable ....
</article>
</div>
</template>
<script>
import ModalBoxActionArticle from '../components/modalBoxActionArticle'
export default {
name: 'ImageArticle',
component : {
ModalBoxActionArticle
},
setup() {
console.log('%c loading ImageArticle component', 'color:green');
return {};
},
}
</script>
Last but not least find below, the component ModalBoxActionArticle that is inside the ImageArticle component
<template>
<div class="modal">
<button class="modal__btt modal__btt--alert">Signaler</button>
<button class="modal__btt">Partager</button>
<button class="modal__btt">Modifier</button>
<button class="modal__btt modal__btt--alert">Supprimer</button>
</div>
</template>
<script>
export default {
name: "ModalBoxActionArticle",
setup() {
console.log('%cloading ModalBoxActionArticle newest component', 'color:red');
return {};
},
}
</script>
In ImageArticle.vue you have defined
component : {
ModalBoxActionArticle
},
This must be like (the letter s must be at the end of the word component):
components : {
ModalBoxActionArticle
},
I made this using vue-cli. I have a component called InputField, and I render and mount the component to #app. I know that it will inject the component to the app, but how can I get the "default" value in index.html and access it in InputField.vue? I've tried to add props: "default" but the default value is undefined.
The idea is to get the default value from the component in html and save it to values in data when component is mounted.
I added the following ...
... to my html but seems like it wont work in vue-cli?
Also in my template I added default="def" like this:
<input default="def" v-model="values" name="my-input" />
But when I refer to "default" in js it is undefined.
InputField.vue
<template>
<div >
<input default="def" v-model="valuess" name="my-input" />
<input
v-model="message"
type="text">
<h2 class="message">{{ message }}</h2>
</div>
</template>
<script>
module.exports={
name:'InputField',
props:["default"],
mounted(){
console.log(this.default);
this.valuess=this.default;
},
updated(){
if(this.valuess===this.default){
return this.$emit('dirty-field',false);
}
this.$emit('dirty-field',true);
},
data: function () {
return {
valuess: '',
message:'heelo',
}
}
}
</script>
index.html
<div id="app">
<InputField default="My default text"></InputField>
</div>
main.js
new Vue({
render: h => h(InputField),
}).$mount('#app');
Try to pass default props like this with :default:
<InputField :default="My default text"></InputField>
I've recently started to create an app with Vue 3 and I'm struggling with authentication when trying to emit an event from child to parent. Here's a sample of my code:
Child
<template>
<form class="msform">
<input #click="goToLogin" type="button" name="next" value="Login" />
</form>
</template>
<script>
import Cookies from "js-cookie";
export default {
emits:['event-login'],
methods: {
goToLogin() {
this.$emit("event-login");
},
},
};
</script>
Parent
<template>
<login v-if='loggedIn' #event-login='logIn'/>
<div class="my-page">
<router-view/>
</div>
</template>
<script>
import Cookies from "js-cookie";
import Login from '../pages/Login'
export default {
name: "MainLayout",
components:{
"login":Login
},
data() {
return {
loggedIn: false,
};
},
methods: {
logIn() {
this.loggedIn = true;
}
}
}
I don't know exactly why the event is not handled in the parent, can I get some help, please?
You're listening for the emitted event on a separate instance of login.
router-view is still just a component like any other, so try moving the handler there instead:
<template>
<login v-if='loggedIn' />
<div class="my-page">
<router-view #event-login='logIn' />
</div>
</template>
I have the following in App.vue
<template>
<div id="app">
<input type="text" v-model="term">
<hello-world text="Button 1" v-if="term === ''"></hello-world>
<hello-world v-else text="Button 2"></hello-world>
</div>
</template>
<script>
import HelloWorld from '#/components/HelloWorld'
export default {
name: 'app',
data() {
return {
term: ''
}
},
components: {
HelloWorld
}
}
</script>
And here's the HelloWorld.vue:
<template>
<div>
<button>{{ text }}</button>
</div>
</template>
<script>
export default {
props: {
text: String
},
created() {
console.log('Created')
},
destroyed() {
console.log('Destroyed')
}
}
</script>
So, when I type something the first component should be destroyed and the second component should be created. However, nothing like that happens. The component neither gets destroyed nor gets created.
It's as if the v-if didn't trigger the created() & destroyed() function. Please help me with this.
Vue uses virtual dom approach. So, it is comparing the virtual tree and it is not identifying changes on structure (oldNode.type === newNode.type). When it occurs, Vue updates the same component instead of destroying the old node and creating a new one.
Try to force Vue to detect virtual tree changes avoiding use siblings with the same tag name and controlled by v-if directive.
Reference:
https://medium.com/#deathmood/how-to-write-your-own-virtual-dom-ee74acc13060
Vue.component('hello-world', {
props: {
text: String
},
created() {
console.log('Created')
},
destroyed() {
console.log('Destroyed')
},
template: "<button>{{ text }}</button>"
});
var app = new Vue({
el: "#app",
data() {
return {
term: ''
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input type="text" v-model="term">
<span><hello-world v-if="!term" text="Button 1"></hello-world></span>
<span><hello-world v-if="term" text="Button 2"></hello-world></span>
</div>
I am not sure what you are trying to achieve, but testing your code logs created from both components
https://codesandbox.io/s/8l0j43zy89
Since you are actually showing conditionally the same component, I don't think it will get destroyed.