how to create v-model custom component in Nuxt - javascript

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>

Related

Form validation with NuxtJS

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 ?

Vue: dynamic "v-slot = { value }" causes div to be hidden

In Parent I included one ChildComponent as such:
<template>
<div>
<ChildComponent :value="var1" v-slot="{value}">
<input v-model="value.name"/>
</ChildComponent>
</div>
</template>
<script>
import ChildComponent from "../components/ChildComponent.vue";
export default {
components: { ChildComponent },
data() {
return {
var1: {
name: "Vue.js",
message: "LocalHost"
}
};
}
</script>
ChildComponent:
<template>
<div>
<div id="divToShow" v-if="this.$slots.default || this.$scopedSlots.value">
<slot/>
</div>
<div v-else id="divFallback">
<p>Nothing in your input component!</p>
</div>
</div>
</template>
<script>
export default {
name: "ChildComponent",
props: {
value: String
}
}
</script>
However, divToShow does not appear, so divFallback takes its place. How should I go about making divToShow show up when Parent defines a (seemingly) dynamic name slot like this?

How to bind card data from one component to another component card in vue.js?

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>

Filter empty the array after click on custom event

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>

Vue Js: passing data

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>

Categories

Resources