Vee Validate require either of two fields - javascript

I'm trying to use Vee Validate to require either of two input fields, name OR location, but they cannot both be empty. I am getting this error- 'Error in directive validate bind hook: "TypeError: Cannot read property 'expression' of undefined"' Here's what I have-
HTML
<div class="col-xs-12 col-sm-8">
<div class="same-height-parent">
<div class="same-height" :class="{'has-error': errors.has('searchLocation') }">
<input type="text" class="form-control" placeholder="Enter Zip or City, ST" v-model="searchLocation" v-validate ="{ rules: { required: this.locationInput} }" data-vv-name="searchLocation" >
</div>
<div class="form-element same-height">or</div>
<div class="same-height" :class="{'has-error': errors.has('searchName') }">
<input type="text" class="form-control" placeholder="Enter Name" v-model="searchName" v-validate ="{ rules: { required: nameInput} }" data-vv-name="searchName">
</div>
</div>
</div>
<div class="col-xs-12 col-sm-4">
<button class="btn btn-success btn-block btn-fz20"
#click="validateBeforeSubmit()">Search</button>
</div>
JS
export default {
name: 'startNewSearch',
data: function() {
return {
sectionTitle: 'Start a New Search',
sectionClass: 'search',
searchLocation: '',
searchName: '',
searchType: 'location'
}
},
methods: {
validateBeforeSubmit: function(e) {
this.$validator.validateAll();
if (!this.errors.any()) {
this.submit()
}
},
submit: function(e) {}
}
},
computed: {
locationInput() {
if(this.searchName === '') {
return true;
}
return false;
},
nameInput() {
if(this.searchLocation === '')
return true; // cellphone is required
return false;
}
}
}

This is an old question, but I came across it while looking for a similar problem.
Anyhow, I believe you have a syntax error.
v-validate ="{ rules: { required: nameInput} }"
...you're missing 'this'...
v-validate ="{ rules: { required: this.nameInput} }"
Regards,
Wayne

In vee-validate v3 my solution was to extend the require_if rule like this:
app.html:
...
<ValidationProvider name="lastName" immediate rules="required_if_not:company" v-slot="{ errors }">
...
app.js:
extend('required_if_not', {
...required_if,
// params: ['target']
validate: (value, args) => {
let target_value = args.target;
return Boolean(target_value || value);
},
message: 'Bitte dieses Feld ausfüllen.'
});
this also works with multiple fields.

Related

Why do I get this error: Uncaught TypeError: Cannot read property 'classList' of null

I know there are few instances of this error being asked about, but none of the tips given seem to do anything for me. Any thoughts or tips would be appreciated.
I have a form that has fields validated via formvalidation.io, latest version 1.8.1
I thought my problem might have something to do with the "Confirm Password" and Password Strength steps but removing those fields has the same error appear.
Keep getting this error, although the form functions just fine and info gets written to the db correctly etc.:
FormValidation.min.js:formatted:2560 Uncaught TypeError: Cannot read property 'classList' of null
at FormValidation.min.js:formatted:2560
at Array.forEach (<anonymous>)
at s$4 (FormValidation.min.js:formatted:2559)
at FormValidation.min.js:formatted:2588
at Array.forEach (<anonymous>)
at c (FormValidation.min.js:formatted:2587)
at s.install (FormValidation.min.js:formatted:2845)
at l.registerPlugin (FormValidation.min.js:formatted:1407)
at FormValidation.min.js:formatted:1965
at Array.forEach (<anonymous>)
My Form:
<form id="signupForm" method="post" action="signup.html">
<div class="form-group">
<label><b>Work Name</b></label>
<input type="text" class="form-control" id="working_name" name="working_name" placeholder="Your Working Name">
</div>
<div class="form-group">
<label><b>Work Email</b></label>
<input type="text" class="form-control" id="email" name="email" placeholder="Your Work Email">
</div>
<div class="form-group">
<label><b>Choose a Password</b></label>
<input type="text" class="form-control" id="pwd" name="pwd" placeholder="Choose a Password">
<div class="progress mt-2" id="progressBar" style="opacity: 0; height: 10px;">
<div class="progress-bar progress-bar-striped progress-bar-animate" style="width: 100%; height: 5vh;"></div>
</div>
</div>
<div class="form-group">
<label><b>Retype Password</b></label>
<input type="text" class="form-control" id="confirmPWD" name="confirmPwd" placeholder="Enter your Password Again">
</div>
<div class="form-group">
<label><b>Website</b></label>
<input type="text" class="form-control" id="website_url" name="website_url" placeholder="Your Website (if you have one)">
</div>
<div class="form-group">
<label><b>Twitter Page</b></label>
<input type="text" class="form-control" id="twitter_url" name="twitter_url" placeholder="Twitter Page">
</div>
<div class="form-group">
<label><b>Link to Current Advertising</b></label>
<input type="text" class="form-control" id="advertising_link" name="advertising_link" placeholder="Link to Current Advertising">
</div>
<div class="form-group">
<label><b>Referred By</b></label>
<input type="text" class="form-control" id="referred_by" name="referred_by" placeholder="Who referred you to RS?">
</div>
<div class="form-group">
<label><b>Other Information</b></label>
<textarea id="other_info" name="other_info" cols="40" rows="3" class="form-control" placeholder="Other Information"></textarea>
</div>
<div class="form-group" align="center">
<!-- Do NOT use name="submit" or id="submit" for the Submit button -->
<br><button class="btn btn-signup" name="action" value="Sign up to use RS Services" type="submit">Sign up to use RS Services</button>
</div>
</form>
<script>
document.addEventListener('DOMContentLoaded', function(e) {
const strongPassword = function() {
return {
validate: function(input) {
// input.value is the field value
// input.options are the validator options
const value = input.value;
if (value === '') {
return {
valid: true,
};
}
const result = zxcvbn(value);
const score = result.score;
const message = result.feedback.warning || 'The password is weak';
const cmessage = 'Success Full';
// By default, the password is treat as invalid if the score is smaller than 3
// We allow user to change this number via options.minimalScore
const minimalScore = input.options && input.options.minimalScore ?
input.options.minimalScore :
5;
console.log(minimalScore, "dfd");
if (score >= minimalScore) {
console.log("condition true")
return {
valid: true,
message: cmessage,
meta: {
// This meta data will be used later
score: score,
},
}
} else if (score < minimalScore) {
console.log("condition false")
return {
valid: false,
// Yeah, this will be set as error message
message: message,
meta: {
// This meta data will be used later
score: score,
},
}
}
},
};
};
const form = document.getElementById('signupForm');
const fv = FormValidation.formValidation(
form, {
fields: {
working_name: {
validators: {
notEmpty: {
message: 'Your Agency or Working Name is required'
},
stringLength: {
min: 3,
max: 30,
message: 'The name must be more than 3 and less than 30 characters long'
},
// regexp: {
// regexp: /^[a-zA-Z0-9_]+$/,
// message: 'The name can only consist of letters, numbers or an underscore'
// }
}
},
email: {
validators: {
notEmpty: {
message: 'Your Email Address is required'
},
emailAddress: {
message: 'That is not a valid email address'
}
}
},
pwd: {
validators: {
notEmpty: {
message: 'The password is required and cannot be empty'
},
checkPassword: {
message: 'The password is too weak',
minimalScore: 4,
},
}
},
confirmPwd: {
validators: {
identical: {
compare: function() {
return form.querySelector('[name="pwd"]').value;
},
message: 'The Passwords do not match'
}
}
},
},
plugins: {
trigger: new FormValidation.plugins.Trigger(),
bootstrap: new FormValidation.plugins.Bootstrap(),
submitButton: new FormValidation.plugins.SubmitButton(),
defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
icon: new FormValidation.plugins.Icon({
valid: 'fa fa-check',
invalid: 'fa fa-times',
validating: 'fa fa-refresh'
}),
},
}
)
.registerValidator('checkPassword', strongPassword)
.on('core.validator.validating', function(e) {
if (e.field === 'pwd' && e.validator === 'checkPassword') {
document.getElementById('progressBar').style.opacity = '1';
}
})
.on('core.validator.validated', function(e) {
if (e.field === 'pwd' && e.validator === 'checkPassword') {
const progressBar = document.getElementById('progressBar');
if (e.result.meta) {
// Get the score which is a number between 0 and 4
const score = e.result.meta.score;
console.log(score);
// Update the width of progress bar
const width = (score == 0) ? '1%' : score * 25 + '%';
console.log(width, "width");
progressBar.style.opacity = 1;
progressBar.style.width = width;
} else {
progressBar.style.opacity = 0;
progressBar.style.width = '0%';
}
}
});
});
</script>
Problem Solved.
Had to redo my html a little.
More of an issue with the way I had hideif/showif statements in place.

VeeValidate3: Custom validation always is true on submit

I am using Vue.js 2 and VeeValidate3 to validate my form. This from is also making an axios call to check if the username is already in use. If so, obviously the validation needs to be false.
So far so good. I also see the error message Dieser Name wird bereits verwendet when I type in a username which is already in use.
However, if I see the error message and nevertheless click the submit button, the error message disappears and I can see the message Submit submitCompleteNormalRegistrationForm which gets printed when the form gets submitted.
The question is, why does the form get submitted also there is an validation error with the name? What I am doing wrong?
Also, how can I set the validation for the name to true when the name is not in use?
This is my code so far:
<template>
<div>
<ValidationObserver ref="completeNormalRegistrationForm" v-slot="{ passes }" class="flex-column flex-grow-1 d-flex w-100">
<form #submit.prevent="passes(submitCompleteNormalRegistrationForm)" id="completeNormalRegistrationForm" class="flex-column flex-grow-1 d-flex w-100">
<div class="backButtonWrapper text-left">
<i id="backButtonRegistrationForm" #click="showLoginForm" class="far fa-arrow-alt-circle-left"></i>
</div>
<div class="form-wrapper margin-auto w-100">
<p class="rubik-bold" style="font-size: 1rem;">Registrieren</p>
<ValidationProvider vid="name" name="Nutzername" rules="required|alpha_dash" v-slot="{ errors }">
<input #keyup="completeNormalRegistrationFormUsernameExists" class="form-control search-username" v-model="registerForm.name" type="text" placeholder="Username">
<span v-if="errors[0]" class="username-invalid-span">{{ errors[0] }}</span>
</ValidationProvider>
<ValidationProvider vid="email" name="E-Mail" rules="required|email" v-slot="{ errors }">
<input class="form-control search-email" v-model="registerForm.email" type="email" placeholder="E-Mail">
<span v-if="errors[0]" class="email-invalid-span">{{ errors[0] }}</span>
</ValidationProvider>
<ValidationProvider vid="confirmation" name="Passwort" v-slot="{ errors }">
<input class="form-control" v-model="registerForm.password" type="password" placeholder="Passwort">
<span v-if="errors[0]" class="password-invalid-span">{{ errors[0] }}</span>
</ValidationProvider>
<ValidationProvider rules="confirmed:confirmation" name="Passwort" v-slot="{ errors }">
<input class="form-control" v-model="registerForm.passwordConfirmation" type="password" placeholder="Passwort wiederholen">
<span v-if="errors[0]" class="password-invalid-span">{{ errors[0] }}</span>
</ValidationProvider>
<button type="submit" class="btn btn-primary btn-big big-letter-spacing text-uppercase rubik-bold login">Anmelden</button>
</div>
</form>
</ValidationObserver>
</div>
</template>
<script>
export default {
name: "NavbarAction",
data() {
return {
registerForm: {
name: '',
email: '',
password: '',
passwordConfirmation: '',
termsAndConditions: false,
},
}
},
methods: {
async completeNormalRegistrationFormUsernameExists() {
const nameValid = await this.usernameExists(this.registerForm.name);
if (nameValid) {
this.$refs.completeNormalRegistrationForm.setErrors({name: 'Dieser Name wird bereits verwendet'});
} else {
console.log('Set name is NOT in use!');
}
},
async usernameExists(name){
return await axios.post(window.routes.usernameExists, {value: name})
.then(r => {
return r.data;
});
},
submitCompleteNormalRegistrationForm(){
console.log('Submit submitCompleteNormalRegistrationForm');
console.log(this);
}
}
}
</script>
UPDATE (working with custom rule now):
extend('unique-email', (value) => {
return axios.post(this.routes.emailExists, { value: value })
.then((r) => {
// If email exists, axios response is true
if(r.data){
return {
valid: false,
data: { message: 'E-Mail wird bereits genutzt' }
};
}else{
return {
valid: true,
};
}
}, (err) => {
return {
valid: false,
data: { message: 'E-Mail wird bereits genutzt' }
};
})
},
)
You need to express your email validator as a vee-validate rule instead of trying to do it yourself on keyup. One of the many undocumented things in vee-validate is that if you return a promise as the result of a validation, vee-validate will handle it correctly, waiting to get the result before allowing validation to pass.
Here's an example to get you started:
mounted() {
extend('unique-email', (value) => {
return this.usernameExists(value)
.then((res) => {
return {
valid: true,
};
}, (err) => {
this.$refs.completeNormalRegistrationForm.setErrors({
name: ['Username already registered']
});
})
}, {
immediate: false
})
}
this is front-end validation. The only thing you can do is disable the button when the form is invalid. There is nothing preventing a smart kid trying to submit a form anyway. The true validation should be serverside.
something like:
<button type="submit" class="btn btn-primary btn-big big-letter-spacing text-uppercase rubik-bold login" :disabled="passes(submitCompleteNormalRegistrationForm)">Anmelden</button>
Finally also found a way to set custom error messages without using $refs:
extend('unique-email', (value) => {
return axios.post(window.laravel.emailExists, { value: value })
.then((r) => {
// If email exists, axios response is true
if(r.data){
return "E-Mail wird bereits genutzt";
}else{
return true;
}
}, (err) => {
return "E-Mail wird bereits genutzt";
})
},
);

How to emit and event within a promise in Vuejs [duplicate]

I'm learning on how to render HTML contents in Vuejs I'm trying to build a small input component which gets generated from render function. It looks something like this:
export default {
name: "nits-input",
methods: {
},
props: {
label: String,
hint: String,
error: String,
placeholder: String
},
render (createElement) {
//Help action text
let helpText = this.hint ? createElement('span', { class: 'm-form__help' }, this.hint) : ''
//Error Text
let errorText = this.error ? createElement('span', { class: 'm--font-danger' }, this.error) : ''
return createElement('div', { class: ''}, [
createElement('label', this.label),
createElement('input', {
class: 'form-control m-input',
attrs: { type: this.type, placeholder: this.placeholder },
domProps: { value: self.value},
on: {
input: function (event) {
this.$emit('input', event.target.value)
}
}
}),
helpText, errorText
])
}
}
While calling this component I'm doing below:
<div class="form-group m-form__group">
<nits-input
label="Email Address"
type="email"
hint="We'll never share your email with anyone else."
placeholder="Enter email"
v-model="email"
>
</nits-input>
</div>
<div class="form-group m-form__group">
<nits-input
label="Password"
type="password"
placeholder="Enter password"
v-model="password"
>
</nits-input>
</div>
I want the value to be stored into v-model, to check the values are being set properly I'm using a watch function
watch: {
email () {
console.log('Email v-model defined as '+this.email)
},
password() {
console.log('Password v-model defined as '+this.password)
}
}
But this always gives me error:
Uncaught TypeError: Cannot read property '$emit' of null
I've taken the references from This VueJS Documentation Link. Help me out in this. Thanks.
you should use arrow function since you're loosing the scope inside that callback :
on: {
input:(event)=> {
this.$emit('input', event.target.value)
}
}

How to handle validation messages returned by Sails JS?

Hope you are doing great!!
I am working on SailsJS web-app and using actions structure for controllers.
This is my user/login action:
module.exports = {
friendlyName: 'Login',
description: 'Login user.',
inputs: {
email: {
description: 'user email.',
type: 'string',
required: true
},
password: {
description: 'user password.',
type: 'string',
required: true
}
},
exits: {
success: {
statusCode: 200,
responseType: 'view',
},
},
fn: async function (inputs, exits) {
// All done.
return 'hello world';
}
};
This is the login form html code:
<div class="row">
<div class="valign-wrapper">
<div class="col s6 z-depth-4 card-panel">
<form class="col s12 login-form" method="POST" action="/login">
<input type="hidden" name="_csrf" value="<%= _csrf %>" />
<div class="card-content">
<h5 class="card-title center-align">Login</h5>
<div class="row margin">
<div class="input-field col s12">
<input id="email" type="email" class="validate">
<label for="email">Email</label>
<div class="invalid-feedback" v-if="formErrors.emailAddress">Please provide a valid email address.</div>
</div>
</div>
<div class="row margin">
<div class="input-field col s12 right">
<input id="password" type="password" class="validate">
<label for="email">Password</label>
</div>
</div>
<div class="row">
<button class="btn waves-effect waves-light right" type="submit" name="action">Login</button>
</div>
</div>
</form>
</div>
</center>
</div>
</div>
Whenever, I am submitting blank form I get this following error:
{
"code": "E_MISSING_OR_INVALID_PARAMS",
"problems": [
"\"email\" is required, but it was not defined.",
"\"password\" is required, but it was not defined."
],
"message": "The server could not fulfill this request (`POST /login`) due to 2 missing or invalid parameters. **The following additional tip will not be shown in production**: Tip: Check your client-side code to make sure that the request data it sends matches the expectations of the corresponding parameters in your server-side route/action. Also check that your client-side code sends data for every required parameter. Finally, for programmatically-parseable details about each validation error, `.problems`. "
}
Now, the issue is that I am unable to find a way to handle this error in prettier way.
I hope one of you can guide me on the right path.
Thank You,
U can transform error in api/responses/badRequest
module.exports = async function badRequest(data) {
const status = 400;
if (data.code && data.code === 'E_MISSING_OR_INVALID_PARAMS'){
return this.res.status(status).json({
code: 'My code',
message: 'My message',
whateva: 'Bla bla'
});
}
return this.res.status(status).json(data);
};
I have a custom project and I need the same thing u requested. I made npm package who take an error object and make it prettier for frontend. Something like this:
module.exports = async function badRequest(data) {
const formatError = require('myFormatError');
const {status, response}= formatError(data);
return this.res.status(status).json(response);
};
It doesn't need to be npm, u can make some function. I hope u were looking for this.
Using the same error object to display will be a mistake because in production technical errors will be stripped off by the toJson method.
The best way to handle the error is to write a custom one. such as
module.exports = {
friendlyName: 'Login',
description: 'Login user.',
inputs: {
email: {
description: 'user email.',
type: 'string'
},
password: {
description: 'user password.',
type: 'string'
}
},
exits: {
success: {
statusCode: 200,
responseType: 'view',
},
badrequest:{
statusCode: 400,
responseType: 'view',
}
},
fn: async function (inputs, exits) {
try{
if(!inputs.email || !inputs.password){
return exits.badrequest({code: 'PARAM_MISSING', message: 'Email/Password is missing'});
}
// all good
return exits.success({/* object containing information realted to success*/});
}
catch(e){
return exists.error(e);
}
}
}
};

Bootstrap validation on dynamically adding multiple fields

I am using bootstrap v3.1.1 and I want to validate a form with bootstrap validation but who contains a button to clone 3 fields. With cloning everything works nice, but I can't validate the cloned fields. Here is my HTML Form:
<form id="myForm" action="myAction">
<div class="row" id="line_1">
<div class="col-md-2 form-group">
<input type="text" class="form-control input-sm" id="idFirstField_1" name="firstField[]">
</div>
<div class="col-md-2 form-group">
<input type="text" class="form-control input-sm" id="idSecondField_1" name="secondField[]">
</div>
<div class="col-md-2 form-group">
<input type="text" class="form-control input-sm" id="idThirdField_1" name="thirdField[]">
</div>
</div>
<a id="cloneButton">add line</a>
</form>
In JavaScript file I Have:
$(document).ready(function () {
var count = 2;
$('#cloneButton').click(function () {
var klon = $('#line_1');
klon.clone().attr('id', 'line_' + (++count)).insertAfter($('#line_1'));
$('#line_' + count).children('div').children('input').each(function () {
$(this).val('');
var oldId = $(this).attr('id').split('_');
$(this).attr('id', oldId[0] + '_' + count);
});
});
//For validating the fields:
$('#myForm').bootstrapValidator({
fields: {
'firstField[]': {
validators: {
notEmpty: {
message: 'Enter a value'
}
}
},
'secondField[]': {
validators: {
notEmpty: {
message: 'Enter a value'
}
}
},
'thirdField[]': {
validators: {
notEmpty: {
message: 'Enter a value'
}
}
}
}
});
});
I now that I must to use somethings like this
$('#myForm').bootstrapValidator('addField', klon.find('[name="firstField[]"]'));
for each field, but I don't now how correctly do it. Please help me. Thanks!!
if you insert the method addField in your input loop, it should work. I also suggest to save your first row as a template.
var template = $('#line_1').clone();
var options = {
fields: {
'firstField[]': {
validators: {
notEmpty: {
message: 'Enter a value 1'
}
}
},
'secondField[]': {
validators: {
notEmpty: {
message: 'Enter a value 2'
}
}
},
'thirdField[]': {
validators: {
notEmpty: {
message: 'Enter a value 3'
}
}
}
}
};
$('#myForm').bootstrapValidator(options);
$('#cloneButton').click(function () {
var rowId = $('.row').length + 1;
var validator = $('#myForm').data('bootstrapValidator');
var klon = template.clone();
klon.attr('id', 'line_' + rowId)
.insertAfter($('.row').last())
.find('input')
.each(function () {
$(this).attr('id', $(this).attr('id').replace(/_(\d*)$/, "_"+rowId));
validator.addField($(this));
})
});
FIDDLE
This Answer not exactly for this question but if someone want to add different field dynamically then they can use this.
$('#myForm').formValidation('addField', 'fourthField[]', {
validators: {
notEmpty: {
message: 'Enter a value 4'
}
},
});
Syntax : $("#form_name").formValidation("addField",'no of the field',{validation});

Categories

Resources