I created a Vue component that has several forms that can be submitted by the user. On submit, the form will send some data to my backend. The problem is that my backend needs to know which form was submitted, and this input doesn't depend on the user, so I added a hidden input so that when the user send the data, my backend can also know which type of form was submitted. I tried the following:
<template>
<div>
<div v-if="order=='total'">
<form #submit="formSubmit">
<input type="hidden" v-model="order_type" value="form1">
<input type="text" class="form-control" v-model="amount">
<br>
<input type="text" class="form-control" v-model="price">
<br>
<button class="btn btn-primary">BUY</button>
</form>
</div>
<div v-else-if="order=='partial'">
<input type="hidden" v-model="order_type" value="form2">
<input type="text" class="form-control" v-model="amount">
<br>
<input type="text" class="form-control" v-model="price">
<br>
<button class="btn btn-primary">BUY</button>
</form>
</div>
<br>
</div>
</template>
<script>
import axios from 'axios'
export default {
props:{
order:{
type:String,
default:'total'
},
},
mounted() {
console.log('Component mounted.')
},
data() {
return {
name: '',
description: '',
output: ''
};
},
methods: {
formSubmit(e) {
e.preventDefault();
let currentObj = this;
axios.post('MYURL', {
order_type: this.order_type,
price: this.price,
amount: this.amount
})
.then(function (response) {
currentObj.output = response.data;
})
.catch(function (error) {
currentObj.output = error;
});
}
}
}
</script>
The problem with this code is that order_type doesn't get sent with the form. I have read somewhere that Vue doesn't allow hidden values, so is there any other way to do this?
You can pass a param to the method:
#submit.prevent="formSubmit("form1")"
And in the method:
formSubmit(value) {
let currentObj = this;
axios
.post("MYURL", {
price: this.price,
amount: this.amount,
order_type: value
})
.then(function(response) {
currentObj.output = response.data;
})
.catch(function(error) {
currentObj.output = error;
});
},
Your template becomes:
<template>
<div>
<div v-if="order=='total'">
<form #submit.prevent="formSubmit("form1")">
<input type="text" class="form-control" v-model="amount">
<br>
<input type="text" class="form-control" v-model="price">
<br>
<button class="btn btn-primary" type="submit">BUY</button>
</form>
</div>
<div v-else-if="order=='partial'">
<form #submit.prevent="formSubmit("form2")">
<input type="text" class="form-control" v-model="amount">
<br>
<input type="text" class="form-control" v-model="price">
<br>
<button class="btn btn-primary" type="submit">BUY</button>
</form>
</div>
<br>
</div>
</template>
SOLUTION 2
To avoid duplication you could also set a computed property:
orderType(){
if (this.order === "total") {
return "form1"
} else if (this.order === "partial") {
return "form2"
} else {
return null
}
With that in place you can simplify the template by removing the conditional and not needing to pass anything to the method:
<template>
<div>
<form #submit.prevent="formSubmit()">
<input type="text" class="form-control" v-model="amount" />
<br />
<input type="text" class="form-control" v-model="price" />
<br />
<button class="btn btn-primary" type="submit">BUY</button>
</form>
</div>
</template>
And in the method the value of order_type is calculated in the computed property:
formSubmit() {
let currentObj = this;
axios
.post("MYURL", {
price: this.price,
amount: this.amount,
order_type: this.orderType
})
.then(function(response) {
currentObj.output = response.data;
})
.catch(function(error) {
currentObj.output = error;
});
},
Related
I am trying to do customer login with Vue .
I have tried to do something and received respone 200 and 302 still but not working. I also tried this way : http://web.archive.org/web/20150417052042/http://inside.sauce.ly:80/how-to-build-an-ajax-login-form-...
but same .
let productForm = new Vue({
el:".vue-login-form",
data(){
return{
form: {
email: null,
password: null,
},
customerData: null,
}
},
methods:{
login(){
axios.post('/account/login', this.form )
.then((response) => {
console.log(response);
this.customerData = response.data;
})
.catch(function (error){
});
},
},
})
<form action="">
<div class="form-top">
<h2>Welcome Back!</h2>
<p>Please login to your account.</p>
</div>
<div class="login-fields">
<div class="input">
<input type="email" v-model="form.email" placeholder="Email address">
</div>
<div class="input mb-0">
<input type="password" v-model="form.password" placeholder="Password">
</div>
<div class="forgot-pass">Forgot Password?</div>
<div class="submit-button">
<button type="button" #Click="login()">Log In</button>
</div>
</div>
</form>
I'm trying to add some validations with Vuelidate to a login form. When I leave the username field blank, I'm expecting to see a warning displayed saying "Name is required", but nothing is showing up.
It's not progressing to the next step (which is what I want), so I'm assuming that the validation is working, I'm just not getting the message displayed on the screen. I ran it in debug mode and I'm not getting any errors, is there something I've done wrong?
<template>
<div>
<h3>Sign in</h3>
<div class="row" v-if="errorMessage">
<div class="alert alert-danger"><p>{{ errorMessage }}</p></div>
</div>
<div class="row" v-if="successMessage">
<div class="alert alert-success"><p>{{ successMessage }}</p></div>
</div>
<form #submit.prevent="OnLogin">
<div class="form-group">
<label for="userSigninLogin">Email</label>
<input name="username" type="text"
class="form-control"
:class="{ 'is-invalid': submitted && $v.apiRequest.username.$error }"
placeholder="Enter your email" v-model="apiRequest.username">
</div>
<div class="form-group">
<label for="userSigninPassword">Password</label>
<input name="password" type="password"
class="form-control" id="userSigninPassword"
placeholder="Enter your password" v-model="apiRequest.password">
</div>
<button type="submit" class="btn btn-primary">Sign in</button>
<div v-if="submitted" && !$v.apiRequest.username.required
class="alert alert-danger"><p>Name is required</p></div>
<div class="row" v-if="submitted" && !$v.apiRequest.username.required>
<div class="alert alert-danger"><p>Name is required</p></div>
</div>
</form>
</div>
</template>
<script>
import { required, minLength } from 'vuelidate/lib/validators';
export default {
data() {
return {
apiRequest: new this.$request({
username: '',
password: '',
}),
errorMessage: '',
successMessage: '',
submitted: false,
};
},
validations: {
apiRequest: {
username: {
required,
minLength: minLength(2),
},
},
},
methods: {
OnLogin() {
this.submitted = true;
this.apiRequest.addStore(this.$store);
this.apiRequest.post('login')
.then((response) => {
this.successMessage = response;
this.errorMessage = '';
})
.catch((errors) => {
this.errorMessage = errors;
this.successMessage = '';
});
},
},
};
</script>
Follow the steps it helps you to resolve your issue. You forgot to add validation on button click and also there is template error in displaying error message.
Step 1: HTML template
<div id="app">
<h3>Sign in</h3>
<div class="row" v-if="errorMessage">
<div class="alert alert-danger">
<p>{{ errorMessage }}</p>
</div>
</div>
<div class="row" v-if="successMessage">
<div class="alert alert-success">
<p>{{ successMessage }}</p>
</div>
</div>
<form #submit.prevent="OnLogin">
<div class="form-group">
<label for="userSigninLogin">Email</label>
<input name="username"
type="text" class="form-control" :class="{ 'is-invalid': submitted && $v.apiRequest.username.$error }"
placeholder="Enter your email" v-model="apiRequest.username" />
<div v-if="submitted && $v.apiRequest.username.$error" class="alert alert-danger">
<span v-if="!$v.apiRequest.username.required">Username is Required</span>
<span v-if="!$v.apiRequest.username.minLength">Enter Minimum 6 character</span>
<span v-if="$v.apiRequest.username.minLength && !$v.apiRequest.username.email">Enter Valid Email address</span>
</div>
</div>
<div class="form-group">
<label for="userSigninPassword">Password</label>
<input name="password" type="password" class="form-control"
id="userSigninPassword" placeholder="Enter your password" v-model="apiRequest.password" />
<div class="row" v-if="submitted && !$v.apiRequest.password.required">
<span class="alert alert-danger">Password is required</span>
</div>
</div>
<button type="submit" class="btn btn-primary">Sign in</button>
</form>
</div>
Step 2: Initalize your modal data
data() {
return {
apiRequest: {
username: "",
password: "",
},
errorMessage: "",
successMessage: "",
submitted: false,
};
},
Step 3: Add validations rule
validations: {
apiRequest: {
username: {
required,
minLength: minLength(6),
email,
},
password: { required },
},
},
Step 4: Add form submit method
methods: {
OnLogin() {
this.submitted = true;
this.$v.$touch();
if (this.$v.$invalid) {
return; // stop here if form is invalid
}
this.apiRequest
.post("login")
.then((response) => {
this.successMessage = response;
this.errorMessage = "";
})
.catch((errors) => {
this.errorMessage = errors;
this.successMessage = "";
});
},
},
DEMO
Here I have written two steps one is "step===1" and other one is "step===2". So here i wants to reuse step1 template to step2. That means we have step one template and at step1 we click on next button so at next step i want to show the same template like reusing..
<div v-if="step === 1">
<h1>Step One</h1>
<h4>Address</h4>
<label>Address</label>
<input type="text" v-model="address">
<label>City</label>
<input type="text" v-model="city">
<label>State</label>
<input type="text" v-model="state">
<button #click.prevent="next()">Next</button>
</div>
<div v-if="step === 2">
reuse step===1 template here
</div>
vue.js
export default {
data() {
return {
address: null,
city: null,
state: null
}
},
methods:{
prev() {
this.step--;
},
next() {
this.step++;
},
}
</script>
new Vue({
el: '#app',
data() {
return {
stepTotal: 2,
step: 1,
address: null,
city: null,
state: null
}
},
methods: {
prev() {
this.step--;
},
next() {
this.step++;
},
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<template v-for="index of stepTotal">
<div v-if="step === index" :key="index">
<h1>Step {{index}}</h1>
<h4>Address</h4>
<label>Address</label>
<input type="text" v-model="address">
<label>City</label>
<input type="text" v-model="city">
<label>State</label>
<input type="text" v-model="state">
<br>
<button v-if="index != 1" #click.prevent="prev()">Prev</button>
<button v-if="index != stepTotal" #click.prevent="next()">Next</button>
</div>
</template>
</div>
I'd probably separate the form for each step into its own component. So for instance:
AddressForm.vue
<template>
<div>
<label>Address</label>
<input type="text" v-model="localValue.address" />
<label>City</label>
<input type="text" v-model="localValue.city" />
<label>State</label>
<input type="text" v-model="localValue.state" />
</div>
</template>
<script>
export default {
props: {
value: Object,
},
computed: {
localValue: {
get() { return this.value; },
set(value) { this.$emit("input", value); },
},
},
};
</script>
And then just reuse this component for each step:
<div v-if="step === 1">
<h1>Step One</h1>
<h4>Address</h4>
<AddressForm v-model="step1address />
<button #click.prevent="next()">Next</button>
</div>
<div v-if="step === 2">
<h1>Step Two</h1>
<h4>Address 2</h4>
<AddressForm v-model="step2address />
<button #click.prevent="next()">Next</button>
</div>
Here's a running sample of the above:
https://codesandbox.io/s/tender-antonelli-2n4vb
Is this correct way of managing mutations?
My HTML
<div class="form-group">
<label>Merchant Id No:</label>
<input type="text" class="form-control border-input" v-model="merchantId">
</div>
<div class="form-group">
<label>Name:</label>
<input type="text" class="form-control border-input" v-model="merchantName">
</div>
My Computed Properties:
merchantId: {
get(){
return this.merchant.merchant_id
},
set(value){
this.$store.commit('merchantId', value);
}
},
merchantName: {
get(){
return this.merchant.name
},
set(value){
this.$store.commit('merchantName', value);
}
},
My Mutations:
merchantName(state, merchantName){
state.merchant.name = merchantName
},
merchantId(state, merchantId){
state.merchant.merchant_id = merchantId
},
Is there a way to mutate only in the merchant? Because I need to do it one by one.
merchant(state, merchant){
state.merchant = merchant
},
Here is my merchant Object.
You can add a button at the end of your input fields and add a click listener to commit a mutation withe the payload of merchant object.
Example
<div class="form-group">
<label>Merchant Id No:</label>
<input type="text" class="form-control border-input" v-model="merchant.merchantId">
</div>
<div class="form-group">
<label>Name:</label>
<input type="text" class="form-control border-input" v-model="merchant.merchantName">
</div>
<div class="form-group">
<label>Name:</label>
<input type="email" class="form-control border-input" v-model="merchant.merchantEmail">
</div>
// more input fields...
<button #click.prevent="save">Save merchant<button>
script
export default{
data(){
return{
merchant:{
merchantId:'',
merchantName:'',
merchantEmail:''
//more properties binded to the v-model
}
}
},
methods:{
click(){
this.$store.commit('merchant', this.merchant);
}
}
}
And your mutation
merchant(state, merchant){
state.merchant = merchant
},
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/