I am validating start and end time fields in a form.
The inputs look like (yes, I have a lot of parameters to be able to do server-side validation):
<ValidationObserver>
<div class="w3-third">
<label>From</label>
<ValidationProvider vid='st' mode="eager" :rules="{'available': ['#st','#et', res_date, 'startTime', selectedField.id] }" v-slot="{ errors}">
<dropdown id="starttime" :options="startTimeOptions" v-model="startTime" #change="getDuration()"></dropdown>
<span class="w3-red">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="w3-third ">
<label>Until</label>
<ValidationProvider vid="et" :rules="{'available': ['#st','#et', res_date, 'endTime', selectedField.id] }" v-slot="{ errors}">
<dropdown id="endtime" :options="endTimeOptions" v-model="endTime" #change="getDuration()"></dropdown>
<span>{{ errors[0] }}</span>
</ValidationProvider>
</div>
</ValidationObserver>
Even with a very simple validation rule like this where I am simply return true every time:
extend('available', {
validate(value, {s, e, dt, which, field } ) {
console.log("validate", which );
return true;
},
message: 'The time is not available ',
params:[ 's', 'e', 'dt', 'which', 'field']
});
It validates once for each field when I enter the form component. But subsequent validations happen 3x times. Could this be related to how I am forming my rules object? I have changed the mode, but if I try "lazy" it doesn't validate at all after entering the form. Note that this is on a select dropdown input.
I see that both fields reference themselves in the rule:
<ValidationProvider vid='st' :rules="{'available': ['#st','#et', res_date, 'startTime', selectedField.id] }" v-slot="{ errors}">
that is why it triggers multiple validation attempts per change because it validates the input itself and validates each targeted field, so for the same input it validates 2x times and one more for the other field.
You should only reference other fields and avoid referencing itself, use the value instead.
<ValidationProvider vid='st' :rules="{'available': ['#et', res_date, 'startTime', selectedField.id] }" v-slot="{ errors}">
You will need to change your rule implementation to take that into account though.
Related
I am using AlpineJS and x-model, which works great in the following case:
<script src="https://unpkg.com/alpinejs#3.9.5/dist/cdn.min.js"></script>
<form x-data="{ value: '' }">
<input x-model="value" placeholder="Type and see..." />
<br>Value: <span x-text="value"></span>
</form>
But when I have nested components with the same property name, the value doesn't propagate to the parent component, it stays in the child component:
<script src="https://unpkg.com/alpinejs#3.9.5/dist/cdn.min.js"></script>
<form x-data="{ value: '' }">
<div x-data="{ value: '' }">
<input x-model="value" placeholder="Type and see..."/>
<br>Child value: <span x-text="value"></span>
</div>
Parent value: <span x-text="value"></span>
</form>
I know this is a very specific case. One could say: "just make everything be one component". But I cannot do that, because the nested component will be a low level generic component that I need to reuse. And I need the parent to be able to access the same value attached to the model.
Any idea on how I can approach this without using $store?
You can use the x-modelable directive that can expose any Alpine.js property as a target of x-model directive. The child component's property name must be unique. The property name in x-model on the child component should be a parameter of a backend template system' macro function.
<script src="https://unpkg.com/alpinejs#3.9.5/dist/cdn.min.js"></script>
<form x-data="{ value: '' }">
<div x-data="{ innerValue: '' }" x-modelable="innerValue" x-model="value">
<input x-model="innerValue" placeholder="Type and see..." />
<br>Child value: <span x-text="innerValue"></span>
</div>
Parent value: <span x-text="value"></span>
</form>
I have the following Checkboxes now a want put validation in checkbox that one checkbox must be checked . But i dont't know how to do that.
CheckBox
<div class="form-group clearfix">
<label for="" class="col-sm-2 col-form-label">Arch (es) </label>
<div class="col-sm-10">
<label class="control-label" for="inputError" style="color: red"><i
id="arch_upper_error"></i></label>
<div class="demo-checkbox">
<input id="md_checkbox_1" name="arch_upper" value="41" class="chk-col-black"
type="checkbox">
<label for="md_checkbox_1">Upper</label>
<input id="md_checkbox_2" name="arch_lower" value="41" class="chk-col-black"
type="checkbox">
<label for="md_checkbox_2">Lower</label>
</div>
</div>
</div>
I tried this in laravel validation but i know its wrong because it required for both but i want at least one checkbox is checked.
public function rules()
{
return [
'arch_lower' => 'required',
'agarch_upper' => 'required',
,
];
}
I think you could use Laravel's required-without method:
The field under validation must be present and not empty only when any
of the other specified fields are not present.
Implementation would look something like this:
'arch_upper' => 'required_without: arch_lower',
If, by any chance, you have more checkboxes, you could use required-without-all:
The field under validation must be present and not empty only when all
of the other specified fields are not present.
Implementation:
'arch_upper' => 'required_without_all: arch_lower,another_checkbox',
Note: Code is not tested, if you encounter any errors, let me know.
You can read more on Laravel's official documentantion.
I am trying to use VeeValidate v3 to validate that a start and end time on a given day are available for a reservation. In my form I have the date displayed separately and then 2 input fields for start and end time. In my rule in .extend, I have several issues. The date isn't part of the form, so how do I get access to that in extend? My second question is what is the best way to indicate which field is being validated (is value start time or end time) ?
So far,my fields look like this:
<ValidationObserver>
<div class="w3-third">
<label>From</label>
<ValidationProvider vid='st' rules="available:#st,#et" v-slot="{ errors}">
<dropdown id="starttime" :options="startTimeOptions" v-model="startTime" #change="getDuration()"></dropdown>
<span>{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="w3-third ">
<label>Until</label>
<ValidationProvider vid="et" rules="available:#st,#et" v-slot="{ errors}">
<dropdown id="endtime" :options="endTimeOptions" v-model="endTime" #change="getDuration()"></dropdown>
<span>{{ errors[0] }}</span>
</ValidationProvider>
</div>
</ValidationObserver>
And my extend looks like this, I haven't gotten very far with this since I need the value for day as well:
validate(value, {s, e} ) {
var start= moment(day + "T" + s).format('YYYY-MM-DDTHH:mmZ')
var end = moment(day + "T" + e).format('YYYY-MM-DDTHH:mmZ')
/* make call to server here to see if that is available. */
return true;
},
params:[ 's', 'e']
});
I think you're on the right track. Try switching to the rules Object instead of string for ValidationProvider, and pass in your day property there.
<ValidationProvider vid="st"
:rules="{'available':['#st','#et',day]}"
v-slot="{ errors}">
In my Laravel+Vue.js SPA ( Single Page Application) I am using the phone number input validation package from here, BootstrapVue from here and Veevalidate from here .
I think I need to show only the code inside my component file. The vue-phone-number-input component shows blue border and HTML5 error message tooltip (?) upon invalid data but no error message appears in red as it happens with name field. My code follows in EditProfile.vue:
<ValidationObserver ref="form" v-slot="{ passes }">
<div id="registration_form">
<b-form #submit.prevent="passes(onSubmit)" #reset="resetForm">
<ValidationProvider vid="name" rules="required|min:2" name="name" v-slot="{ valid, errors }">
<b-form-group
label="User Name:"
label-for="exampleInput1"
>
<b-form-input
type="text"
v-model="name"
:state="errors[0] ? false : (valid ? true : null)"
placeholder="Enter your name"
></b-form-input>
<b-form-invalid-feedback id="inputLiveFeedback">{{ errors[0] }}</b-form-invalid-feedback>
</b-form-group>
</ValidationProvider>
<ValidationProvider vid="mobile" rules="required" name="mobile" v-slot="{ valid, errors }">
<b-form-group
label="Mobile:"
label-for="exampleInput1"
>
<vue-phone-number-input
v-model="mobile"
default-country-code="BD"
required
disable-leading-trailing-space
:state="errors[0] ? false : (valid ? true : null)"
#update="updatePhoneNumber"
placeholder="Enter Mobile Number"
/>
<b-form-invalid-feedback id="inputLiveFeedback">{{ errors[0] }}</b-form-invalid-feedback>
</b-form-group>
</ValidationProvider>
<b-button type="submit" variant="primary">Submit</b-button>
<b-button type="reset" variant="danger">Reset</b-button>
</b-form>
</div><!-- end of id registration_form-->
</ValidationObserver>
JS part inside EditProfile.vue is:
import Datepicker from 'vuejs-datepicker';
import { ValidationObserver, ValidationProvider } from "vee-validate";
export default {
name: "EditProfile",
components: {
ValidationObserver,
ValidationProvider,
Datepicker
},
data: () => ({
name: "",
mobile:""
}),
methods: {
onSubmit() {
console.log("Form submitted yay!");
},
resetForm() {
this.name = "";
this.mobile = "";
requestAnimationFrame(() => {
this.$refs.form.reset();
});
}
}
};
When the submit button is pressed then validation works for name field nad for vue-phone-number-input it also happens but no error message shows up in red color.
My Vue.js version is 2.6.10 and I used the latest versions of BootstrapVue and Veevalidate (3) as well.
How can I make the error message appear in red color for vue-phone-number-input element ?
In bootstrap, invalid-feedback is only shown when it has a sibling input (or select etc) that is set to the state is-invalid. Chances are that vue-phone-number-input does not meet that criteria. So, instead you should make your error message like this:
<span class="text-danger" v-show="errors[0]">{{ errors[0] }}</span>
I have implemented a Kendo DropDownlist as below:
<kendo-dropdownlist v-if="PaymentTypeList != null"
name='PayType'
class="form-control"
v-model="vModel.PayType"
:data-text-field="'Text'"
:data-value-field="'Id'"
:auto-bind="true"
:data-source="PaymentTypeList">
</kendo-dropdownlist>
I have to render only one div below according the value selected on the dropdown list.
<div v-if="vModel.PayType == PaymentTypes.Cash">
<div class="row">
<div class="col-sm-3">
<div class="form-group">
<label>Pay Code
<span class="text-red">*</span>
</label>
<input type="text" class="form-control" id="PayCode" name="PayCode" autocomplete="off" v-model="vModel.PayCode">
</div>
</div>
</div>
</div>
<div v-else>
<kendo-dropdownlist v-model="dropdownlistValue"
:data-source="dataSourceArray"
:data-text-field="'text'"
:data-value-field="'value'">
</kendo-dropdownlist>
</div>
But the first div is never shown whatever is the condition either false or true.
When i try with the v-show it works.
How should i make this code able to work on v-if.
The plunker implementation is here on the link
https://plnkr.co/edit/Xbhm67KjnpovOWNBy2O2?p=preview
Edited: According to vue js
v-if is also lazy: if the condition is false on initial render, it will not do anything - the conditional block won’t be rendered until the condition becomes true for the first time.
But in my case when the initial condition is true the first div is rendered, and after that the first division is never rendered whatever will be the condition either true or false.
I suggest you solve this issue by using v-show. v-if is "better" suited for (not) rendering the DOM at all opposed to v-show that is just manipulating display of DOM (hidden/shown).
Forked your Plunker to this one: https://plnkr.co/edit/PjOhBbuTO6czxvQQ10da?p=preview (had to introduce "empty" select value).
Hope it helps...