Vee validate 4 select's selected prop doesnt work - vue.js

I'm having a problem with vee-validate package.
My problem is the package cannot handle the selected attribute.
When the condition is true in the "selected" prop, the browser doesn't select it. I'm trying like this:
<div class="form-group">
<Field name="brand_id"
as="select"
class="form-control"
id="brandSelect"
>
<option value="">Válassz egyet</option>
<option v-for="brand in brands"
:value="brand.id"
:selected="product.brand && product.brand.id == brand.id"
>
{{ brand.title }}
</option>
</Field>
<ErrorMessage name="brand_id" />
</div>
package.json:
{
"private": true,
"scripts": {
"dev": "vite",
"build": "vite build"
},
"devDependencies": {
"#popperjs/core": "^2.10.2",
"#vitejs/plugin-vue": "^3.0.1",
"axios": "^0.27.2",
"bootstrap": "^5.2.1",
"laravel-vite-plugin": "^0.6.0",
"lodash": "^4.17.21",
"postcss": "^8.1.14",
"sass": "^1.32.11",
"vite": "^3.0.0",
"vue": "^3.2.37"
},
"dependencies": {
"vee-validate": "^4.6.9",
"yup": "^0.32.11"
}
}
Anybody had/has this issue too?

With some workaround I have a solution to set the brand_id attributes correctly in the form with setFieldValue function of the correct <Form> ref:
let self = this;
Object.values(this.products).forEach(function (product) {
if (! product.brand) {
return;
}
let productFormRef = 'productForm' + product.id;
self.$refs[productFormRef][0].setFieldValue('brand_id', product.brand.id);
});

What worked for me is to move the whole select inside the Field:
<Field as="div"
v-slot="{ field }"
v-model="product.brand.id"
name="brand_id"
class="form-group"
>
<select v-bind="field"
name="brand_id"
class="form-control"
id="brandSelect"
>
<option value="">Válassz egyet</option>
<option v-for="brand in brands"
:value="brand.id"
>
{{ brand.title }}
</option>
</select>
<!-- I can't remember if/how ErrorMessage works inside the slot -->
</Field>

Related

How to set custom component fields value in Vue Query Builder

I am using https://dabernathy89.github.io/vue-query-builder/ Vue Query Builder. Now, I need to use custom-component type. Here is the code for the rules in the parent component:
rules: [
{
type: "text",
id: "url_regex",
label: "Url Regex",
},
{
type: "text",
id: "page_source",
label: "Page Source ",
},
{
type: "custom-component",
id: "page_dom_element",
label: "Page Dom Element",
operators: [],
component : PageDomElement,
},
],
Above you can see that, third rules contain custom-component type and the component is PageDomElement.
And this PageDomElement is look like this:
<template>
<div>
<input type="text" id="page_dom_element" class="form-control" placeholder="jQuery path"/>
<select name="" id="" class="form-control">
<option value="equals">equals</option>
<option value="does-not-equals">does not equals</option>
<option value="contains">contains</option>
<option value="does-not-contain">does not contain</option>
<option value="is-empty">is empty</option>
<option value="is-not-empty">is not empty</option>
<option value="begins-with">begins with</option>
<option value="end-with">end with</option>
</select>
<input type="text" class="form-control"/>
</div>
</template>
<script setup lang="ts">
</script>
<style scoped>
</style>
Now, my question is how can I get the this custom component fields value ?

How to use flatpickr with vee-validation in vuejs

i have use it but date not selected on first click, used version is "vue": "2.x","vue-flatpickr-component": "^8.1.6",
and my code is:
<b-form-group class="requied_field showOnCheck"
:label="$t('Start On')"
label-for="v-autoresponder_start_date"
:description="$t('start_on_desc')">
<validation-provider
#default="{ errors }"
:name="$t('Start On')"
rules="required">
<b-input-group class="input-group-merge">
<b-input-group-prepend is-text>
<feather-icon icon="CalendarIcon" />
</b-input-group-prepend>
<flat-pickr
v-model="formData.autoresponder_start_date"
:disabled="isDisabledField"
class="form-control"
id="v-autoresponder_start_date"
:config="{ defaultDate:'today',enableTime:true, minDate:'today', maxData:formData.autoresponder_end_date, dateFormat: 'Z', altInput: true}"
/>
</b-input-group>
<small class="text-danger">{{ errors[0] }}</small>
</validation-provider>
Please anyone solve the problem.
Add your config inside data function
export default {
data () {
return {
dateConfig:
{
defaultDate:'today',
enableTime:true,
minDate:'today',
maxData:formData.autoresponder_end_date,
dateFormat: 'Z',
altInput: true
}
}
},
}
Use as follows
<flat-pickr
v-model="formData.autoresponder_start_date"
:disabled="isDisabledField"
class="form-control"
id="v-autoresponder_start_date"
:config="dateConfig"
/>

VeeValidate 4 Field Validation State

I'm trying to imitate Bootstrap form validation styling with Vue and Vee-validate.
In order to have that Boostrap validation error message, when there's a validation error, the input itself must have is-invalid class presents. And in addition, the error message element must have invalid-feedback class, of course.
I'm struggling to add is-invalid class to the input when there's a validation error.
In Vee-validate 3, I was able to control the input element's classes with this guide. But it seems to be deprecated.
This is a code sandbox that you can play with. Nothing extra-ordinary, just straight out of Veevalidate example.
<template>
<div id="app">
<Form #submit="onSubmit">
<Field name="email" type="email" :rules="validateEmail" class="form-control"/>
<ErrorMessage class="invalid-feedback" name="email" />
<button class="btn btn-primary">Sign up</button>
</Form>
</div>
</template>
<script>
import {
Form,
Field,
ErrorMessage
} from "vee-validate";
export default {
components: {
Form,
Field,
ErrorMessage,
},
methods: {
onSubmit(values) {
console.log(values, null, 2);
},
validateEmail(value) {
// if the field is empty
if (!value) {
return "This field is required";
}
// if the field is not a valid email
const regex = /^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i;
if (!regex.test(value)) {
return "This field must be a valid email";
}
// All is good
return true;
},
},
};
</script>
<style>
span {
display: block;
margin: 10px 0;
}
</style>
Versions
"vee-validate": "^4.5.11",
"vue": "^3.2.33",
You can render more complex fields, by utilizing the scoped slots of the <Field />-component.
If you replace your Field-component with the following, it should work as expected:
<Field name="email" :rules="validateEmail" v-slot="{ field, errors }">
<input v-bind="field" type="email" :class="{'is-invalid': !!errors.length }" />
</Field>

Array of Dynamic Dependent Select Box in Vue.js

I have an array of Depend select box which contains Universities and courses. Each university has its own course. and I have built the course dropdown which depends on the university. I can successfully get university course from server request but the problem is when I change the select university it's changing all course fields. How I can get rid of the problem please give me some ideas. Thanks
<template>
<form #submit.prevent="handleSubmit">
<div class="col col-md-12">
<div v-for="(interest, index) in interests" :key="index" class="row">
<div class="col col-md-6">
<div class="form-group mb-4">
<label for="select-ins">Interested Universities </label>
<select
v-model="interest.institute_id"
class="form-control"
#change="onChangeUniversity($event)"
>
<option disabled value="">Select a University</option>
<option
v-for="institute in institutes"
:key="institute.id"
:value="institute.id"
>
{{ institute.institute_name }}
</option>
</select>
</div>
</div>
<div class="col col-md-6">
<div class="form-group mb-4">
<label>Interested Course</label>
<select
v-model="interest.course_id"
class="form-control"
#change="onChangeCourse($event)"
>
<option disabled value="">Select a Course</option>
<option
v-for="course in courses"
:key="course.id"
:value="course.id"
>
{{ course.course_name }}
</option>
</select>
</div>
</div>
<div class="col col-md-12 text-right">
<div class="row ml-4">
<div v-show="index == interests.length - 1">
<button
class="btn btn-warning mb-2 mr-2 btn-rounded"
#click.prevent="add"
>
Add
</button>
</div>
<div v-show="index || (!index && interests.length > 1)">
<button
class="btn btn-danger mb-2 mr-2 btn-rounded"
#click.prevent="remove"
>
Remove
</button>
</div>
</div>
</div>
</div>
</div>
</form>
</template>
<script>
export default {
data() {
return {
institutes: [],
courses: [],
interests: [
{
institute_id: "",
course_id: "",
},
],
};
},
mounted() {
axios.get("/institues").then((res) => {
this.institutes = res.data;
});
},
methods: {
onChangeUniversity(event) {
let universityId = event.target.value;
axios.get(`/institute-course/${universityId}`).then((res) => {
this.courses = res.data;
});
},
add() {
this.interests.push({
institute_id: "",
course_id: "",
});
},
remove(index) {
this.interests.splice(index, 1);
},
},
};
</script>
check screenshot
http://prntscr.com/115mkn5
lets start at your mounted hook.
you call for a API to receive all available institutes. so far so good. each institute got is own ID, this is important for later, lets keep that in mind.
now your using a function which will then call on a "change" event, like onChangeUniversity this is a good way on preventing to overload data in a page, nice idea just to fetch data only when they are needed.
then comes the tricky part which makes it difficult for you and everyone else reading your code.
you have this courses array in your data which normally belongs to the related institute. this array should not be handled as a second array apart from institutes, it should be a child of it.
like check this data structur:
institutes: [
{
institute_name: "WhatEver1",
id: 0,
courses: [{ course: 1 }, { course: 2 }, { course: 3 }],
}
]
instead of this:
institutes: [
{
institute_name: "WhatEver1",
id: 0,
},
],
courses: [{ course: 1 }, { course: 2 }, { course: 3 }],
the first option above is a good nested way to display your data as loop inside a loop.
which means you have to push your courses inside your institute of choice with the belonged id.
your onChangeUniversity function should than do something like this:
onChangeUniversity(event) {
let universityId = event.target.value;
axios.get(`/institute-course/${universityId}`).then((res) => {
const foundedId = this.institutes.findIndex(institute => institute.id === universityId)
this.institutes[foundedId].courses = res.data
});
},
after that its much easier to iterate over and display the data inside the options. and i am sure you will not have that issue anymore.
just try it like that first and give feedback.
Update
<div class="form-group mb-4">
<label>Interested Course</label>
<select
v-model="interest.course_id"
v-if="institute.courses.length !== 0" <-------HERE
class="form-control"
#change="onChangeCourse($event)"
>
<option disabled value="">Select a Course</option>
<option
v-for="course in institute.courses"
:key="course.id"
:value="course.id"
>
{{ course.course_name }}
</option>
</select>
</div>
you need a render condition to stop your courses loop from being iterated when there is no data inside.
also make sure you await till the fetching of courses is completed.
async onChangeUniversity(event) {
let universityId = event.target.value;
await axios.get(`/institute-course/${universityId}`).then((res) => {
this.courses = res.data;
});
},
and also in your mounted hook
async mounted() {
await axios.get("/institues").then((res) => {
this.institutes = res.data;
});
},
if you still struggle please give me a CodeSandbox of your current code.

How to parse object key from handlebars partials.

while working with in express with express-handlebars as view engine and handlebars helpers. where i have created small partial for select tags but it rending plain key as string.
My Select Partials select.hbs file
<select name="" id="">
<option value="">Select</option>
{{#forEach this.select_values}}
<option value="{{../this.opt_value}}"> {{ ../this.opt_label }} </option>
{{/forEach}}
</select>
passing array of object in accounts
accounts: [
{
name: 'John',
email: 'john#example.com'
},
{
name: 'Malcolm',
email: 'malcolm#example.com'
},
{
name: 'David',
email: 'david#example.com'
}
]
Calling partials in layout
{{> modules/select select_values=accounts opt_value='name' opt_label='email'}}
I am using bellow dependencies for
"dependencies": {
"body-parser": "~1.18.2",
"cookie-parser": "~1.4.3",
"debug": "~2.6.9",
"express": "~4.15.5",
"express-handlebars": "^3.0.0",
"handlebars-helpers": "^0.10.0",
"hbs": "^4.0.1",
"morgan": "~1.9.0",
"serve-favicon": "~2.4.5"
}
It works with handlebars builtin helper lookup
added default {{#each}} loop from handlebars.
<select name="" id="">
<option value="">Select</option>
{{#each this.select_values}}
<option value="{{lookup this ../this.opt_value}}"> {{lookup this ../this.opt_label }} </option>
{{/each}}
</select>
Special thanks for #Tamlyn for explanation on lookup helper.