How to make custom validation rules with VeeValidate 3 and vue.js - javascript

I want to create custom rules for a form.
The example would be this:
<label class="form-label">Price range from</label>
<validation-provider rules="required_if:price_to" name="Price range from"
v-slot="{ errors }">
<input v-model="price_range_from" type="number"
ref="price_from">
<span class="validation-error form-span">{{ errors[0] }}</span>
</validation-provider>
</div>
<div class="ml-2 w-100">
<label class="form-label">Price range to</label>
<validation-provider name="Price range to"
v-slot="{ errors }">
<input v-model="price_range_to" type="number" class="form-control"
ref="price_to" name="price_range_to">
<span class="validation-error form-span">{{ errors[0] }}</span>
</validation-provider>
Out of this part of form I want to create a rule which has logic of this:
input of price_range_from is required if the price_range_to
field is not null.
input of price_range_from cannot be greater
then price_range_to.
And vice versa.
Script:
import {ValidationProvider, ValidationObserver, extend} from 'vee-validate';
import * as rules from "vee-validate/dist/rules";
import {required} from 'vee-validate/dist/rules';
Object.keys(rules).forEach(rule => {
extend(rule, rules[rule]);
});
extend('required', {
...required,
message: 'This field is required'
});
Tried to read the documentation on [https://logaretm.github.io/vee-validate/guide/forms.html]
But couldn't find the answer how to make custom rules.
Would be glad if someone showed and example that I could understand and move forward and make more custom rules.

You can do this by targeting other fields: https://vee-validate.logaretm.com/v3/advanced/cross-field-validation.html#targeting-other-fields
import { extend } from 'vee-validate';
extend('password', {
params: ['target'],
validate(value, { target }) {
return value === target;
},
message: 'Password confirmation does not match'
});
...
<ValidationObserver>
<ValidationProvider rules="required|password:#confirm" v-slot="{ errors }">
<input type="password" v-model="password">
<span>{{ errors[0] }}</span>
</ValidationProvider>
<ValidationProvider name="confirm" rules="required" v-slot="{ errors }">
<input type="password" v-model="confirmation">
<span>{{ errors[0] }}</span>
</ValidationProvider>
</ValidationObserver>
Read the docs to see more writing about how it works. Basically #confirm turns into target in the custom rule, and it corresponds to the name attribute on the input.
The validate function in the custom rule just returns a boolean for whether the field is valid or not, so you can add any custom logic in there and just make sure it returns a boolean.
In your case, it sounds like you want two different error messages, so you could consider making two custom rules.

Related

How to use Vuelidate to show errors only when user is finished with input

I have the following form built with Bootstrap-Vue, which has a bit of Vuelidation code applied to it.
<b-form #submit.prevent="onSubmit">
<input type="hidden" name="_token" :value="csrf" />
<transition-group name="fade">
<b-form-select
:class="{ 'hasError': $v.form.dobDate.$error }"
class="mb-3"
name="dobDate"
id="dobDate"
v-model.lazy="$v.form.dobDate.$model"
:options="optionsDays"
v-if="isSixteen"
key="dobDateSelect"
>
<template slot="first">
<option value disabled>Please select a date</option>
</template>
</b-form-select>
</transition-group>
<transition-group name="fade">
<b-form-select
:class="{ 'hasError': $v.form.dobMonth.$error }"
class="mb-3"
name="dobMonth"
id="dobMonth"
v-model.lazy="$v.form.dobMonth.$model"
:options="optionsMonths"
v-if="isSixteen"
value="optionsMonths.key"
key="dobMonthSelect"
>
<template slot="first">
<option value disabled>Please select a Month</option>
</template>
</b-form-select>
</transition-group>
<b-alert
show
variant="danger"
class="error"
v-if="!$v.form.dobYear.required"
>This field is required</b-alert>
<b-alert
show
variant="danger"
class="error"
v-if="!$v.form.dobYear.minLength"
>Field must have at least {{ $v.form.dobYear.$params.minLength.min }} characters.</b-alert>
<b-alert class="error" v-if="!$v.form.dobYear.numeric">Please enter a valid year of birth</b-alert>
<b-alert show variant="danger" v-if="belowSixteen">You are underage</b-alert>
<b-form-input
:class="{ 'hasError': $v.form.dobYear.$error }"
placeholder="Year of Birth"
v-model="form.dobYear"
#blur="$v.form.dobYear.$touch()"
autofocus
class="form-control mb-3"
name="year"
id="year"
maxlength="4"
#keyup="checkAge"
></b-form-input>
<b-button
class="btn btn-lg btn-primary btn-block"
type="submit"
variant="primary"
:disabled="$v.$invalid||belowSixteen"
>Submit</b-button>
<b-alert
show
variant="danger"
v-if="belowSixteen"
class="error mt-3"
>Sorry you have to be over 16 to play</b-alert>
</b-form>
But currently I am getting immediate feedback when the page loads which can be jarring for the user. Instead I want the errors to show when the user has finished with the input/select.
I have tried using #blur="$v.form.dobYear.$touch()" however it doesn't seem to work at all. What am I doing wrong?
Here is a snipper of how my validations look like in my script currently:
validations: {
form: {
dobYear: {
required,
minLength: minLength(4),
maxLength: maxLength(4),
numeric
},
dobMonth: {
required: requiredIf(function() {
return this.isSixteen;
})
},
dobDate: {
required: requiredIf(function() {
return this.isSixteen;
})
}
}
}
Calling $touch() in blur event is right. But you could use little bit different logic with state attribute given from bootstrap-vue. You could find more detail from here Form input [contextual states]
eg:
<b-form-input
v-model="form.name"
type="text"
#blur="$v.form.name.$touch()"
:state="$v.form.name.$dirty ? !$v.form.name.$anyError : null"
/>
<b-form-invalid-feedback :state="$v.form.name.$dirty ? !$v.form.name.$anyError : null" >
Some kind of invalid feedback Message here
</b-form-invalid-feedback>
And out of curiosity why you use v-model with validation model like shown below.
v-model.lazy="$v.form.dobMonth.$model"
Isn't it just okay for use v-model with data() like shown below?
v-model.lazy="form.dobMonth"
You can wrap it as follows:
<div v-if="$v.email.$dirty">
<b-alert
show
variant="danger"
class="error"
v-if="!$v.form.dobYear.required"
>This field is required</b-alert>
<b-alert
show
variant="danger"
class="error"
v-if="!$v.form.dobYear.minLength"
>Field must have at least {{ $v.form.dobYear.$params.minLength.min }} characters.</b-alert>
<b-alert class="error" v-if="!$v.form.dobYear.numeric">Please enter a valid year of birth</b-alert>
<b-alert show variant="danger" v-if="belowSixteen">You are underage</b-alert></div>
Know more

Value change for Ng Date Time Picker doesn't work

Nothing of events are not working for ng-pick-datetime
<label class="fieldlabel">{{ attribute.attribute.displayName }}: </label>
<label>
<mat-form-field class="field-full-width">
<input [owlDateTimeTrigger]="datePicker" placeholder="Date" [owlDateTime]="datePicker"
[dateTimeInput]="emitValue()" [(ngModel)]="value.value">
<owl-date-time #datePicker></owl-date-time>
</mat-form-field>
</label>
Also I import needed modules:
import { OwlDateTimeModule, OwlNativeDateTimeModule } from 'ng-pick-datetime';
https://www.npmjs.com/package/ng-pick-datetime
I have the same errors for other events: afterPickerOpen,
yearSelected, monthSelected, dateTimeChange
dateTimeInput is an output (event) not an input. Hence, you need to use () instead of [].
(dateTimeInput)="emitValue()"
For further information on outputs, read the official Angular docs.

Angular 2: Length validation not working

I am trying to simply replicate the walkthrough from the Angular website but cannot get length validation to work:
<input
style="display:inline-block;min-width:150px"
class="form-input"
id="phone"
required
minlength="4"
maxlength="24"
type="number"
name="phone"
[(ngModel)]="client.phone"
#phone="ngModel" />
<!-- required works, minlength and maxlength always false -->
{{ phone.hasError('required') }} {{ phone.hasError('minlength') }} {{ phone.hasError('maxlength') }}
<div *ngIf="phone.errors && (phone.dirty || phone.touched)"
class="alert alert-danger">
<div [hidden]="!phone.errors.required">
Name is required
</div>
<div [hidden]="!phone.errors.minlength">
Name must be at least 4 characters long.
</div>
<div [hidden]="!phone.errors.maxlength">
Name cannot be more than 24 characters long.
</div>
</div>
I must be missing something simple, but for some reason the required validation changes depending on input, but both minlength and maxlength are always false regardless of how long my input is.
Its because number type doesnt have length property
There is a bug for this https://github.com/angular/angular/issues/15053
You can work around it like:
[ngModel]="client.phone" (ngModelChange)="client.phone = $event + ''"
Plunker Example
Update
Since in 4.2.0-beta.0 (2017-05-04) were introduced min and max validators so you can have a look https://github.com/angular/angular/pull/15813/commits/52b0ec8062381e7285b5f66aa83008edfbf02af3

Disable input conditionally (Vue.js)

I have an input:
<input
type="text"
id="name"
class="form-control"
name="name"
v-model="form.name"
:disabled="validated ? '' : disabled"
/>
and in my Vue.js component, I have:
..
..
ready() {
this.form.name = this.store.name;
this.form.validated = this.store.validated;
},
..
validated being a boolean, it can be either 0 or 1, but no matter what value is stored in the database, my input is always disabled.
I need the input to be disabled if false, otherwise it should be enabled and editable.
Update:
Doing this always enables the input (no matter I have 0 or 1 in the database):
<input
type="text"
id="name"
class="form-control"
name="name"
v-model="form.name"
:disabled="validated ? '' : disabled"
/>
Doing this always disabled the input (no matter I have 0 or 1 in the database):
<input
type="text"
id="name"
class="form-control"
name="name"
v-model="form.name"
:disabled="validated ? disabled : ''"
/>
To remove the disabled prop, you should set its value to false. This needs to be the boolean value for false, not the string 'false'.
So, if the value for validated is either a 1 or a 0, then conditionally set the disabled prop based off that value. E.g.:
<input type="text" :disabled="validated == 1">
Here is an example.
var app = new Vue({
el: '#app',
data: {
disabled: 0
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="disabled = (disabled + 1) % 2">Toggle Enable</button>
<input type="text" :disabled="disabled == 1">
<pre>{{ $data }}</pre>
</div>
you could have a computed property that returns a boolean dependent on whatever criteria you need.
<input type="text" :disabled=isDisabled>
then put your logic in a computed property...
computed: {
isDisabled() {
// evaluate whatever you need to determine disabled here...
return this.form.validated;
}
}
Not difficult, check this.
<button #click="disabled = !disabled">Toggle Enable</button>
<input type="text" id="name" class="form-control" name="name" v-model="form.name" :disabled="disabled">
jsfiddle
You can manipulate :disabled attribute in vue.js.
It will accept a boolean, if it's true, then the input gets disabled, otherwise it will be enabled...
Something like structured like below in your case for example:
<input type="text" id="name" class="form-control" name="name" v-model="form.name" :disabled="validated ? false : true">
Also read this below:
Conditionally Disabling Input Elements via JavaScript
Expression You can conditionally disable input elements inline
with a JavaScript expression. This compact approach provides a quick
way to apply simple conditional logic. For example, if you only needed
to check the length of the password, you may consider doing something
like this.
<h3>Change Your Password</h3>
<div class="form-group">
<label for="newPassword">Please choose a new password</label>
<input type="password" class="form-control" id="newPassword" placeholder="Password" v-model="newPassword">
</div>
<div class="form-group">
<label for="confirmPassword">Please confirm your new password</label>
<input type="password" class="form-control" id="confirmPassword" placeholder="Password" v-model="confirmPassword" v-bind:disabled="newPassword.length === 0 ? true : false">
</div>
Your disabled attribute requires a boolean value:
<input :disabled="validated" />
Notice how i've only checked if validated - This should work as 0 is falsey ...e.g
0 is considered to be false in JS (like undefined or null)
1 is in fact considered to be true
To be extra careful try:
<input :disabled="!!validated" />
This double negation turns the falsey or truthy value of 0 or 1 to false or true
don't believe me? go into your console and type !!0 or !!1 :-)
Also, to make sure your number 1 or 0 are definitely coming through as a Number and not the String '1' or '0' pre-pend the value you are checking with a + e.g <input :disabled="!!+validated"/> this turns a string of a number into a Number e.g
+1 = 1
+'1' = 1
Like David Morrow said above you could put your conditional logic into a method - this gives you more readable code - just return out of the method the condition you wish to check.
You may make a computed property and enable/disable any form type according to its value.
<template>
<button class="btn btn-default" :disabled="clickable">Click me</button>
</template>
<script>
export default{
computed: {
clickable() {
// if something
return true;
}
}
}
</script>
Try this
<div id="app">
<p>
<label for='terms'>
<input id='terms' type='checkbox' v-model='terms' /> Click me to enable
</label>
</p>
<input :disabled='isDisabled'></input>
</div>
vue js
new Vue({
el: '#app',
data: {
terms: false
},
computed: {
isDisabled: function(){
return !this.terms;
}
}
})
To toggle the input's disabled attribute was surprisingly complex. The issue for me was twofold:
(1) Remember: the input's "disabled" attribute is NOT a Boolean attribute.
The mere presence of the attribute means that the input is disabled.
However, the Vue.js creators have prepared this...
https://v2.vuejs.org/v2/guide/syntax.html#Attributes
(Thanks to #connexo for this... How to add disabled attribute in input text in vuejs?)
(2) In addition, there was a DOM timing re-rendering issue that I was having. The DOM was not updating when I tried to toggle back.
Upon certain situations, "the component will not re-render immediately. It will update in the next 'tick.'"
From Vue.js docs: https://v2.vuejs.org/v2/guide/reactivity.html
The solution was to use:
this.$nextTick(()=>{
this.disableInputBool = true
})
Fuller example workflow:
<div #click="allowInputOverwrite">
<input
type="text"
:disabled="disableInputBool">
</div>
<button #click="disallowInputOverwrite">
press me (do stuff in method, then disable input bool again)
</button>
<script>
export default {
data() {
return {
disableInputBool: true
}
},
methods: {
allowInputOverwrite(){
this.disableInputBool = false
},
disallowInputOverwrite(){
// accomplish other stuff here.
this.$nextTick(()=>{
this.disableInputBool = true
})
}
}
}
</script>
Can use this add condition.
<el-form-item :label="Amount ($)" style="width:100%" >
<template slot-scope="scoped">
<el-input-number v-model="listQuery.refAmount" :disabled="(rowData.status !== 1 ) === true" ></el-input-number>
</template>
</el-form-item>
If you use SFC and want a minimal example for this case, this would be how you can use it:
export default {
data() {
return {
disableInput: false
}
},
methods: {
toggleInput() {
this.disableInput = !this.disableInput
}
}
}
<template>
<div>
<input type="text" :disabled="disableInput">
<button #click="toggleInput">Toggle Input</button>
</div>
</template>
Clicking the button triggers the toggleInput function and simply switches the state of disableInput with this.disableInput = !this.disableInput.
This will also work
<input type="text" id="name" class="form-control" name="name" v-model="form.name" :disabled="!validated">
My Solution:
// App.vue Template:
<button
type="submit"
class="disabled:opacity-50 w-full px-3 py-4 text-white bg-indigo-500 rounded-md focus:bg-indigo-600 focus:outline-none"
:disabled="isButtonDisabled()"
#click="sendIdentity()"
>
<span v-if="MYVARIABLE > 0"> Add {{ MYVARIABLE }}</span>
<span v-else-if="MYVARIABLE == 0">Alternative text if you like</span>
<span v-else>Alternative text if you like</span>
</button>
Styles based on Tailwind
// App.vue Script:
(...)
methods: {
isButtonDisabled(){
return this.MYVARIABLE >= 0 ? undefined: 'disabled';
}
}
Manual:
vue v2
vue v3
If isButtonDisabled has the value of null, undefined, or false, the
disabled attribute will not even be included in the rendered
element.
Bear in mind that ES6 Sets/Maps don't appear to be reactive as far as i can tell, at time of writing.
We can disable inputs conditionally with Vue 3 by setting the disabled prop to the condition when we want to disable the input
For instance, we can write:
<template>
<input :disabled="disabled" />
<button #click="disabled = !disabled">toggle disable</button>
</template>
<script>
export default {
name: "App",
data() {
return {
disabled: false,
};
},
};
</script>
There is something newly released called inert, which is literally making it ignored by the browser.
<template>
<input
type="text"
id="name"
class="form-control"
name="name"
:inert="isItInert"
/>
</template>
<script setup>
const isItInert = true
</script>
Here is the playground for testing purposes.
Vue 3
<input
type="text"
id="name"
class="form-control"
name="name"
v-model="form.name"
:disabled="VALIDATOR == '0'"
/>

How to implement Ember-Validations in Ember-App-Kit(EAK)

I have a ember-app-kit application. For the form I am using ember default views. But for form validations I have came across with this lib which everyone highly recommends. Ember Validations By Docyard . But I am not sure how to implement the same with my eak set-up.
Questions that I have:
1. Where should I add validations ?
2. What to declare when defining validations?
3. Errors how to show them on focus out or even on submit button ?
Say for example I have a sign up form and I want to validate firstname lastname, email, password, gender(select options) . How should I go about it ?
If possible please clarify the queries with a JSbin.
Validations should go to controller, unless your working with dyanmic formsets, which can be duplicated. Also u have to wrap ControllerObject into this
var AddController = Ember.ArrayController.extend(Ember.Validations.Mixin, {}
To start validation u have to make new Object named validations
You have to add input value to be validated
validations: {
newFirstname:{
format: { with: /^[A-Za-z-]{2,16}$/, allowBlank: true, message: 'Enter valid name.' }
},
newFamilyname: {
format: { with: /^[A-Za-z-]{3,16}$/ , message: 'Required field lastname.' }
}
},
Showing errors.
<div class="row">
<div class="col-md-6 col-xs-4">
<label>First name: </label>
{{input type="text" placeholder="First name" value=newFirstname class="form-control"}}
{{#if errors.newFirstname}}
<span class="error errorForValidation"><span class="glyphicon glyphicon-warning-sign"></span> {{errors.newFirstname}}</span>
{{/if}}
</div>
<div class="col-md-6 col-xs-4">
<label>*Last name: </label>
{{input type="text" placeholder="Family name" value=newFamilyname class="form-control"}}
{{#if errors.newFamilyname}}
<span class="error"><span class="glyphicon glyphicon-warning-sign"></span> {{errors.newFamilyname}}</span>
{{/if}}
</div>
</div><!--end row-->
Showing button when validation is flawless
<button type="submit" class="btn btn-primary" {{bind-attr disabled="isInvalid"}}{{action 'GetData'}}>Create</button>
JSBIN : http://emberjs.jsbin.com/iDeQABo/17/edit

Categories

Resources