#submit.prevent not working on vue md-input - vue.js

when I click 'login button' even I don't fill data in md-input it still running,
I test my onSubmit() method by login with my user and it works!
I don't think I do thing wrong in the method so I guess that my form is incorrect.
here is my code :
my form
<form #submit.prevent="onSubmit">
<login-card header-color="green">
<h4 slot="title" class="title">CCRP Sign On</h4>
<p slot="description" class="description">IT solution by เจ้เก๋ IT-PM</p>
<md-field class="md-form-group" slot="inputs">
<md-icon>account_box</md-icon>
<label>ID...</label>
<md-input v-model.trim="userId" type="text"></md-input>
</md-field>
<md-field class="md-form-group" slot="inputs">
<md-icon>lock_outline</md-icon>
<label>Password...</label>
<md-input v-model.trim="password" type="password"></md-input>
</md-field>
<md-field class="md-form-group">
<md-icon>announcement</md-icon>
<label>Password...</label>
</md-field>
<md-button slot="footer" class="md-simple md-success md-lg" type="submit">Login</md-button>
</login-card>
</form>
in scrpit methods
async onSubmit() {
const authData = {
userId: this.userId,
password: this.password
};
await this.login(authData).then(() => {
if (this.isAuthenticated) {
this.$router.push("dashboard");
} else {
console.log("err");
}
});
},
can you help me solve this?

Your understanding of "prevent" key is quite incorrect.
All it does is not reload the form after submit action. However the submit action will be called irrespective of whether the prevent is used or not.
It is just preventing the default functionality of form getting reloaded after each submit.
On the other hand what you need to do is validate your form before actually submitting it.
Example :
//- Requires "vuelidate" - npm install vuelidate
<script>
import { validationMixin } from "vuelidate";
import { required, email } from "vuelidate/lib/validators";
export default {
name: "FormValidation",
mixins: [validationMixin],
data: () => ({
form: {
email: null,
password: null
},
userSaved: false,
sending: false,
lastUser: null
}),
validations: {
form: {
email: {
required,
email
},
password: {
required
}
}
},
methods: {
getValidationClass(fieldName) {
const field = this.$v.form[fieldName];
if (field) {
return {
"md-invalid": field.$invalid && field.$dirty
};
}
},
clearForm() {
this.$v.$reset();
this.form.email = null;
this.form.password = null;
},
saveUser() {
this.sending = true;
// Instead of this timeout, here you can call your API
window.setTimeout(() => {
this.lastUser = `${this.form.email}`;
this.userSaved = true;
this.sending = false;
this.clearForm();
}, 1500);
},
validateUser() {
this.$v.$touch();
if (!this.$v.$invalid) {
this.saveUser();
}
}
}
};
</script>
<style lang="scss" scoped>
.md-progress-bar {
position: absolute;
top: 0;
right: 0;
left: 0;
}
</style>
<template>
<div>
<!-- Calling validateUser insted of submit action -->
<form novalidate class="md-layout" #submit.prevent="validateUser">
<md-card class="md-layout-item md-size-50 md-small-size-100">
<!-- Title of the form -->
<md-card-header>
<div class="md-title">Login</div>
</md-card-header>
<!-- Inputs for the form -->
<md-card-content>
<md-field :class="getValidationClass('email')">
<label for="email">Email</label>
<md-input
type="email"
name="email"
id="email"
autocomplete="email"
v-model="form.email"
:disabled="sending"
/>
<span class="md-error" v-if="!$v.form.email.required">The email is required</span>
<span class="md-error" v-else-if="!$v.form.email.email">Invalid email</span>
</md-field>
<md-field :class="getValidationClass('password')">
<label for="password">Password</label>
<md-input
type="password"
name="password"
id="password"
autocomplete="password"
v-model="form.password"
:disabled="sending"
/>
<!-- to show errors in case validation fails -->
<span class="md-error" v-if="!$v.form.password.required">The email is required</span>
<span class="md-error" v-else-if="!$v.form.email.email">Invalid email</span>
</md-field>
</md-card-content>
<md-progress-bar md-mode="indeterminate" v-if="sending"/>
<md-card-actions>
<md-button type="submit" class="md-primary" :disabled="sending">Create user</md-button>
</md-card-actions>
</md-card>
<md-snackbar :md-active.sync="userSaved">The user {{ lastUser }} was saved with success!</md-snackbar>
</form>
</div>
</template>

Related

Vue JS: Forms are not getting cleared when router.push() method is executed after the logout

I am using Flask as a backend and Vue JS as front end for my development. Vuex for state store.
In the logout() I am clearing the authentication token from localStorage via store.dispatch('/logout') and then using router.push('/login') to navigate to Login.vue. I find that the form details entered before are not getting cleared. When the logout() is performed it navigates to the Login.vue with flash message stating 'You have been logged out successfully'.
Below is the code snippet for the same:
logout() {
axios.get(`${this.host}:5000/logout`)
.then((res) => {
this.$store.dispatch('logout')
.then(() => {
this.$router.push('/login');
});
this.flashMessage.success({
message: res.data.msg,
time: 5000,
flashMessageStyle: {
backgroundColor: 'linear-gradient(#e66465, #9198e5)',
},
});
})
.catch((error) => {
this.flashMessage.error({
message: error.toString(),
time: 5000,
flashMessageStyle: {
backgroundColor: 'linear-gradient(#e66465, #9198e5)',
},
});
});
}
logout() is written in App.vue. Here router is an instance of vue-router.
To avoid the issue of form data not being cleared I have used router.go() instead of router.push() in the above code. But because of this implementation, the flash message is not getting displayed as the reload (because of router.go()) is overwriting the displaying of flash message which I don't want.
Please let me if it is possible to erase the form data after logout without getting into the trouble of not showing flash message.
Not sure how you have implemented Login.vue, but here is a Login.vue that I have implemented, and it works. One of the takeaways should be that my form model data values are initialized to empty strings.
<template>
<div id="login">
<form class="form-horizontal">
<div class="form-group">
<label for="username" class="col-md-offset-3 col-md-2 align-right">User Name</label>
<div class="col-md-3">
<input type="input" ref="username" class="form-control" id="username" v-model="username">
</div>
</div>
<div class="form-group">
<label for="password" class="col-md-offset-3 col-md-2 align-right">Password</label>
<div class="col-md-3">
<input type="password" class="form-control" id="password" v-model="password" v-on:keyup.enter="login">
</div>
</div>
<div class="form-group">
<div class="col-md-offset-5 col-md-4">
<button type="button" class="btn btn-default"
v-on:click="login">Login</button>
<span class="error-msg" v-if="errorMsg">{{ errorMsg }}</span>
</div>
</div>
</form>
</div>
</template>
<script>
import { loginUrl, axios, processAjaxLoginError } from '../globalvars.js'
export default {
name: 'Login',
data() {
return {
username: '',
password: '',
errorMsg: ''
}
},
methods: {
login() {
axios.post(loginUrl, {
username: this.username,
password: this.password
})
.then(response => {
// Commit the token to the store
this.$store.commit('updateToken', { token: response.data.message });
// Clear error message
this.errorMsg = '';
// Redirect to customer index view
this.$router.push("/customers")
})
.catch(error => {
this.errorMsg = processAjaxLoginError(error);
})
}
},
computed: {
token() {
return this.$store.state.token;
}
},
mounted() {
this.$refs.username.focus();
}
}
</script>

Using nuxt.js google recaptcha module

There is a problem that is wasting too much time. I installed the Nuxt js recaptcha module. but the information given in the documentation is insufficient. I haven't used recaptcha before. How exactly should I use it.
<template>
<div class="mx-auto mt-5" style="width: 500px; max-width:90%">
<div class="mx-auto mt-5" style="width: 230px;">
<img
src="#/assets/media/images/site/logo.png"
style="width: 110px"
/>.com'a Üye Olun
</div>
<div class="bg-white p-4 mt-2" style="border-radius:20px">
<b-form #submit.prevent="onSubmit" #reset="onReset" v-if="show">
<b-form-group id="input-group-2" label-for="input-2">
<b-form-input
id="input-2"
class="form-control form-control-lg"
v-model="form.userFullName"
placeholder="İsim soyisim"
required
></b-form-input>
</b-form-group>
<b-form-group id="input-group-2" label-for="input-2">
<b-form-input
id="input-5"
class="form-control form-control-lg"
v-model="form.userName"
placeholder="Kullanıcı adı"
required
></b-form-input>
</b-form-group>
<b-form-row>
<b-col>
<b-form-input
id="input-1"
v-model="form.userEmail"
type="email"
class="form-control form-control-lg"
placeholder="E-mail adresiniz"
required
></b-form-input>
</b-col>
<b-col>
<b-form-input
id="input-3"
v-model="form.userPassword"
class="form-control form-control-lg"
placeholder="Şifreniz"
required
></b-form-input>
</b-col>
</b-form-row>
<b-form-group
id="input-group-4"
class="mt-3"
v-slot="{ ariaDescribedby }"
>
<b-form-checkbox-group
v-model="form.checked"
id="checkboxes-4"
:aria-describedby="ariaDescribedby"
>
<b-form-checkbox class="text-dark" value="1"
>Beni Hatırla</b-form-checkbox
>
</b-form-checkbox-group>
</b-form-group>
<b-button
:disabled="isClickSubmit"
type="submit"
class="btn btn-dark btn-lg btn-block"
variant="primary"
>
<b-spinner v-if="isClickSubmit" small style="margin-bottom:3px" type="grow"></b-spinner>
Kaydol</b-button
>
</b-form>
</div>
</div>
</template>
import axios from "axios";
export default {
layout: "default",
data() {
return {
isClickSubmit: false,
form: {
userEmail: "",
userFullName: "",
userName: "",
userPassword: null
},
show: true
};
},
methods: {
async mounted() {
try {
const bune = await this.$recaptcha.init();
console.log(bune);
} catch (e) {
console.log(e);
}
},
async onSubmit(event) {
this.isClickSubmit = true;
this.onReset();
try {
console.log(this.$recaptcha);
const token = await this.$recaptcha.execute("login");
console.log("ReCaptcha token:", token);
// await this.$recaptcha.reset()
const form = this.form;
const sonuc = await axios.post("http://localhost:3000/api/users", {
form
});
this.isClickSubmit = false
} catch (error) {
console.log("Login error:", error);
}
// console.log(JSON.stringify(this.form));
},
onReset() {
this.form.userEmail = "";
this.form.userFullName = "";
this.form.userName = "";
this.form.userPassword = null
}
}
};
nuxt.config.js:
env: {
GOOGLE_SECRET: '...' },
privateRuntimeConfig: {
secretKey: process.env.GOOGLE_SECRET },
modules: [
[
"#nuxtjs/recaptcha",
{
siteKey:process.env.GOOGLE_SECRET ,
version: 3,
} ]
],
You don't seem to have the recaptcha element in your template.
<!-- Add this where you want the captcha, regardless of version -->
<recaptcha #error="onError" #success="onSuccess" #expired="onExpired" />
<script>
export default {
data() {
return {
isClickSubmit: false,
form: {
userEmail: "",
userFullName: "",
userName: "",
userPassword: null,
token: null
},
show: true
};
},
methods: {
onSuccess(token) {
this.form.token = token;
},
onExpired() {
this.$recaptcha.reset();
},
onError(error) {
console.error(error);
}
}
}
Before you make your request, you'll need to send some things to Google. You'll make this call before serving any requests. This function is from a project of mine.
// Backend code
function Recaptcha(token, ip, callback) {
axios.post(`https://www.google.com/recaptcha/api/siteverify?secret=${SECRET_KEY}&response=${token}`,
{
remoteip: ip,
},
{
headers: {
'Content-Type':
'application/x-www-form-urlencoded; charset=utf-8',
},
},
)
.then(callback);
}
Example usage of Recaptcha function:
Hopefully this helps you understand it a bit better.

How to prevent default, then submit default with VueJS

I am submitting a form using VueJS and i need to submit two actions on the final submit, one after the other.
Either one works when running just one.
What i am trying to do, is signup a user for firebase, wait, then submit the form with the same email/password as normal and signup that user with another sign in system.
The delimiters have been changed, so just over look that.
How to do this with Jquery
<form #submit="checkForm" #submit.prevent="register" action="#" method="post" novalidate="true" ref="form">
<h1 class="text-center">{{ 'customer.register.title' | t }}</h1>
<h1 v-if="authUser">
Is authed in
</h1>
<h1 v-else>
Not auth
</h1>
<div class="form-group">
<ul>
<li v-for="error in errors">
${ error }
</li>
</ul>
</div>
<p>
<label for="CustomerFirstName">${ firstName }</label>
<input id="name" v-model="name" type="name" name="customer[first_name]" autocomplete="name"
autocorrect="off" autocapitalize="off">
</p>
<p>
<label for="CustomerEmail">${ loginEmailName }</label>
<input id="email" v-model="email" type="email" name="customer[email]" autocomplete="email"
autocorrect="off" autocapitalize="off">
</p>
<p>
<label for="CustomerPassword">${ loginPasswordName }</label>
<input id="password" v-model="password" type="password" name="customer[password]">
</p>
<p>
<button type="submit" value="Create" class="btn btn-primary">Submit</button>
</p>
</form>
Then the JS that works on either one but not together.
const appTwo = new Vue({
delimiters: ["${", "}"],
el: "#create_customer_vue",
data: {
errors: ["1", "2", "3"],
email: '',
password: '',
name: null,
firstName: "First name",
loginEmailName: emailTitle,
loginPasswordName: passwordTitle,
title: registerTitle,
authUser: null
},
methods: {
register: function() {
firebase.auth().createUserWithEmailAndPassword(this.email, this.password)
},
submitForm: function(){
this.$refs.form.submit()
},
created() {
firebase.auth().onAuthStateChanged(user => { this.authUser = user })
},
checkForm: function(e) {
if (this.email && this.password) {
return true;
}
this.errors = [];
if (!this.email) {
this.errors.push("Valid email required");
}
if (!this.password) {
this.errors.push("Valid password required");
}
e.preventDefault();
}
}
});
Just call the one submit handler then submit the form normally after the Firebase operation completes.
For example
<form #submit.prevent="register" ... >
methods: {
checkForm () {
if (this.email && this.password) {
return true;
}
this.errors = [];
if (!this.email) {
this.errors.push("Valid email required");
}
if (!this.password) {
this.errors.push("Valid password required");
}
return false
},
async register ($event) {
if (this.checkForm()) {
await firebase.auth().createUserWithEmailAndPassword(this.email, this.password)
$event.target.submit() // or use this.$refs.form.submit() if you prefer
}
}
}

Simple If return in VUE.JS method

Template won't show v-if when method return true.
I can log the username password and the failed attempt in the else section of my login method. If I try to log the loginFailed var I get loginFailed is not defined.
<template>
<div class="container-big">
<div class="container-header">
<h1>Our Login</h1>
</div>
<p v-if="loginFailed">
Login Failed
</p>
<div id="loginContainer" class="container-login">
<P>{{msg}}</p>
<input id="login" type="text" placeholder="username" v-model="username" spellcheck="false" >
<input id="key" type="password" placeholder="password" v-model="password" spellcheck="false" >
</div>
<div class="container-signin">
<button class="signin" id="go" #click="login()"></button>
</div>
</div>
</template>
<script>
export default {
name: 'Login',
data () {
return {
msg: 'This is your login',
password: '',
username: '',
loginFailed: false
}
},
methods: {
login () {
console.log(this.username);
console.log(this.password);
if (this.username !== '' && this.password === 'pass') {
this.$router.push( { name: 'dashboard', path: '/dashboard' }) }
else {
console.log('failed attempt')
this.loginFailed === true;
return this.loginFailed
}
}
}
}
</script>
What I want to do is if login failed show
<p v-if="loginFailed">
Login Failed
</p>
In the login() method, you're performing a comparison when you should actually assign a value to the loginFailed property:
this.loginFailed === true;
Change that line so that it actually assigns true to this.loginFailed:
this.loginFailed = true;
side note: You most likely don't need to return anything from login() since it's simply dealing with instance properties, you might want to remove this line:
return this.loginFailed

Vue not updating on property change

I've got an index component that contains this, in part:
<template>
<ul class="nav navbar-nav navbar-right">
<li v-if="state.user"><a #click.stop="do_logout" v-link="{ path: '/'}">Logout {{ state.user.display_name }}</a></li>
<li v-else v-link-active><a v-link="{ path: '/login' }">Login</a></li>
</ul>
<router-view></router-view>
<template>
<script>
import state from '../state';
import { logout } from '../actions';
export default {
data() {
return {
state
};
},
methods: {
do_logout() {
logout().then(() => this.$router.go('/'));
}
}
}
</script>
And I've got a login component that looks like this:
<template>
<form class="form-signin" #submit.prevent="do_login">
<input type="email" v-model="email" id="inputEmail" class="form-control" placeholder="Email address" required autofocus>
<input type="password" v-model="password" id="inputPassword" class="form-control" placeholder="Password" required>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign In</button>
</form>
</template>
<script>
import { login } from '../../actions';
export default {
data() {
return {
email: '',
password: ''
};
},
methods: {
do_login() {
login(this.email, this.password).then(() => this.$router.go('/'));
}
}
}
</script>
My login and logout methods look like this:
import state from './state';
export const login = (email, pwd) => {
return fetch_post_json('/api/login', {
email,
pwd
}).then(j => state.user = j.user);
};
export const logout = () => _fetch('/api/logout', 'GET', null, false).then(() => state.user = null);
Logging out works fine; clicking the link changes the text and presents the "Login" link. Logging in succeeds in logging in, in the Javascript, but doesn't update the link. I'm forced to reload the page to get the page to render correctly. Why?