I'm learning vue js and trying submit form data into a contact card. I'm getting these errors and needed some help solving - Property "phone" was accessed during render but is not defined on instance.
at <Contact onAddContact=fn >
at .
Thank you to anyone that can help!
Here's my code:
Contact.Vue
<template>
<div class="contact">
<li>
<h2>{{ name }}</h2>
</li>
<li>
{{ phone }}
</li>
<li>
{{ email }}
</li>
</div>
</template>
<script>
export default {
}
</script>
CreateAForm.Vue
<template>
<div class="container">
<form id="contact" action="" method="post" #submit.prevent="submitContact">
<h3>Form</h3>
<fieldset>
<input type="text" v-model="enteredName" />
</fieldset>
<fieldset>
<input type="tel" v-model="enteredPhone" />
</fieldset>
<fieldset>
<input type="email" v-model="enteredEmail" />
</fieldset>
<fieldset>
<button name="submit" type="submit" id="contact-submit" data-submit="...Sending">Submit</button>
</fieldset>
</form>
</div>
</template>
<script>
export default {
emits: ['add-contact'],
data() {
return {
enteredName: '',
enteredPhone: '',
enteredEmail: '',
};
},
methods: {
submitContact() {
this.$emit('add-contact',
this.enteredName,
this.enteredPhone,
this.enteredEmail
);
},
},
};
</script>
App.Vue
<template>
<Nav></Nav>
<CreateAForm></CreateAForm>
<contact #add-contact="addContact"></contact>
<new-contact
v-for="contact in contacts"
:key="contact.id"
:id="contact.id"
:name="contact.name"
:phone-number="contact.name"
:email-address="contact.email">
</new-contact>
</template>
<script>
import Nav from './components/Nav.vue';
import CreateAForm from './components/CreateAForm.vue';
import Contact from './components/Contact.vue';
export default {
name: 'App',
components: {
Nav,
CreateAForm,
Contact,
},
methods:{
addContact(name, phone, email) {
const newContact = {
id: new Date().toISOString(),
name: name,
phone: phone,
email: email,
};
this.contacts.push(newContact);
}
}
}
</script>
First of all, This error appears because you don't define name, phone, and email inside Contact.vue. You should define them as props. There are also some other issues:
In $emit you should provide one argument.
contacts should be defined in App.vue data.
You don't have a NewContact component. You mean to use the Contact one.
The #add-contact should be placed in CreateAForm.
Working code:
<template>
<div class="contact">
<li>
<h2>{{ name }}</h2>
</li>
<li>
{{ phoneNumber }}
</li>
<li>
{{ emailAddress }}
</li>
</div>
</template>
<script>
export default {
props: ['name', 'phoneNumber', 'emailAddress'],
}
</script>
<template>
<div class="container">
<form id="contact" action="" method="post" #submit.prevent="submitContact">
<h3>Form</h3>
<fieldset>
<input type="text" v-model="enteredName" />
</fieldset>
<fieldset>
<input type="tel" v-model="enteredPhone" />
</fieldset>
<fieldset>
<input type="email" v-model="enteredEmail" />
</fieldset>
<fieldset>
<button name="submit" type="submit" id="contact-submit" data-submit="...Sending">Submit</button>
</fieldset>
</form>
</div>
</template>
<script>
export default {
emits: ['add-contact'],
data() {
return {
enteredName: '',
enteredPhone: '',
enteredEmail: '',
};
},
methods: {
submitContact() {
this.$emit('add-contact',
{
name: this.enteredName,
phone: this.enteredPhone,
email: this.enteredEmail
});
},
},
};
</script>
<template>
<Nav></Nav>
<CreateAForm #add-contact="addContact"></CreateAForm>
<contact
v-for="contact in contacts"
:key="contact.id"
:id="contact.id"
:name="contact.name"
:phone-number="contact.phone"
:email-address="contact.email">
</contact>
</template>
<script>
import Nav from './components/Nav.vue';
import CreateAForm from './components/CreateAForm.vue';
import Contact from './components/Contact.vue';
export default {
name: 'App',
components: {
Nav,
CreateAForm,
Contact,
},
data() {
return {
contacts: [],
}
},
methods:{
addContact({ name, phone, email }) {
const newContact = {
id: new Date().toISOString(),
name,
phone,
email,
};
this.contacts.push(newContact);
}
}
}
</script>
Related
I'm new to NuxtJS, I was trying to do a simple form to try things out.
The idea is that I have a component that contains the full form
<template>
<div>
<h1>
{{ title }}
</h1>
<form #submit.prevent="handleSubmit">
<input type="email" v-model="email" />
<input type="password" v-model="password" />
<button type="submit">Sign in</button>
</form>
</div>
</template>
<script>
export default {
data: function() {
return {
title: 'Sign in',
email: null,
password: null
}
},
methods: {
handleSubmit: function() {
console.log('Hello')
}
}
}
</script>
It's nothing crazy, and then I'm just calling this component in my page
<template>
<LoginForm />
</template>
<script>
export default {
}
</script>
But when I submit my form I can't see my message in the console, I'm wondering what I did wrong or did I miss something ?
Also it is a good practice to make a component like this or should I divide more my component into small one's ?
I am having problems with the two-way binding of a custom component in Next. Maybe I'm making a silly mistake somewhere. I would be grateful for any help
#Custom Component Input.vue
<template>
<input :value="modelValue" #input="$emit('update:modelValue', $event.target.value)" class="input" type="text">
</template>
<script>
export default {
props:{
modelValue:String,
},
}
</script>
<style lang="scss" scoped>
#import '#/assets/_shared.scss';
.input{
padding: 10px 15px;
background: white;
border: 1px solid #cecece;
border-radius: 4px;
}
</style>
#Page index.vue
<template>
<section class="new-appeal">
<form class="new-appeal-form">
<label class="new-appeal-form-item">
<Input placeholder="Appeal" v-model.trim="cashier_name"/>
</label>
<Button class="submit">Creare appeal</Button>
</form>
</section>
</template>
<script>
export default {
layout:'main',
data:function(){
return{
cashier_name:''
}
},
}
</script>
as you can see I'm trying to do two-way data binding, but unfortunately it doesn't work
In Vue 2 you the default v-model value is just value and in order to update the value you have to emit input event. You can't use update:modelValue in vue 2.
you should use this way,
<Input placeholder="Appeal" v-model.trim="cashier_name"/>
in your custom Input component
<template>
<input :value="value" #input="$emit('input', $event.target.value)" class="input" type="text">
</template>
<script>
export default {
props: ['value']
}
</script>
This is working great and is following the conventions.
index.vue
<template>
<section class="new-appeal">
<form class="new-appeal-form">
<label class="new-appeal-form-item">
<Input v-model.trim="cashierName" placeholder="Appeal" />
</label>
<Button class="submit">Creare appeal</Button>
</form>
</section>
</template>
<script>
export default {
layout: 'main',
data() {
return {
cashierName: '',
}
},
}
</script>
Input.vue
<template>
<input
:value="cashierName"
class="input"
type="text"
#input="$emit('input', $event.target.value)"
/>
</template>
<script>
export default {
name: 'Input',
props: {
cashierName: {
type: String,
default: '',
},
},
}
</script>
Otherwise, you could have it as following too (I'm still renaming cashier_name to camelCase btw)
index.vue
<template>
<section class="new-appeal">
<form class="new-appeal-form">
<label class="new-appeal-form-item">
<Input v-model.trim="cashierName" placeholder="Appeal" />
</label>
<Button class="submit">Creare appeal</Button>
</form>
</section>
</template>
<script>
export default {
layout: 'main',
data() {
return {
cashierName: '',
}
},
}
</script>
Input.vue
<template>
<input
:value="cashierName"
class="input"
type="text"
#input="$emit('update:cashierName', $event.target.value)"
/>
</template>
<script>
export default {
name: 'Input',
// https://vuejs.org/v2/api/#model
model: {
prop: 'cashierName',
event: 'update:cashierName',
},
props: {
cashierName: {
type: String,
default: '',
},
},
}
</script>
i have two components one is Displaying cards which is responsible to show the data into a card which comes from backend(DisplayNotes.vue) and another one is updating the existing data card by opening popup(updateNotes.vue), if the user clicks on any card it opens one popup which is responsible for editing data but in my case if the user clicks on any card it should opens the popup-card(UpdateNotes.vue) along with the existing data,Here my question is How to get data from the card into a popup card [Here i am clicking 4th card ,when ever i click on the forth card the content should bind to the pop-up card]1,please help me to get the data into a popup card
DisplayNotes.vue
<template>
<div class="carddisplay-section" >
<div v-for="note in notes" :key="note.id" id="blur" class="container note">
<div #click="toggle(note.id)" class="card-content">
<h5>{{note.title}}</h5>
<p>{{note.body}}</p>
</div>
<div class="import-icons">
<icons class="imported-icons note-icons" />
<button v-if="flag" class="card-button" type="button" #click="handlesubmit();Togglebtn();">Close</button>
</div>
</div>
<div id="popup">
<UpdateNotes :cardId="clickedCard"/>
</div>
</div>
</template>
<script>
import service from '../service/User'
import icons from './icons'
import UpdateNotes from './UpdateNotes.vue'
export default {
name: 'DisplayNotes',
components: {
icons,UpdateNotes
},
data() {
return {
flag: true,
notes: [{
id: 1,
title: 'Fundoo',
body: 'unlimited notes..'
}, ],
clickedCard:'',
}
},
methods: {
Togglebtn() {
this.flag = !this.flag;
},
async handlesubmit() {
service.userDisplayNotes().then(response => {
this.notes.push(...response.data);
})
},
toggle(id){
var blur=document.getElementById('blur');
blur.classList.toggle('active');
this.clickedCard = id;
var popup=document.getElementById('popup');
popup.classList.toggle('active');
},
}
}
</script>
<style lang="scss">
#import "#/styles/DisplayNotes.scss";
</style>
UpdateNotes.vue[popup]
<template>
<div v-if="flag==false" class="update">
<form class="update-note" #submit.prevent autocomplete="off">
<input name="title" v-model="title" placeholder="Title" />
<textarea name="content" v-model="body" style="resize: none" placeholder="Take a note..." rows="3"></textarea>
<div class="btm-icons">
<icons />
<button id="btn-section" type="submit" #click="handlesubmit();flip();">Close</button>
</div>
</form>
</div>
</template>
<script>
import icons from './icons.vue'
import service from '../service/User'
export default {
components: {
icons
},
props: ['cardId'],
data() {
return {
title: '',
body: '',
flag: false,
}
},
methods: {
flip() {
this.flag = !this.flag;
},
async handlesubmit() {
let userData = {
id: this.cardId,
title: this.title,
body: this.body
}
service.userUpdateNotes(userData).then(response => {
alert("Note updated successfully");
return response;
})
}
}
}
</script>
<style lang="scss" scoped>
#import "#/styles/UpdateNotes.scss";
</style>
As you are passing the id of the card in the popup, similarly pass the data of the currently clicked card in the popup.
UpdateNotes.vue
<template>
<div v-if="flag==false" class="update">
<form class="update-note" #submit.prevent autocomplete="off">
<input name="title" v-model="title" placeholder="Title" />
<textarea name="content" v-model="body" style="resize: none" placeholder="Take a note..." rows="3"></textarea>
<div class="btm-icons">
<icons />
<button id="btn-section" type="submit" #click="handlesubmit();flip();">Close</button>
</div>
</form>
</div>
</template>
<script>
import icons from './icons.vue'
import service from '../service/User'
export default {
components: {
icons
},
props: ['cardId', 'cardContent'],
data() {
return {
title: '',
body: '',
flag: false,
}
},
created () {
this.title = this.cardContent.title;
this.body = this.cardContent.body;
},
methods: {
flip() {
this.flag = !this.flag;
},
async handlesubmit() {
let userData = {
id: this.cardId,
title: this.title,
body: this.body
}
service.userUpdateNotes(userData).then(response => {
alert("Note updated successfully");
return response;
})
}
}
}
</script>
<style lang="scss" scoped>
#import "#/styles/UpdateNotes.scss";
</style>
DisplayNotes.vue
<template>
<div class="carddisplay-section" >
<div v-for="note in notes" :key="note.id" id="blur" class="container note">
<div #click="toggle(note.id)" class="card-content">
<h5>{{note.title}}</h5>
<p>{{note.body}}</p>
</div>
<div class="import-icons">
<icons class="imported-icons note-icons" />
<button v-if="flag" class="card-button" type="button" #click="handlesubmit();Togglebtn();">Close</button>
</div>
</div>
<div id="popup">
<UpdateNotes :cardId="clickedCard" :cardContent="cardContent"/>
</div>
</div>
</template>
<script>
import service from '../service/User'
import icons from './icons'
import UpdateNotes from './UpdateNotes.vue'
export default {
name: 'DisplayNotes',
components: {
icons,UpdateNotes
},
data() {
return {
flag: true,
notes: [{
id: 1,
title: 'Fundoo',
body: 'unlimited notes..'
}, ],
clickedCard: '',
cardContent: {}
}
},
methods: {
Togglebtn() {
this.flag = !this.flag;
},
async handlesubmit() {
service.userDisplayNotes().then(response => {
this.notes.push(...response.data);
})
},
toggle(id){
var blur=document.getElementById('blur');
blur.classList.toggle('active');
this.clickedCard = id;
this.cardContent = this.notes.filter((note) => note.id === id);
var popup=document.getElementById('popup');
popup.classList.toggle('active');
},
}
}
</script>
<style lang="scss">
#import "#/styles/DisplayNotes.scss";
</style>
i have two components Register.vue and Login.vue ,Register.vue is responsible for registration it will contain two headings like Login and Signup ,if the user clicks on Login heading inside the Register page it's automatically hide the Signup(Register.vue) component and it displays the Login.vue , upto this it's working fine[Register.vue page when user clicks on Login thing it should opens Login page ]1.[After clicking Login heading it opens like this ]2in Login page also two headings Login and Signup if the user clicks on the signup heading it will hide the login.vue component and it should display the Register.vue ,it's not working How to fix this thing
Register.vue
<template>
<div class="main">
<div v-if="flag==true" class="container">
<img id="side-img" src="../assets/sideImg.png" alt="notFound" />
<p id="side-content">Online Book Shopping</p>
<div class="box">
<div class="headings">
<h5 class="signin" v-on:click="flip()" id="login" :class="{ active: isLogin }" #click="isLogin = true">Login</h5>
<h5 class="signup" id="signup" :class="{ active: !isLogin }" #click="isLogin = false">signup</h5>
</div>
<form ref="myForm" #submit.prevent="handlesubmit">
<div class="fullname">
<p>FullName</p>
<input type="name" id="name-input" class="namebox" required v-model="fullName" autocomplete="off" pattern="[A-Za-z]{3,12}">
</div>
<div class="username">
<p>EmailID</p>
<input type="email" id="Email-input" class="emailbox" autocomplete="off" required v-model="email" pattern="^[a-z0-9._%+-]+#[a-z0-9.-]+\.[a-z]{2,4}$">
</div>
<div class="password-section">
<p>Password</p>
<input :type="password_type" class="password" :class="{'password-visible': isPasswordVisible }" id="passField" v-model="password" pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[#$!%*?&])[A-Za-z\d#$!%*?&]{6,}$" required>
<i class="bi bi-eye-slash" id="togglePassword" #click="togglePassword();"></i>
</div>
<div class="mobile">
<p>MobileNumber</p>
<input type="tel" class="telephone" autocomplete="off" v-model="mobile" id="tel" pattern="^\d{10}$" required>
</div>
<button class="btn-section" id="btn" type="submit">Signup</button>
</form>
</div>
</div>
<Login v-if="flag==false" />
</div>
</template>
<script>
import Login from './Login.vue'
import service from '../service/User'
export default {
name: 'Register',
components: {
Login
},
data() {
return {
fullName: '',
email: '',
password: '',
mobile: '',
password_type: "password",
isLogin: false,
isPasswordVisible: false,
flag: true,
title: 'Online Book Shopping'
}
},
methods: {
flip() {
this.flag = !this.flag;
},
togglePassword() {
this.password_type = this.password_type === 'password' ? 'text' : 'password'
this.isPasswordVisible = !this.isPasswordVisible
},
handlesubmit() {
let userData = {
fullName: this.fullName,
email: this.email,
password: this.password,
mobile: this.mobile
}
service.userRegister(userData).then(response => {
if (response.status == 201) {
alert("user registered successfully");
this.$refs.myForm.reset();
this.$router.push('/login');
}
return response;
}).catch(error => {
alert("invalid credentials");
return error;
})
}
}
}
</script>
Login.vue
<template>
<div class="main">
<div v-if="flag" class="container">
<img id="side-img" src="../assets/sideImg.png" alt="notFound" />
<p id="side-content">Online Book Shopping</p>
<div class="box">
<div class="headings">
<h5 class="signin" :class="{ active: !isSignup }" #click="isSignup = false">Login</h5>
<!-- <router-link to="/register">
<h5 class="signup" id="signup" :class="{ active: !isLogin }" #click="isLogin = false">signup</h5>
</router-link> -->
<h5 class="signup" id="signup" v-on:click="flip();" :class="{ active: isSignup }" #click="isSignup = true">signup</h5>
</div>
<form #submit.prevent="">
<div class="username">
<p>EmailID</p>
<input type="email" id="Email-input" class="emailbox" autocomplete="off" required v-model="email" pattern="^[a-z0-9._%+-]+#[a-z0-9.-]+\.[a-z]{2,4}$">
</div>
<div class="password-section">
<p>Password</p>
<input :type="password_type" class="password" :class="{'password-visible': isPasswordVisible}" id="passField" v-model="password" pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[#$!%*?&])[A-Za-z\d#$!%*?&]{6,}$" required>
<i class="bi bi-eye-slash" id="togglePassword" #click="togglePassword();"></i>
</div>
<div class="forget-section">
Forgot-password
</div>
<div class="btn-section">
<button type="submit" #click="handlesubmit();" class="login-btn">Login</button>
</div>
<div class="seperator">
<h5><span>OR</span></h5>
</div>
<div class="btn-groups">
<button type="button" class="btn btn-primary">Facebook</button>
<button type="button" class="btn btn-light">Google</button>
</div>
</form>
</div>
</div>
<Register v-else />
</div>
</template>
<script>
import Register from './Register.vue'
import service from '../service/User'
export default {
name: 'Login',
components:{Register},
data() {
return {
email: '',
password: '',
password_type: "password",
isPasswordVisible: false,
isSignup: false,
flag:true,
}
},
methods: {
flip() {
this.flag = !this.flag;
},
togglePassword() {
this.password_type = this.password_type === 'password' ? 'text' : 'password'
this.isPasswordVisible = !this.isPasswordVisible
},
handlesubmit() {
let userData = {
email: this.email,
password: this.password,
}
service.userLogin(userData).then(response => {
if(response.status==200){
alert("user logged in... ");
return response;
}
}).catch(error => {
alert("invalid credentials");
return error;
})
}
}
}
</script>
<style lang="scss" scoped>
#import "#/styles/Login.scss";
</style>
console errors
vue.runtime.esm.js?2b0e:619 [Vue warn]: Unknown custom element: <Register> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
found in
---> <Login> at src/Pages/Login.vue
<Register> at src/Pages/Register.vue
<App> at src/App.vue
<Root>
I am trying to practice vue application using props but when I click on the the name, I tried to do console.log the problem but it hasn't helped me. Maybe I am new to filter option but I want to know what I am doing wrong?
App.vue
<template>
<div id="app">
<h1>All Friends</h1>
<AllFriends :Totalfriends="friends" />
<h1>Online Friends</h1>
<OnlineFriends :Totalfriends="friends" #toggleStatus="toggleStatus" />
</div>
</template>
<script>
import AllFriends from "./components/AllFriends"
import OnlineFriends from "./components/OnlineFriends"
export default {
name: 'App',
components: {
AllFriends,
OnlineFriends
},
data(){
return{
friends: [
{name:'Mario', online: true},
{name:'Luigi', online: false},
{name:'Todd', online: true},
{name:'Bowzer', online: false}
]
}
},
methods: {
toggleStatus(payload){
this.friends = this.friends.filter((friend)=>{
if(friend !== payload){
console.log(friend)
}
})
}
}
}
</script>
OnlineFriends.vue
<template>
<div>
Online Friends
<div v-for="(friends, index) in Totalfriends" :key="index">
<p #click="toggleStatus(friends.name)" v-if="friends.online">{{friends.name}}</p>
</div>
</div>
</template>
<script>
export default {
props:["Totalfriends"],
methods: {
toggleStatus(friend){
this.$emit("toggleStatus",{friend})
}
}
}
</script>
AllFriends.vue
<template>
<div>
All Friends
<div v-for="(friend, index) of Totalfriends" :key="index">
<p>{{friend.name}}</p>
</div>
</div>
</template>
<script>
export default {
name: "AllFriends",
props: ["Totalfriends"]
}
</script>