How to call validate method of Element-UI form - vue.js

I'm trying design some forms with Element-UI in one of my Vue.js projects. I want to check if the form is valid before continuing any further action once the submit button is clicked.
Can anybody direct me to an example how to reference the element inside a Vue component and check its validity.
Following is my form setup.
<div id="frmEventCreate">
<el-form v-bind:model="data" v-bind:rules="rules">
<el-form-item label="Event name" prop="name" required>
<el-input v-model="data.name"></el-input>
</el-form-item>
<el-button type="success" v-on:click="next" icon="el-icon-arrow-right"> Next Step </el-button>
</el-form>
</div>
var objEvent = {neme: "Some Name"};
vmEventCreate = new Vue({
el: '#frmEventCreate',
data: {
data: objEvent,
rules: {
name: [
{required: true, message: 'Please input event name', trigger: 'blur'},
{min: 10, max: 100, message: 'Length should be 10 to 100', trigger: 'blur'}
]
},
},
methods: {
next: function () {
// need to check if the form is valid, here..
}
}
});

Here is the link to the validation example in Element UI docs
You need to add a ref attribute to your form like this:
<el-form v-bind:model="data" v-bind:rules="rules" ref="someForm">
Then, when you click on the submit button which is calling the next method in your case you can validate your form like this:
this.$refs['someForm'].validate((valid) => {
if (valid) {
alert('submit!');
} else {
console.log('error submit!!');
return false;
}
});

Related

How do i force user from leaving input box untill the error is resolved or value correct according to validation in vue3?

How do i force user from leaving input box untill the error is resolved or value correct according to validation in vue3 ?
i want user not to leave the input box or cursor should not go to another element until the thrown error is resolved in vue3
Add blur event, and check, use ref ... if blur and if input has error, focus input.
<template>
<div class="home">
<form class="field">
<input
id="movieInput"
type="text"
placeholder="Search for a movie"
ref="movieInput"
#input="onInput"
#blur="onBlurInput"
/>
</form>
</div>
</template>
<script>
export default {
name: 'HomeView',
data: () => ({
isFieldError: true,
}),
methods: {
onInput(event) {
const { value } = event.target;
this.isFieldError = value.length < 3;
},
onBlurInput() {
if (this.isFieldError) {
this.$refs.movieInput.focus();
}
},
},
};
</script>

Check input filed that is looped over and set status for each element accordingly

I am working in a vue component and have a v-for loop in the html that creates some v-text-fields. I want to be able to verify that the v-text-field matches one of the elements in an answer array. I have it set up like this below right now.
<v-expansion-panel
v-for="(element, index) in prompts"
:key="'bucket-a-' + index"
>
<v-expansion-panel-header>
<v-container>
<v-expansion-panel-content>
<v-text-field
label="Answer must match one of the answer values from above"
clearable
v-model="element.answer"
:error="validator"
#input="answerInputValidator($event, element)"
></v-text-field>
</v-expansion-panel-content>
</v-container>
</v-expansion-panel-header>
</v-expansion-panel>
The answer input validator function is set up like this below:
answerInputValidator(evt, prompt) {
this.answerObjects.forEach(element => {
if(element.value === evt){
prompt.answer = evt;
return this.validator = false;
}else{
return this.validator = true;
}
});
}
The function works to validate the v-text-field and links to :error with the property this.validator. However, the issue I am having is that this.validator is a variable declared on the whole of the component so if one input area is found to be valid and the user moves onto the next one and starts inputting and invalid response the previous input area will also be set to invalid. Because this.validtor then gets set to true because the input is invalid on the element being manipulated. But I don't want it to affect all other v-text-fields. I need to be able to check the input against an array of information but treat each field differently. Any ideas on how to achieve this?
You'll need as many error validator flags as you have v-text-field elements. I don't know the structure of the prompts array but maybe each element of it can have its own isError property initialized to false.
Then each v-text-field can have the error prop set as :error="element.isError" Then the validator method can receive each element and toggle that element's individual isError flag on or off without affecting any others.
I don't know how v-text-field works since I have never user Vuetify, but as another answer says each of the prompt could have a property to check is the answer match.
Here is a snippet of how I would do it using plain vue.
Template
<template>
<main>
<div v-for="option in options" :key="option.id">
<input
type="text"
v-model="option.userAnswer"
#input="handleAnswer(option)"
/>
</div>
</main>
Data
data() {
return {
options: [
{
id: 1,
question: "question 1",
userAnswer: "",
rightAnswer: "hello 1",
isAnswerCorrect: false,
},
{
id: 2,
question: "question 2",
userAnswer: "",
rightAnswer: "hello 2",
isAnswerCorrect: false,
},
{
id: 3,
question: "question3",
userAnswer: "",
rightAnswer: "hello3",
isAnswerCorrect: false,
},
],
};
},
Methods
methods: {
handleAnswer(option) {
if (option.userAnswer === option.rightAnswer) {
console.log("right");
option.isAnswerCorrect = true;
} else {
console.log("error");
option.isAnswerCorrect = false;
}
},
},
I hope it helps!

When data is changed within the watch function, dom does not update

Below is the data in a component
data: function () {
return {
sltAreaStyle: {
paddingTop: "3%",
},
checkedTypes: ["krw", "btc", "usdt"],
};
},
Below is watch function of checkedTypes data
watch: {
checkedTypes: {
handler: function (newVal, oldVal) {
if (newVal.length < 1) {
alert("Choose one or more.");
var last = oldVal[0];
this.$data.checkedTypes = [last];
}
},
},
},
Below is my html template
<div class="ckbxArea">
<input type="checkbox" value="krw" v-model="checkedTypes">KRW</input>
<input type="checkbox" value="btc" v-model="checkedTypes">BTC</input>
<input type="checkbox" value="usdt" v-model="checkedTypes">USDT</input>
</div>
I want to change the last value to checkedTypes data when all the check boxes are unchecked.
If the first checkbox was finally unchecked, the checkedTypes would be 'krw' like checkedTypes = ['krw'] The checkedTypes data is ['krw'], but all checkbox tags are unchecked. That is, dom has not been updated. I don't think I understand Vue's life cycle well. I think this problem is related to the life cycle of v-model and components, but I don't know what the problem is. Please explain why this problem occurs and tell me how to solve it.
Well this is more about Vue rendering mechanisms for v-modeleld input controls.
Check this:
Only one last checkbox is checked so model value is ['krw']
Uncheck last checkbox
Watcher is executed - new model value is [] BUT the watcher immediately sets it to same value as before ... ['krw']
Vue re renders the template (see the message in the console) BUT as the v-model value is same as during last render, it does not update the checkbox
Simple solution to situations like this is to postpone the update to next rendering cycle using nextTick
this.$nextTick(() => {
this.checkedTypes = [last];
})
new Vue({
el: "#app",
data: function () {
return {
checkedTypes: ["krw", "btc", "usdt"],
};
},
updated() {
console.log("Component updated")
},
watch: {
checkedTypes: {
handler: function (newVal, oldVal) {
if (newVal.length < 1) {
alert("Choose one or more.");
//console.log("Choose one or more.");
var last = oldVal[0];
// this.checkedTypes = [last];
this.$nextTick(() => {
this.checkedTypes = [last];
})
}
},
},
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.14/vue.js"></script>
<div id="app">
<input type="checkbox" value="krw" v-model="checkedTypes"/> KRW
<input type="checkbox" value="btc" v-model="checkedTypes"/> BTC
<input type="checkbox" value="usdt" v-model="checkedTypes"/> USDT
<pre>{{ checkedTypes }}</pre>
</div>

How to verify vue-formulate form from another button

I would like to verify my formulate not through vue-formulate input type submit but by another button. I mean, I have a form and inside this I include vue formulate and when I submit my form, I would like to check my vue-formulate before sending data.
Here is an example
<template>
<div class="eventForm">
<el-form :model="event" label-position="top" ref="form" :rules="rules" :hide-required-asterisk="true" :disabled="formType=='view'?true:false">
<!-- Input exemple for element form -->
<el-form-item :label="$t('Event category')" prop="event_category" >
<el-radio-group v-model="event.event_category">
<el-radio-button
v-for="value in listOfEventCategory"
:key="value[0]"
:label="value[0]"
:value="value[0]">
{{ value[1] }}
</el-radio-button>
</el-radio-group>
</el-form-item>
<!-- My other element form -->
...
<!-- Call of vue-formulate inputs through json -->
<FormulateForm
v-model="event.data"
:schema="event.template"
/>
<!-- My button to save form -->
<el-form-item class="lst-btn-end-form" v-if="formType!='view'">
<el-button #click.stop="save('form')">{{ $t('Save') }}</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
import Vuex from 'vuex'
export default {
name: 'settingsEventForm',
data () {
return {
headers: '',
loading: false,
contributors: [],
formSchema: []
}
},
computed: {
...Vuex.mapGetters(['event', 'listOfEventCategory'])
},
methods: {
...Vuex.mapActions({
createEvent: 'createEvent',
getListOfEventCategory: 'getListOfEventCategory',
}),
save (formName) {
// Here I would like to call the function to verify if elements from vueformulate are valid
...
// Then verify the other elements and save the form
this.$refs[formName].validate((valid) => {
if (valid) {
// Save my form
this.createEvent(this.event)
} else {
this.$toast.open({
message: this.$root.$t('check_data_entered'),
type: 'is-danger'
})
return false
}
})
},
},
mounted: function () {
this.getListOfEventCategory()
},
}
</script>
Is it possible to do what I want ? Someone can help me please ?
Thanks !

vuejs: Trying to focus the input using v-el directive

I am creating a wizard login form where the Mobile Number is first entered and
password is entered next.
Here am trying to focus the password input using
this.$$.passwordInput.focus()
however if am getting the error given below
Uncaught TypeError: Cannot read property 'focus' of undefined
The full code is below
index.html
<div id="login">
<div v-if="flow.mobile">
<form v-on="submit: checkmobile">
<p>
Mobile Number<br>
<input type="text" v-model="mobile_number" v-el="mobileNumber">
</p>
</form>
</div>
<div v-if="flow.password">
<form v-on="submit: checkpassword">
<p>
Password<br>
<input type="password" v-model="password" v-el="passwordInput">
</p>
</form>
</div>
script.js
var demo = new Vue({
el: '#login',
data: {
flow: {
mobile: true,
password: false
}
},
methods: {
checkmobile: function(e) {
e.preventDefault();
this.flow.mobile = false;
this.flow.password = true;
this.$$.passwordInput.focus();
},
checkpassword: function(e) {
e.preventDefault();
}
}
});
Your passwordInput is inside a v-if block, which only gets rendered when you set flow.password to true; However Vue uses asynchronous rendering, so the v-if block will not be rendered immediately. You can use Vue.nextTick to wait until it does:
this.flow.password = true;
var self = this;
Vue.nextTick(function () {
self.$$.passwordInput.focus();
});
Read the guide about async rendering for more details.
In Vue.js 2.x you can create your own directive to focus a field automatically:
Vue.directive('focus', {
inserted: function (el) {
el.focus();
},
update: function (el) {
Vue.nextTick(function() {
el.focus();
})
}
})
Then you can use v-focus attribute on inputs and other elements:
<input v-focus>
Working example: https://jsfiddle.net/LukaszWiktor/cap43pdn/
If you are using vuejs 2, you should read this:
https://v2.vuejs.org/v2/guide/migration.html#v-el-and-v-ref-replaced
--
In this case, in your template:
use ref="passwordInput" instead v-el="passwordInput"
and in your method:
this.$refs.passwordInput.focus()
I hope this help you!
Glad this worked for some of you.
I have no idea why, but after trying every conceivable variation of the accepted answer I could not get the $$.ref property when using v-repeat.
I could only access the newly created dom elements like so:
new Vue({
el: '#reporting_create',
data: {
recipients: {
0: {
fname: null,
lname: null,
email: null,
registration: false,
report: false
}
},
curRec:1
},
methods: {
addRecipient: function(){
event.preventDefault();
this.recipients.$add(
this.curRec,
{
fname: null,
lname: null,
email: null,
registration: false,
report: false
}
);
var num = this.curRec;
this.$nextTick(function () {
console.log(this._children[num].$$.rowrec);
newSwitches.find('.switch').bootstrapSwitch();
})
this.curRec++;
}
}})
html:
<template v-repeat="recipients">
<div class="row" v-el="rowrec">
<div>{{$key}}</div>
</div>
</template>
The addRecipients function was called outside the v-repeat so even the suggested answer here did couldn't help
Not sure if there is an issue with doing it this way but it works and I'm tired.
Vue.js 1 works a bit different.
Example:
<textarea v-el:model_message></textarea>
JS:
this.$els.model_message.focus();
If you are using Vue.js 2.0, you should do the following:
<input type="text" v-model="currentItem.name" ref="txtName">
So you can access this input by using the $refs object:
this.$refs.txtName.focus();
I hope it helps.
Vue v2's documentation uses focus as an example in writing custom directives. All of the needed code is supplied with the example, https://v2.vuejs.org/v2/guide/custom-directive.html. First you must register the directive. The link shows how to register it locally on the component.
// Register a global custom directive called `v-focus`
Vue.directive('focus', {
// When the bound element is inserted into the DOM...
inserted: function (el) {
// Focus the element
el.focus()
}
})
Having done this, you are now able to use v-focus on an element:
<input v-focus>
Like so.