I'm creating a signup form which verifies if a login_id selected by the user is available on the server.
This form is on bootstrapvue.
<b-form #submit="onSubmit" v-if="show" #reset="onReset" >
<b-form-group
id="signupInputGroup0"
label="Login:"
label-for="exampleInput0"
description="Choose a unique login id"
valid-feedback="Great! Your login id is unique"
invalid-feedback="Login id already exists. Please pick another login.">
<b-form-input
id="signupInput0"
type="login"
v-model="form.login"
required
placeholder="Enter a unique login id"
/>
<b-button variant="success" #click="onCheckAvailability">Check Availability</b-button>
</b-form-group>
...
My question now is regarding the call to onCheckAvailability. This function is going to call an API and set the valid status to LoginId field.
Am actually considering vuelidate to create validations for all form fields. Customize my own validation method call isUniqueLogin
validations:{
form: {
login: {
required,
isUniqueLogin: this.onCheckAvailability(this.login)
}, ...
In such a case, how do we pass this validation on click back to the form?
I'm looking for a neat and elegant way of doing it.
And also OK to use something else that can do this well.
Note: This is not a submit click. It's a simple field validation on click.
Sometimes, using frameworks can be tedious if I don't understand the paradigms well.
Both <b-form-group> and <b-form-input> have a prop called state which accepts true if the value is valid, false for invalid, or null if not validated.
You would need to set this prop (on both <b-form-group> and <b-form-input>) to the result of the checkAvailability call.
Note that invalid-feedback and valid-feedback props are used on <b-form-group> not <b-form-input>
See https://bootstrap-vue.js.org/docs/components/form-group
Related
I have the following html div. The {{ }} represent liquid syntax and it renders server side.
<div class="two columns">
<button
data-value='{{ value }}'
class="button-selection"
:class="selectionButtonClass($event)"
#click="selectionButton($event)"
>
<span class="text">{{ value }}</span>
</button>
</div>
In a vue 3 instance I have the following method in the same page.
selectionButtonClass(el) {
console.log('checking val');
console.log(el);
}
My goal is to set a conditional class in the selectionButton method but I can't get the element to get the data attribute. The above appears in the console log as undefined. However the #click does show the event obviously it's recognize the onclick but not the class method check.
$event is only available to event handlers. #click="selectionButton($event)" defines an inline event handler, while :class="selectionButtonClass($event)" is not an event handler.
To get the element, you need to add a ref attribute to the <button>:
<button
ref="selectionButton"
data-value='{{ value }}'
class="button-selection"
:class="selectionButtonClass($event)"
#click="selectionButton($event)"
>
And access it by this.$refs.selectionButton, assuming you are using the options API. However, the ref is available only after the component is mounted. Thus you need to handle the case where the ref is null.
More on template refs: https://vuejs.org/guide/essentials/template-refs.html
Since you are using server side rendering, I think it would be better to render the value as a parameter of the selectionButton function on the server side.
I am using the vue-multiselect library like so:
in src/components/FeedbackForm.vue
<div>
<CustomerSelect :required="true" />
</div
Question: How can I make this select component required on the client-side? I thought I would be able to simply add an HTML5 attribute like so:
in src/components/CustomerSelect.vue
template section:
<multiselect
id="customer_last_name_input"
v-model="c_lastname_value"
:options="getActiveUserProfiles"
label="lastname"
track-by="uid"
:close-on-select="true"
#select="onSelect"
#remove="onRemove"
required <----------can't do this?
>
script section:
props: ['required']
Doing the above code does not invoke client-side validation in the browser like a regular HTML select element. Thanks for any help.
As for docs it accepts a allowEmptybool prop.
allowEmpty || Boolean || Allows to remove all selected values.
Otherwise one must be left selected.
so it would be
<multiselect
id="customer_last_name_input"
v-model="c_lastname_value"
:options="getActiveUserProfiles"
label="lastname"
track-by="uid"
:close-on-select="true"
#select="onSelect"
#remove="onRemove"
:allow-empty="required" <----------do this?
>
I'm only a few months into vue coming from an angularjs background.
I built my first custom directive and it's acting a little odd to me.
Vue.directive('silly',{
componentUpdated: function (el, binding, vnode) {
console.log("it was called");
}
});
and I place it on my form like this:
<form id="opt-cpmt-form" method="post" class="mri-grid mri-p-none">
<label for="one">name<input id="one" type="text" v-model="local.name" v-silly class="form-control"></label><br/>
<label for="two">phone<input v-isnumeric id="two" type="text" v-model="local.phone" class="form-control "></label><br/>
<label for="two">zip<input id="three" type="text" v-model="local.zip" class="form-control" ></label><br/>
</form>
It kinda works...the part that I didn't understand is that my v-silly directive is called when any of the other fields are updated too. It seems to be related to the model but I only want my directive called when the field changes.
Any ideas??
It's an expected behaviour as the component updates whenever a piece of its data object is updated. To not trigger the logic too many times, you can create an event listener when the directive is bound to its parent and then run the logic when a desired event happens.
Vue.directive('silly', {
bind(el) {
this.updateCallback = function(event) {
// Your logic
};
el.addEventListener('input', this.updateCallback);
},
unbind(el) {
el.removeEventListener('input', this.updateCallback);
}
});
In case you plan to listen to the changes of v-model directive, bear in mind that it uses different events based on what element it's bound to. You can read more about that topic in v-model documentation.
v-model internally uses different properties and emits different events for different input elements:
text and textarea elements use value property and input event;
checkbox and radiobutton inputs use checked property and change event;
select fields use value as a prop and change as an event.
Also, from my experience when it comes to the form validation; I've done it using the directives and regretted it afterwards. I found it best to create reusable functions and create the custom form validation for every form. See custom form validation for more.
In Laravel Nova, action modals are rendered in Vue by retrieving a list of fields to display through a dynamic component. I have replaced the action modal with own custom component, but am struggling to achieve the effect I want without also extending the entire set of components for rendering form fields.
I have my CustomResourceIndex.vue, containing a conditionally loaded (via v-if) ActionModal.vue, in which the form fields are rendered like so:
<div class="action" v-for="field in action.fields" :key="field.attribute">
<component
:is="'form-' + field.component"
:resource-name="resourceName"
:field="field"
/>
</div>
where the actual form field component is chosen based on the field.component value.
Those form fields (which I ideally do not want to have to extend and edit) are rendered like so:
<template>
<default-field :field="field" :errors="errors">
<template slot="field">
<input
class="w-full form-control form-input form-input-bordered"
:id="field.attribute"
:dusk="field.attribute"
v-model="value"
v-bind="extraAttributes"
:disabled="isReadonly"
/>
</template>
</default-field>
</template>
I would like to watch the value of specific fields and run methods when they change. Unfortunately due to a lack of ref attribute on the input elements or access to the value that the form element is bound to, I'm not sure how I can accomplish that from within ActionModal.vue.
I am hoping that because I have access to the ids still, there is some potential way for me to emulate this behavior.
Many resources I've found on my own have told me that anything with an ID is accessible via this.$refs but that does not seem to be true. I can only see elements that have an explicitly declared ref attribute in this.$refs, so I am not sure if I've misunderstood something there.
I would recommend looking into VueJS watch property.
You can listen to function calls, value changes etc.
watch: {
'field.component': function(newVal, oldVal) {
console.log('value changed from ' + oldVal + ' to ' + newVal);
},
},
Are those components triggering events? Try looking into the events tab of the Vue DevTools to see if some events are triggered from the default-field component when you update the value.
My guess is that you could write something like:
<div class="action" v-for="field in action.fields" :key="field.attribute">
<component
:is="'form-' + field.component"
:resource-name="resourceName"
:field="field"
#input="doSomething($event)"
/>
</div>
The $event value being the new value of the field.
Hit me on the comments if you have more info on the behavior of the default form fields (Are their complete code accessible somewhere?).
Sorry, I'm still very new to VueJS and it's framework.
I'm trying to use vee-validate and a custom rule to check the value of an input field against an Axios GET response to an API backend. Essentially, if you input an invalid ID, it will throw up an error until you get it right (ie: assigning a ticket to a valid employee, you must enter a valid employee ID).
My template code looks like this right now:
<b-col cols="4">
<b-input-group>
<b-input-group-text style="width:150px;" slot="prepend">Key Owner</b-input-group-text>
<input
class="form-control"
v-model="selected_owner_id"
type="text"
id="ownerId"
name="ownerId"
data-vv-delay="800"
#change="validateCorpId"
v-validate="'ownerId|required'"
v-bind:class="{'form-control': true, 'error': errors.has('ownerId') }"
>
</b-input-group>
<span v-show="errors.has('ownerId')" class="text-danger">{{ errors.first('ownerId') }}</span>
</b-col>
(I am messing around with how to do this, hence the #change to the function that actually does the Axios API call)
Here is the Validate extend rule I have made in the same *.vue file as above:
<script>
import { Validator } from "vee-validate";
import VeeValidate from 'vee-validate'
Validator.extend('ownerId', {
// Custom validation message
getMessage: (field) => `The ${field} is not a valid ID.`,
// Custom validation rule
validate: (value) => new Promise(resolve => {
resolve({
valid: value && (this.validateCorpId(value))
});
})
});
...etc...
The validateCorpId(value) function is later on in the methods: {} block
I have been trying to go through the Vee-Validate docs on how to properly create a custom validation rule but as a newbie, a lot of things still seem missing like, where should that Validate.extend actually sit? Where I put it up top in the 'script' area or inside either the 'create' or 'mount' functions?
I did try that and it gets called right away which isnt what I want -- i only want it to happen when you the user enter or change the data in the field that it calls the function which returns a true|false value.
I also added a field called is_selected_owner_id_valid into the 'data' return block and had my Axios call set that true|false depending on the result but, as it's a boolean, the Validate rule read it immediately and it evaluated incorrectly.
I'm happy to keep working it our for myself, but does anyone have a fully working Validate custom rule I could see and reverse-engineer ? Really hard to find an example of what I am trying to do, involving an API call as part of the rule.
I managed to get my issue resolved by initially copying this similar posted answer here:
Vee-validate (VueJS) - evaluating a condition asynchronously
While it works, I'm not convinced about having the actual APi call in the custom rule. However, thanks to the suggestion by Walter Cejas, I'm going to retro fit my solution into that example provided : https://baianat.github.io/vee-validate/examples/async-backend-validation.html
(I thought I had gone through all the vee-validate examples... i was wrong!)