On form button click success, form validations fire again - vue.js

Hopefully this is a newbie question.
I am using Vuelidate to validate my form and the form validations works fine, when the “send email” button is clicked.However on success, instead of showing me the successful message, the system shows that all the form controls have errors(This is because I have bound the name, email, message controls to their corresponding empty data elements).
What am I missing?
How can I fix this issue?
Contact.vue
<template>
<div>
<section class="slice slice-lg" id="sct_contact_form">
<div class="container">
<div class="mb-5 text-center">
<span class="badge badge-soft-info badge-pill badge-lg">
Contact
</span>
<h3 class=" mt-4">Send us a message</h3>
</div>
<div class="row justify-content-center">
<div class="col-lg-8">
<form>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label class="form-control-label">Name</label>
<input class="form-control" type="text" placeholder="Name" v-model="user.name" id="name" name="name" :class="{ 'is-invalid': submitted && $v.user.name.$error }" >
<div v-if="submitted && !$v.user.name.required" class="invalid-feedback">Name is required</div>
</div>
</div>
</div>
<div class="row align-items-center">
<div class="col-md-12">
<div class="form-group">
<label class="form-control-label">Email</label>
<input class="form-control" type="email" placeholder="email#example.com"
v-model="user.email" id="email" name="email" :class="{ 'is-invalid': submitted && $v.user.email.$error }" >
<div v-if="submitted && $v.user.email.$error" class="invalid-feedback">
<span v-if="!$v.user.email.required">Email is required</span>
<span v-if="!$v.user.email.email">Email is invalid</span>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label class="form-control-label">Message</label>
<textarea class="form-control" data-toggle="autosize" placeholder="Tell us a few words ..." rows="3" style="overflow: hidden; overflow-wrap: break-word; resize: none; height: 96.9922px;"
v-model="user.message" id="message" name="message" :class="{ 'is-invalid': submitted && $v.user.message.$error }" ></textarea>
<div v-if="submitted && $v.user.message.$error" class="invalid-feedback">
<span v-if="!$v.user.message.required">Message is required</span>
<span v-if="!$v.user.message.minLength">Message must be at least 6 characters</span>
</div>
</div>
</div>
</div>
<div class="text-center mt-4">
<button type="button" class="btn btn-dark rounded-pill" v-on:click="SendEmail()">Send your message</button>
<span class="d-block mt-4 text-sm">We'll get back to you in 24-48 h.</span>
<div v-if="submitted" class="valid-feedback">
<span v-if="!$v.user.name.$error && !$v.user.email.$error && !$v.user.message.$error">Your email was send successfully. We'll get back to you in 24-48 h.</span>
</div>
</div>
</form>
</div>
</div>
</div>
</section>
</div>
</template>
import { Email } from '../api/email.js';
import { required, email, minLength, sameAs } from "vuelidate/lib/validators";
export default {
name: "Contact",
components:{
},
data() {
return {
user: {
name: "",
email: "",
message: ""
},
submitted: false
};
},
validations: {
user: {
name: { required },
email: { required, email },
message: { required, minLength: minLength(6) }
}
},
methods: {
SendEmail() {
this.submitted = true;
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
var nameWithEmailText="Email message from: "+ this.user.name + "\nEmail message: " + this.user.message;
var subject="Email from contact us page in common membership website";
Meteor.call('email.send', this.user.email, subject, nameWithEmailText);
this.user.name='';
this.user.email='';
this.user.message='';
}
}
}

You should wait for the Meteor.call() to complete, then reset the validation state.
For example
Meteor.call('email.send', this.user.email, subject, nameWithEmailText, (error, result) => {
this.user.name = ''
this.user.email = ''
this.user.message = ''
this.$v.$reset()
})

Related

Uncaught (in promise) TypeError: Cannot read properties of null (reading 'subTree')

Totally new to Vue.js. Here's my issue:-
<template>
<div class="login-page">
<transition name="fade">
<div v-if="!registerActive" class="wallpaper-login"></div>
</transition>
<div class="wallpaper-register"></div>
<div class="container">
<div class="row">
<div class="col-lg-4 col-md-6 col-sm-8 mx-auto">
<div v-if="!registerActive" class="card login" v-bind:class="{ error: emptyFields }">
<h1>Sign In</h1>
<form class="form-group">
<input v-model="emailLogin" type="email" class="form-control" placeholder="Email" required>
<input v-model="passwordLogin" type="password" class="form-control" placeholder="Password" required>
<input type="submit" class="btn btn-primary" #click="doLogin">
<p>Don't have an account? Sign up here
</p>
<p>Forgot your password?</p>
</form>
</div>
<div v-else class="card register" v-bind:class="{ error: emptyFields }">
<h1>Sign Up</h1>
<form class="form-group">
<input v-model="emailReg" type="email" class="form-control" placeholder="Email" required>
<input v-model="passwordReg" type="password" class="form-control" placeholder="Password" required>
<input v-model="confirmReg" type="password" class="form-control" placeholder="Confirm Password" required>
<input type="submit" class="btn btn-primary" #click="doRegister">
<p>Already have an account? Sign in here
</p>
</form>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
registerActive: false,
emailLogin: "",
passwordLogin: "",
emailReg: "",
passwordReg: "",
confirmReg: "",
emptyFields: false
};
},
methods: {
doLogin() {
if (this.emailLogin === "" || this.passwordLogin === "") {
this.emptyFields = true;
} else {
alert("You are now logged in");
}
},
doRegister() {
if (this.emailReg === "" || this.passwordReg === "" || this.confirmReg === "") {
this.emptyFields = true;
} else {
alert("You are now registered");
}
}
}
};
</script>
My intentions are to wire-up the above to an API like thus:-
http://127.0.0.1:8000/api/login
using either the fetch API or something similar. Currently, the form doesn't display in the browser and throws the above error..
Any advice would be great.
With this, my vue HTML finally loads.
Remove these:-
resources/views/layouts/app.blade.php
{{--<script src="https://unpkg.com/vue#3"></script>--}}
{{--<script src="https://unpkg.com/vue-router#4"></script>--}}
</body>
</html>
Add this to your main file:-
resources/js/app.js
import * as Vue from 'vue';
import * as VueRouter from 'vue-router';
npm run dev and voila! Thanks to: Murad for a very useful comment: Vue3 Presence of a css class on element in single file component causes rendering failure when added to dom, Invalid VNode type: Symbol()

Nuxt component variable not updated

I wrote the following code for my navbar:
<template>
<div>
<div v-if="!$auth.loggedIn" data-tip="Login" class="tooltip tooltip-bottom">
<nuxt-link to="/login" class="btn btn-square btn-ghost">
<solid-login-icon class="w-6 h-6" />
</nuxt-link>
</div>
<div v-else class="flex items-stretch">
<a class="pr-2 btn btn-ghost rounded-btn"> Welcome, {{ this.$auth.user.username }}! 👋 </a>
<div data-tip="Logout" class="tooltip tooltip-bottom">
<button class="pr-2 btn btn-square btn-ghost" #click="logout()">
<solid-login-icon class="w-6 h-6" />
</button>
</div>
</div>
</div>
</template>
Which is include in the following login page:
<template>
<div class="h-screen shadow bg-base-200 drawer drawer-mobile">
<input id="my-drawer-2" type="checkbox" class="drawer-toggle" />
<div class="drawer-content">
<NavBar />
<div class="grid grid-cols-1 p-5 md:grid-cols-6">
<div class="col-span-1 md:col-span-2 md:col-start-3">
<div class="bg-white shadow card">
<div class="card-body">
<h2 class="text-left card-title">Login</h2>
<form #submit.prevent="userLogin">
<div class="form-control">
<label class="label">
<span class="label-text">Username</span>
</label>
<input
v-model="login.username"
type="text"
placeholder="Username"
class="input input-bordered"
/>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Username</span>
</label>
<input
v-model="login.password"
type="password"
placeholder="Password"
class="input input-bordered"
/>
</div>
<div class="mt-4">
<button type="submit" class="btn btn-primary btn-md">Login</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<SideBar />
</div>
</template>
<script>
export default {
data() {
return {
login: {
username: '',
password: '',
},
}
},
methods: {
async userLogin() {
try {
const response = await this.$auth.loginWith('local', { data: this.login })
} catch (err) {}
},
},
}
</script>
Upon loggin in with correct credentials the page keeps dispalying the "Login"-icon instead of the Welcome message.
I've tried to replace !$auth.loggedIn with loggedIn (coming from the data function) and with !this.$auth.loggedIn" but both don't seem to solve the issue

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

Validate specific amount of input fields with vee-validate

I want to validate varios steps in a wizard, without validating all inputs, when clicking on the next button. When clicking on the next button it should fire the function to validate the input fields of the first step. Then in the next step the input fields of the second step and so on. The next button is no submit button.
<tab-content title="Company" icon="fas fa-building" :before-change="validateThirdStep">
<div class="col-md-8 offset-md-2">
<label class="col-form-label text-md-right">Do you have a chicken?</label>
<div class="form-goup row">
<div class="col-md-7">
<input type="radio" name="dsb" id="radios" value="yes" v-model="pickeddsb">Yes
<input type="radio" name="dsb" id="radios" value="no" v-model="pickeddsb">No
</div>
</div>
</div>
<div class="form-group" v-if="pickeddsb=='yes'">
<div class="col-md-8 offset-md-2">
<h4>Data</h4>
</div>
<div class="col-lg-8 m-auto">
<!-- Name -->
<div class="form-group row">
<label class="col-md-3 col-form-label text-md-right">{{ $t('name') }}</label>
<div class="col-md-7">
<input
v-model="namedsb"
v-validate="'required|namedsb'"
:class="{ 'has-error': errors.has('namedsb') }"
type="text"
name="namedsb"
>
{{ errors.first('namedsb') }}
</div>
</div>
<!-- Firm -->
<div class="form-group row">
<label class="col-md-3 col-form-label text-md-right">{{ $t('companyname') }}</label>
<div class="col-md-7">
<input
v-model="firm"
v-validate="'required|firmdsb'"
:class="{ 'has-error': errors.has('firmdsb') }"
class="form-control"
type="text"
name="firmdsb"
>
{{ errors.first('firmdsb') }}
</div>
</div>
<!--Telephone-->
<div class="form-group row">
<label class="col-md-3 col-form-label text-md-right">{{$t('telephone')}}</label>
<div class="col-md-7">
<input
v-model="telephonedsb"
v-validate="'required|telephonedsb'"
:class="{ 'has-error': errors.has('telephonedsb')}"
class="form-control"
type="tel"
name="telephonedsb"
>
{{ errors.first('telephonedsb') }}
</div>
</div>
<!-- Email -->
<div class="form-group row">
<label class="col-md-3 col-form-label text-md-right">{{ $t('email') }}</label>
<div class="col-md-7">
<input
v-model="emaildsb"
v-validate="'required|emaildsb'"
:class="{ 'has-error': errors.has('emaildsb') }"
class="form-control"
type="email"
name="emaildsb"
>
{{ errors.first('emaildsb') }}
</div>
</div>
</div>
</div>
</tab-content>
export default {
data() {
return {
namedsb: "",
telephonedsb: "",
emaildsb: "",
namere: "",
telephonere:"",
emailre: "",
}
},
methods: {
validateThirdStep: function() {
this.$validator.validate('namedsb', this.namedsb);
this.$validator.validate('firmdsb', this.firmdsb);
this.$validator.validate('telephonedsb', this.state);
this.$validator.validate('emaildsb', this.emaildsb);
}
}
}
It's fairly easy with the built-in scopes of VeeValidate, you can read about it on this page: enter link description here
A simple explanation is to add a specific scope for each tab/step, by adding this on the fields:
data-vv-scope="step1"
And then use this method when pressing the button for validation:
methods: {
validateForm(scope) {
this.$validator.validateAll('step1').then((result) => {
if (result) {
alert('Form Submitted!');
}
});
}
}

Vue.js not updating template when changing child objects

I'm extending laravel spark and wanted to try to validate registration before actually sending it off.
All data is handled nicely and correctly from the server but the errors do not pop-up.
The code being used for validation is as following:
module.exports = {
...
methods: {
...
validate(field, value) {
var formData = {
field: field,
value: value
};
var form = new SparkForm(formData);
Spark.post('/register_validate', form).then(response => {
this.registerForm.addSuccess(field);
}).catch(errors => {
this.registerForm.addError(field, errors[field]);
});
}
}
};
After, i extended SparkForm and added these methods (successes is just a copy of errors, used to display validation success messages):
/**
* SparkForm helper class. Used to set common properties on all forms.
*/
window.SparkForm = function (data) {
...
this.addError = function(field, errors) {
form.successes.remove(field);
form.errors.add(field, errors);
},
this.addSuccess = function(field) {
form.errors.remove(field);
form.successes.add(field, true);
}
};
And finally i added some methods on the SparkFormErrors.
/**
* Spark form error collection class.
*/
window.SparkFormErrors = function () {
...
this.add = function(field, errors) {
this.errors[field] = errors;
};
this.remove = function(field) {
delete this.errors[field];
}
};
In the console no errors are shown and in the network tab i can see the correct messages coming true, also when i add a console log in for example the response callback i can see the actual errors or success messages. But they are not drawn on screen.
For completeness i'll include the important content of the template blade file:
#extends('spark::layouts.app')
#section('content')
<spark-register-stripe inline-template>
<!-- Basic Profile -->
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">
{{ trans('auth.register.title') }}
</div>
<div class="panel-body">
<!-- Generic Error Message -->
<div class="alert alert-danger" v-if="registerForm.errors.has('form')">
#{{ registerForm.errors.get('form') }}
</div>
<!-- Registration Form -->
<form class="form-horizontal" role="form">
<!-- Name -->
<div class="form-group" :class="{'has-error': registerForm.errors.has('name')}">
<label class="col-md-4 control-label">{{ trans('user.name') }}</label>
<div class="col-md-6">
<input type="name" class="form-control" name="name" v-model="registerForm.name" autofocus #blur="validate('name', registerForm.name)">
<span class="help-block" v-show="registerForm.errors.has('name')">
#{{ registerForm.errors.get('name') }}
</span>
</div>
</div>
<!-- E-Mail Address -->
<div class="form-group" :class="{'has-error': registerForm.errors.has('email')}">
<label class="col-md-4 control-label">{{ trans('user.email') }}</label>
<div class="col-md-6">
<input type="email" class="form-control" name="email" v-model="registerForm.email" #blur="validate('email', registerForm.email)">
<span class="help-block" v-show="registerForm.errors.has('email')">
#{{ registerForm.errors.get('email') }}
</span>
</div>
</div>
<!-- Password -->
<div class="form-group" :class="{'has-error': registerForm.errors.has('password')}">
<label class="col-md-4 control-label">{{ trans('user.password') }}</label>
<div class="col-md-6">
<input type="password" class="form-control" name="password" v-model="registerForm.password" #blur="validate('password', registerForm.password)">
<span class="help-block" v-show="registerForm.errors.has('password')">
#{{ registerForm.errors.get('password') }}
</span>
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<button class="btn btn-primary" #click.prevent="register" :disabled="registerForm.busy">
<span v-if="registerForm.busy">
<i class="fa fa-btn fa-spinner fa-spin"></i>{{ trans('auth.register.submitting') }}
</span>
<span v-else>
<i class="fa fa-btn fa-check-circle"></i>{{ trans('auth.register.submit') }}
</span>
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</spark-register-stripe>
#endsection
Any bright mind seeing what i'm missing/forgetting?