Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property - vue.js

I am trying make form validation dynamically, all props from the JSON file here I am passing the props parent to child component and that props using for input v-model.
When enter a letter inside the text input, I am getting the following error
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "value"
parent component
<template>
<!--parent component-->
<form action="" #submit.prevent="onSubmit">
<div v-for="formInput_Item in formInput_list" :key="formInput_Item.id">
<ShortText
v-if="formInput_Item.type === 'text'"
:input_id="formInput_Item.input_id"
:form-input-item="formInput_Item.formInput_Item"
:label_type="label_type"
:validations="formInput_Item.validations"
:is-valid="isValid"
:value="value"
/>
<p v-if="!formIsValid" class="text-danger">
Please fix the above errors and submit again.
</p>
<div class="col-12 mt-4">
<button class="btn btn-primary float-end" type="submit">SUBMIT</button>
</div>
</div>
</form>
</template>
<script>
import ShortText from '#/components/FormInputs/ShortText'
export default {
components: {
ShortText,
},
data() {
return {
label_type: 'floating', // floating, overhead, below, left, right
formIsValid: true,
error: this.formInput_list[3].validations.required,
value: '',
isValid: true,
}
},
methods: {
validateForm() {
this.formIsValid = true
if (this.value === '') {
this.isValid = false
this.formIsValid = false
}
},
onSubmit() {
console.log(this.isValid)
console.log('value' + this.value)
this.validateForm()
alert('form')
console.log(this.validateForm())
if (!this.formIsValid) {
alert('error')
return
}
alert('succses')
},
},
}
</script>
Child component
<template>
<div>
<div v-if="label_type === 'floating'">
<div class="form-outline mt-4">
<!-- ESlint is complaining about the mutation on this line 👇 -->
<input v-model="value" type="text" class="form-control" />
<label for="" class="form-label" style="margin-left: 10px">
{{ formInput_Item }}
</label>
<div class="form-notch">
<div class="form-notch-leading" style="width: 15px"></div>
<div class="form-notch-middle" style="width: 100px"></div>
<div class="form-notch-trailing"></div>
</div>
</div>
<p v-if="!isValid" class="text-danger">
This field is must not be empty.
</p>
</div>
<div v-else-if="label_type === 'overhead'" class="form-group">
<label class="form-label" for="timeType">{{ formInput_Item }}</label>
<input id="timeType" type="text" class="form-control" required />
</div>
<div v-else-if="label_type === 'below'" class="form-group">
<input type="text" class="form-control" required />
<label class="form-label">{{ formInput_Item }}</label>
</div>
<div v-else-if="label_type === 'left'" class="row form-group">
<div class="col-lg-4">
<label class="form-label">{{ formInput_Item }}</label>
</div>
<div class="col-lg-7">
<input type="text" class="form-control" required />
</div>
</div>
<div v-else-if="label_type === 'right'" class="row form-group">
<div class="col-lg-7">
<input type="text" class="form-control" required />
</div>
<div class="col-lg-4">
<label class="form-label">{{ formInput_Item }}</label>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
input_id: {
type: Number,
required: true,
},
formInput_Item: {
type: String,
required: true,
},
label_type: {
type: String,
required: true,
},
validations: {
type: Object,
},
value: {
type: String,
default: '',
},
isValid: {
type: Boolean,
},
},
data() {
return {
error: this.validations.required,
}
},
}
</script>

Related

how to $emit in vuejs

VueJS emit doesn't work, I'm trying to change the value of a boolean, but it doesn't want to emit the change
here is the first component:
<template>
<div id="reg">
<div id="modal">
<edu></edu>
</div>
<div :plus="plus" v-if="plus" #open="plus = !plus">
abc
</div>
</div>
</template>
the script:
<script>
import edu from './education/edu.vue'
export default {
components: {
edu
},
data() {
return {
plus: false
}
}
}
</script>
the second component with the emit:
<template>
<div id="container">
<h2>Education</h2>
<form action="">
<input type="text" class="input" placeholder="preparatory/bachelor/engineering..">
<input type="text" class="input" placeholder="University..">
<input type="text" class="input" placeholder="Where?..">
<h6>Start date</h6>
<input type="date" class="input" value="2017-09-15" min="2017-09-15" max="2021-09-15">
<div class="end-date">
<h6>End date</h6>
<div class="flexend">
<h6>present</h6><input type="checkbox" name="" id="checkbox" #click="checked">
</div>
</div>
<input type="date" class="input" v-if="show" value="2017-09-15" min="2017-09-15">
<div class="flex-end">
<button class="btn-plus" #click="$emit('open')"><i class="fas fa-plus"></i></button>
</div>
<div class="flex-end">
<button class="btn">next <i class="fas fa-arrow-right"></i></button>
</div>
</form>
</div>
</template>
the script:
<script>
export default {
props:{
plus: Boolean
},
data(){
return{
show: true,
}
},
I thought this is working, but it seems like it's not
You should use the component name instead of the div element :
<edu :plus="plus" v-if="plus" #open="plus = !plus">
abc
</edu>

How to redirect after success fully registered in vue.js?

I developed one page which is responsible for displaying cart items and the response is coming from backend upto this it's working fine .Now inside same page one more registration page is there and that also integrated with backend API, after successfully registered it should be redirected to /orderSuccess page but it's not redirecting ,Here what is the issue please help me How to fix this issue.
After registered it changes my url path /cart to /ordersuccess also but page is not displaying..please help me to fix this issue
Cart.vue
<template>
<div class="main">
<div class="first-section">
<div class="content">
<h5>My Cart({{books.length}})</h5>
</div>
<div v-for="book in books" :key="book.id" class="container">
<div class="mid-section">
<img v-bind:src="book.file" alt="not found">
<p class="title-section">{{book.name}}</p>
</div>
<div class="author-section">
<p class="author-name">by {{book.author}}</p>
</div>
<div class="price-section">
<h6>Rs.{{book.price}}</h6>
</div>
<div class="icons">
<i class="fas fa-minus-circle"></i>
<input class="rectangle" value=1>
<i class="fas fa-plus-circle"></i>
</div>
</div>
<div class="btn-grps">
<button class="btn" v-on:click="flip()" v-if="hide==true" type="submit">Place Order</button>
</div>
</div>
<div class="second -section">
<div class="details-box">
<input type="text" v-if="hide==true" class="initial-btn" placeholder="Customer Details" />
</div>
<div v-if="hide==false" class="fill-details">
<form #submit.prevent="" class="address">
<h4 class="heading">Customer Details</h4>
<div class="name">
<input type="name" required pattern="[A-Za-z]{3,10}" v-model="name">
<label class="label">Name</label>
</div>
<div class="name">
<input type="text" required v-model="phoneNumber">
<label class="label">Phone Number</label>
</div>
<div class="pin">
<input type="text" required v-model="pincode">
<label class="label">PinCode</label>
</div>
<div class="pin">
<input type="text" required v-model="locality">
<label class="label">Locality</label>
</div>
<div class="address-block">
<input class="address" type="text" required v-model="address">
<label id="Add" class="label">Address</label>
</div>
<div class="city-landMark">
<input type="text" required v-model="city">
<label class="label">City/Town</label>
</div>
<div class="city-landMark">
<input type="text" required v-model="landmark">
<label class="label">LandMark</label>
</div>
<div class="Radio-Buttons">
<p>Type</p>
<div class="radio-btns flex-container">
<div>
<input type="radio" id="Home" value="Home" name="type" v-model="type">
<div class="first-radio"> <label class="home" for="Home">Home</label></div>
</div>
<div>
<input class="work-round" type="radio" id="Work" value="Work" name="type" v-model="type">
<div class="second-radio"> <label for="Work" class="work-label">Work</label></div>
</div>
<div>
<input class="other-round" type="radio" id="Other" value="Other" name="type" v-model="type">
<div class="third-radio"><label for="Other">Other</label></div>
</div>
</div>
<div class="btn-continue">
<button type="submit" #click="handlesubmit();" class="continue">continue</button>
</div>
</div>
</form>
</div>
</div>
</div>
</template>
<script>
import service from '../service/User'
export default {
beforeMount() {
// if (localStorage.getItem("reloaded")) {
// localStorage.removeItem("reloaded");
// } else {
// localStorage.setItem("reloaded", "1");
// location.reload();
// }
service.userDisplayCart().then(response => {
this.books = response.data;
})
},
data() {
return {
flag: true,
hide: true,
booksCount: 0,
name: '',
phoneNumber: '',
pincode: '',
locality: '',
city: '',
address: '',
landmark: '',
type: '',
books: []
}
},
methods: {
flip() {
this.hide = !this.hide;
},
Togglebtn() {
this.flag = !this.flag;
},
handlesubmit() {
let userData = {
name: this.name,
phoneNumber: this.phoneNumber,
pincode: this.pincode,
locality: this.locality,
city: this.city,
address: this.address,
landmark: this.landmark,
type: this.type,
}
service.customerRegister(userData).then(response => {
alert("user registered successfully");
this.$router.push('/ordersuccess');
return response;
})
}
}
}
</script>
<style lang="scss" scoped>
#import "#/styles/Cart.scss";
</style>
router.js
{
path:'/dashboard',
component:Dashboard,
children:[{
path:'/displaybooks',
component:DisplayBooks
},
{
path:'/sortLowtoHigh',
component:sortBooksLowtoHigh
},
{
path:'/sortHightoLow',
component:sortBooksHightoLow
},
{
path:'/cart',
component:Cart
},
{
path:'/ordersuccess',
component:OrderPlace
},
]
}
You can use the history mode on your router settings. This should fix the issue
const routes = {
path: 'Dashboard',
....
}
new VueRouter({routes, mode: 'history'});
this.$router.push({ path: '/ordersuccess' })
https://router.vuejs.org/guide/essentials/navigation.html

How to pass data which is coming as response from backend to the another component in vue.js?

I am developing one page which is responsible for placing order Cart.vue which contains two api calls, handleMail() method is sending email and generating a orderID and i am getting response from backend in network section like this.
{
"message":"order created successfully",
"orderID":87450588
}
i am catching that orderID and stored as a orderNumber,Now i want to pass that orderNumber to another component called orderPlace.vue and i want to display that orderNumber inside template section.for this i am creating Event bus it's not working ,please help me to pass orderNumber to another component ...
Cart.vue
<template>
<div class="main">
<div class="first-section">
<div class="content">
<h5>My Cart({{books.length}})</h5>
</div>
<div v-for="book in books" :key="book.id" class="container">
<div class="mid-section">
<img class="img-section" v-bind:src="book.file" alt="not found">
<p class="title-section">{{book.name}}</p>
</div>
<div class="author-section">
<p class="author-name">by {{book.author}}</p>
</div>
<div class="price-section">
<h6>Rs.{{book.price}}</h6>
</div>
<div class="icons">
<i class="fas fa-minus-circle"></i>
<input class="rectangle" value=1>
<i class="fas fa-plus-circle"></i>
</div>
</div>
<div class="btn-grps">
<button class="btn" v-on:click="flip()" v-if="hide==true" type="submit">Place Order</button>
</div>
</div>
<div class="second -section">
<div class="details-box">
<input type="text" v-if="hide==true" class="initial-btn" placeholder="Customer Details" />
</div>
<div v-if="hide==false" class="fill-details">
<form #submit.prevent="" class="address">
<h4 class="heading">Customer Details</h4>
<div class="name">
<input type="name" required pattern="[A-Za-z]{3,10}" v-model="name">
<label class="label">Name</label>
</div>
<div class="name">
<input type="text" required v-model="phoneNumber">
<label class="label">Phone Number</label>
</div>
<div class="pin">
<input type="text" required v-model="pincode">
<label class="label">PinCode</label>
</div>
<div class="pin">
<input type="text" required v-model="locality">
<label class="label">Locality</label>
</div>
<div class="address-block">
<input class="address" type="text" required v-model="address">
<label id="Add" class="label">Address</label>
</div>
<div class="city-landMark">
<input type="text" required v-model="city">
<label class="label">City/Town</label>
</div>
<div class="city-landMark">
<input type="text" required v-model="landmark">
<label class="label">LandMark</label>
</div>
<div class="Radio-Buttons">
<p>Type</p>
<div class="radio-btns flex-container">
<div>
<input type="radio" id="Home" value="Home" name="type" v-model="type">
<div class="first-radio"> <label class="home" for="Home">Home</label></div>
</div>
<div>
<input class="work-round" type="radio" id="Work" value="Work" name="type" v-model="type">
<div class="second-radio"> <label for="Work" class="work-label">Work</label></div>
</div>
<div>
<input class="other-round" type="radio" id="Other" value="Other" name="type" v-model="type">
<div class="third-radio"><label class="other-label" for="Other">Other</label></div>
</div>
</div>
<div class="btn-continue">
<button type="submit" #click="handlesubmit();handleMail();" class="continue">continue</button>
</div>
</div>
</form>
</div>
</div>
</div>
</template>
<script>
import service from '../service/User';
import { EventBus } from "./event-bus.js";
export default {
created() {
if (localStorage.getItem("reloaded")) {
localStorage.removeItem("reloaded");
} else {
localStorage.setItem("reloaded", "1");
location.reload();
}
service.userDisplayCart().then(response => {
this.books = response.data;
})
},
data() {
return {
flag: true,
hide: true,
booksCount: 0,
name: '',
phoneNumber: '',
pincode: '',
locality: '',
city: '',
address: '',
landmark: '',
type: '',
books: [],
cart:'MyCart',
nameField:'Name',
phoneField:'Phone Number',
pincodeField:'PinCode',
AddressField:'Address',
localityField:'Locality',
cityField:'CityTown',
landmarkField:'LandMark',
orderNumber:''
}
},
methods: {
flip() {
this.hide = !this.hide;
},
Togglebtn() {
this.flag = !this.flag;
},
handlesubmit() {
let userData = {
name: this.name,
phoneNumber: this.phoneNumber,
pincode: this.pincode,
locality: this.locality,
city: this.city,
address: this.address,
landmark: this.landmark,
type: this.type,
}
service.customerRegister(userData).then(response => {
return response;
}).catch(error=>{
alert("invalid customer address");
return error;
})
},
// handleMail(){
// service.confirmMail().then(response=>{
// alert("order placed successfully");
// let orderNumber= response.data.orderID;
// this.$router.push({path: '/ordersuccess'});
// console.log(response);
// return orderNumber;
// }).catch(error=>{
// alert("Error in sending email");
// return error;
// })
// }
handleMail(){
service.confirmMail().then(response=>{
alert("order placed successfully");
let orderNumber= response.data.orderID;
console.log("my num",orderNumber);
EventBus.$emit("emitting-order", orderNumber);
this.$router.push({path: '/ordersuccess'});
console(response);
return orderNumber;
})
},
}
}
</script>
<style lang="scss" scoped>
#import "#/styles/Cart.scss";
</style>
OrderPlace.vue
<template>
<div class="order-place">
<div class="image-container">
<img src="../assets/success.png" alt="not found" />
</div>
<div class="title-container">
<p>Order placed Successfully</p>
</div>
<div class="message-section">
<p>Hurray!!!your order is confirmed {{orderNumber}} and placed successfully contact us in below details
for further communication..</p>
</div>
<div class="title-section">
<div class="email-us">
<p>Email-us</p>
</div>
<div class="contact-us">
<p>Contact-us</p>
</div>
<div class="address">
<p>Address</p>
</div>
</div>
<div class="email-sec">
<p>admin#bookstore.com</p>
</div>
<div class="contact-sec">
<p>+918163475881</p>
</div>
<div class="address-sec">
42, 14th Main, 15th Cross, Sector 4 ,opp to BDA complex, near Kumarakom restaurant, HSR Layout, Bangalore 560034
</div>
<div class="button">
<router-link to="/dashboard" class="btn">Continue Shopping</router-link>
</div>
</div>
</template>
<script>
import { EventBus } from "./event-bus.js";
export default {
name: 'OrderPlace',
data(){
return{
successTitle:'Order placed Successfully',
adminEmailSection:'Email-us',
adminContactSection:'Contact-us',
adminAddressSection:'Address',
adminEmail:'admin#bookstore.com',
adminMobNum:'+918163475881',
orderNumber: ''
}
},
mounted() {
EventBus.$on("emitting-order", orderNo=> {
this.orderNumber = orderNo;
console.log(`Oh, that's great ${orderNo})`);
return orderNo;
});
}
}
</script>
<style lang="scss" scoped>
#import "#/styles/OrderPlace.scss";
</style>
event-bus.js
import Vue from 'vue';
export const EventBus = new Vue();
If the orderPlace.vue component is not active when you do the emit. It cannot receive the element.
You can try to register your order number, in the localStorage. Or call orderPlace.vue as a child component and pass the order number to the props

Vue 2 Vuex - update values via form or add new item

I have following template:
<template>
<div class="is-half">
<form #submit.prevent="save">
<input type="hidden" name="bookID" :value="book.id">
<div class="field">
<label class="label">Title</label>
<div class="control">
<input class="input" type="text" placeholder="Title" :value="book.title">
</div>
</div>
<div class="control">
<div class="select">
<select>
<option
v-for="author in this.$store.state.authors"
:value="author.name"
:selected="author.name == book.author"
>{{ author.name }}</option>
</select>
</div>
</div>
<div class="field">
<label class="label">Description</label>
<div class="control">
<textarea class="textarea" placeholder="Description" :value="book.description"></textarea>
</div>
</div>
<div class="control">
<button class="button is-primary">Submit</button>
</div>
</form>
</div>
</template>
<script>
export default {
data() {
return {
book : {
id: null,
title: '',
isbn: '',
author: '',
description: '',
added: ''
}
}
},
methods: {
save(book) {
console.log(this.book);
}
},
created() {
if(this.$store.state.book != 'undefined'){
this.book = Object.assign({}, this.$store.state.book);
}
},
computed: {}
}
</script>
<style></style>
I am trying to update the value of selected item, but whenever I press save, the object has the same values which it gets on load.
How can I update values if the I load new object, or insert new object if id is null?
If i understand your question, the problem is that when you type something in the input, it doesn't update the model.
The problem is you're using :value to bind the values and this is a one-way binding. For 2 way binding replace all :value with v-model: v-model="book.title"

How can I get value when button clicked ? Vue.js 2

My component vue is like this :
<template>
<div class="modal" tabindex="-1" role="dialog">
...
<div class="form-group">
<input type="file" id="change-image" name="replace">
</div>
<div class="form-group">
<input type="text" class="form-control" id="alt-image">
</div>
<div class="checkbox">
<label>
<input type="checkbox"> Set
</label>
</div>
...
<button type="button" class="btn btn-success" #click="editImageProduct">
{{trans('store.modal.edit.button.save')}}
</button>
...
</div>
</template>
<script>
export default{
...
methods: {
editImageProduct(event) {
// get the data
}
}
}
</script>
When I click the button, I want get value from input type file, input type text and intput type checkbox
I know use javascript or jquery
But I want to get it use vue.js 2
How can I do it?
With checkbox and text input, you can use v-model.
With file input you can get data when user upload image, use event onChange
Example code:
new Vue({
el: '#app',
data: {
image: '',
altImage: '',
set: false,
},
methods: {
onUpload(e) {
this.image = e.target.files || e.dataTransfer.files;
},
editImageProduct() {
console.log('File object', this.image);
console.log('Image name', this.image[0].name);
console.log('Alt Image', this.altImage);
console.log('Set', this.set);
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.min.js"></script>
<div id="app">
<div class="form-group">
<input type="file" #change="onUpload">
</div>
<div class="form-group">
<input type="text" class="form-control" v-model="altImage">
</div>
<div class="checkbox">
<label><input type="checkbox" v-model="set"> Set</label>
</div>
<button type="button" class="btn btn-success" #click="editImageProduct">Save</button>
</div>
use v-model in your form
<input type="file" id="change-image" name="replace" v-model="file">
<input type="text" class="form-control" id="alt-image" v-model="text">
<input type="checkbox" v-model="checkbox">
export default {
data: function(){
return {
file: null,
checkbox: null,
text: null,
}
},
methods: {
editImageProduct() {
console.log(this.file, this.checkox, this.text);
}
}
}
EDITED:
try to look into this example for file inputs, hope it'll help you http://codepen.io/Atinux/pen/qOvawK/