Form validation in vue - javascript

I am trying to understand and work around to validate a simple form but the problem I am facing is, when the page loads, it shows the "Error" or "Success" message, which should display only either on keypress or mouseout event.
Moreover, I cannot figure out how to validate the dropdown and finally when a user click submit, it can check all fields are filled and correct to submit the form. Following is my code and my link to JSFiddle
HTML
<div id="app">
<div>
<label for="name">Name</label>
<input type="text" #keypress="checkField" v-model="name">
<span v-if="checkName">Checks out </span>
<span v-if="!checkName">Pleas enter valid name</span>
</div>
<div>
<label for="Age">Age</label>
<input type="number" #keypress="checkField2" v-model="age">
<span v-if="checkAge">Enter Valid Age </span>
<span v-if="!checkAge">Not a valid age</span>
</div>
<div>
<select name="" id="">
<option disabled selected>Please Choose</option>
<option v-for="gender in genders" :value="gender">
{{gender}}
</option>
</select>
<span v-if="genderField">Please select a gender</span>
<span v-if="!genderField">Green means go</span>
</div>
<div>
<button #click="checkSubmit(e)">Submit</button>
</div>
</div>
JS
data: {
name: "",
checkName: "",
age: "",
checkAge: "",
genders : ["Male",'Female',"Other"],
genderField: ""
},
methods: {
checkField() {
if (!this.amount) {
this.checkName = true
}
},
checkGender() {
if(!this.genders){
this.genderField = true
}
},
checkSubmit(e){
//check if all fields are filled before submitting
alert("it is working")
e.preventDefault()
}
}
})

There is a lot of ways to validate forms. I have a few tips for this kind of case.
Use a form element with #submit.prevent="..." event handler. It will ensure a better user experience;
Do not use #key* event handlers to validate or format a value, instead, use #input. It will prevent you from a lot of headache;
Vue provide a API to watch all the attribute changes, not only when the user changes it.
For solve your problem, you can create a validation attribute and set its content acording the other attributes change.
See the example below:
BTW: I recommend that you take a look on vuelidate
const app = new Vue({
data() {
return {
name: null,
age: null,
gender: null,
genders: ['Male', 'Female', "Other"],
validations: {}
}
},
methods: {
submit(e) {
const keys = Object.keys(this.validations);
// required fields
const required = ['name', 'age', 'gender'];
for (const key in required) {
if (!keys.includes(required[key])) {
alert('Please, insert a ' + required[key]);
return;
}
}
for (const key in this.validations) {
if (!this.validations[key]) {
alert('Please, insert valid ' + key);
return;
}
}
alert("ok");
}
},
watch: {
name(newValue) {
this.validations.name = newValue > '';
},
age(newValue) {
this.validations.age = newValue > 0;
},
gender(newValue) {
this.validations.gender = this.genders.includes(newValue);
}
}
});
app.$mount("#app");
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<form #submit.prevent="submit">
<div>
<label for="name">Name</label>
<input type="text" v-model="name">
<span v-if="'name' in validations && validations.name">Checks out </span>
<span v-if="'name' in validations && !validations.name">Pleas enter valid name</span>
</div>
<div>
<label for="age">Age</label>
<input type="number" v-model="age">
<span v-if="'age' in validations && !validations.age">Enter Valid Age</span>
</div>
<div>
<label for="gender">Gender</label>
<select name="gender" v-model="gender">
<option disabled selected>Please Choose</option>
<option v-for="gender in genders" :value="gender">
{{gender}}
</option>
</select>
<span v-if="'gender' in validations && validations.gender">Green means go</span>
<span v-if="'gender' in validations && !validations.gender">Please select a gender</span>
</div>
<input type="submit" value="Submit">
</form>
</div>

In Angular, we have a built-in option to validate forms. But Vue offers very limited functionality when it comes to create and validate forms. To add more functionality, we have to install a separate package called Vuelidate to validate our Vue application forms.
What is Vuelidate?
According to the Vuelidate website:
“Vuelidate 2 is a simple, but powerful, lightweight model-based validation for Vue.js 3 and Vue 2.x.”
Install
npm install #vuelidate/core #vuelidate/validators
Reference:
https://aaqibqs.medium.com/learn-form-validation-in-vue-3-in-10-minutes-with-vuelidate-8929c5059e66

Related

Uncaught TypeError: Cannot read property 'reset' of undefined

I am trying to reset a forms values to the initial ones:
This is the jquery being used and this is the line that is getting the error. Specifically the $("#gquestion")[0].reset();
function questionhide() {
$("#gquestion")[0].reset();
}
and it's called like this as I want this to happen on the hiding of the form:
$("#gquestion").hide(questionhide());
in this file:
$(document).ready(function() {
$("#passwordreset").hide(passwordhide());
$("#hardwareissue").hide(hardwarehide());
$("#softwareissue").hide(softwarehide());
$("#servicerequest").hide();
$("#question").hide(questionhide());
$("#problemtype").change(function() {
if ($("#problemtype").val() == "passwordreset") {
$("#question").hide(questionhide());
$("#hardwareissue").hide(hardwarehide());
$("#softwareissue").hide(softwarehide());
$("#servicerequest").hide();
$("#passwordreset").show();
} else if ($("#problemtype").val() == "hardware") {
$("#question").hide(questionhide());
$("#passwordreset").hide(passwordhide());
$("#softwareissue").hide(softwarehide());
$("#servicerequest").hide();
$("#hardwareissue").show();
} else if ($("#problemtype").val() == "software") {
$("#passwordreset").hide(passwordhide());
$("#question").hide(questionhide());
$("#hardwareissue").hide(hardwarehide());
$("#softwareissue").show();
} else if ($("#problemtype").val() == "servicerequest") {
$("#servicerequest").show();
} else if ($("#problemtype").val() == "question") {
$("#passwordreset").hide(passwordhide());
$("#hardwareissue").hide(hardwarehide());
$("#softwareissue").hide(softwarehide());
$("#question").show();
}
});
// Password jquery handling ---------------------------------
function passwordhide() {
$("#system option:eq(0)").attr('selected','selected');
$("#passwordreset")[0].reset();
$("#otherdiv").hide();
}
$("#system").change(function() {
if ($("#system").val() == "Other") {
$("#otherdiv").show();
}
else {
$("#otherdiv").hide(function () {
$("#pwother").val('');
});
}
});
// General Question handling ---------------------------------
function questionhide() {
$("#question")[0].trigger('reset');
}
and here is the entire html form that it refers to:
<form method="POST" action="/ticket" id="gquestion">
{{ csrf_field() }}
<input name="probtype" type="hidden" value="General Question">
<div class="form-group">
<label form="control-label">Please tell us your question:</label>
<textarea class="form-control" name="other" id="gqtext"></textarea>
<br>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
The form is included in this:
<h1 id='CaT'>Create a Ticket</h1>
<div class="container">
<form method="POST" action='/ticket' name="categoryselect">
{{ csrf_field() }}
<div class="form-group">
<label class="control-label">Please select what you are having a problem with:</label><br>
<div class="selectContainer">
<select class="form-control" name="problemtype" id="problemtype">
<option disabled selected value>--Select a Category--</option>
<option value="passwordreset">I want to reset my password</option>
<option value="hardware">I want to report a hardware issue</option>
<option value="software">I want to report a system/software issue</option>
<option value="sevicerequest">I want to submit a service request</option>
<option value="question">I have a general question</option>
</select>
</div>
</div>
</form>
#include('createTicket/question')
I have used the indexing on other forms as can be seen with the password reset in the same document, and it has worked. They have more elements in them but they do contain textarea and they have cleared properly and I haven't encountered errors. Doing
function questionhide() {
$("#gtext").val('');
}
works but I would like to know why it won't work with the reset line I have now when other forms do. The title is the error I get when I load it up.
Try one of the following:
$("#gquestion").hide(100, questionhide()); // You can change 100 to any other number. It represents the duration of the hide effect.
or:
$("#gquestion").hide({complete: questionhide()});
And Change: $("#gquestion")[0].reset(); to $("#gquestion").trigger('reset');
Didn't test it, but it should work.
You may also try:
function questionhide(){
document.forms.namedItem("gquestion").reset();
}
Looks to me like your function is being created before the document loads, making $('#gquestion') undefined.

Jquery Validate Form issue while split by 2 screen

I'm using the JQuery validate for my contact form. It was a single page form. But right now its split by 2 set. First set has few fields with a continue button. Then second set will be given by continue button. The continue btn validating without an issue. But it doesn't give the alert like the final submit btn.
Can you help me to resolve this
My Markup
<form name="contact" id="contact" method="post" action="http://action.com">
<div id="form-fields">
<!-- Form Step One -->
<div id="form_step1">
<div class="form-row">
<label class="request_label">Program of Interest</label>
<select id="CurriculumID" name="CurriculumID">
<option selected="selected" value="">What program would you like to study</option>
</select>
<br />
</div>
<div class="form-row">
<label class="request_label">First Name</label>
<input name="firstname" id="firstname" type="text" title="First Name" />
<br />
</div>
<div class="form-row">
<label class="request_label">Last Name</label>
<input name="lastname" id="lastname" type="text" title="Last Name" />
<br />
</div>
<!-- CLOSING (FIRST NAME AND LAST NAME) -->
<div class="req_btn_wrapper">
<a href="javascript:void(0)" id="next">
<img src="images/next_btn.png">
</a>
</div>
</div>
<!-- Form Step Two -->
<div id="form_step2">
<div class="form-row">
<label class="request_label">Email</label>
<input name="email" id="email" type="text" title="Email" />
<br />
</div>
<div class="form-row">
<div class="split-form-row">
<label class="request_label">Phone</label>
<input name="dayphone" id="dayphone" class="form_phone" type="text" onkeypress="return numbersonly(this, event)" title="Phone" />
<br />
</div>
<div class="split-form-row">
<label class="request_label">Zip Code</label>
<input name="zip" id="zip" class="form_zip" type="text" title="Zip Code" />
<br />
</div>
<div id="cityStateInput">
<input name="city" id="city" type="text" title="City" placeholder="City" />
<br />
<select name="state" id="state">
<option selected="selected" value="">Select a State:</option>
<option value="N/A">Orange</option>
<option value="N/A">lorem</option>
</select>
<br />
</div>
</div>
<div class="form-row">
<label class="request_label">Year</label>
<select name="gradyear" id="gradyear">
<option selected="selected" value="">Please Select</option>
<option value="2017">2017</option>
<option value="2016">2016</option>
<option value="2015">2015</option>
<option value="2014">2014</option>
</select>
</div>
<!-- Radio -->
<div class="radio_row">
<p id="military" class="military_label">Are you working in the military?</p>
<div class="radio_option">
<input type="radio" name="verify" value="Yes"><span id="yes1" for="yes">Yes</span>
</div>
<div class="radio_option">
<input type="radio" name="verify" value="No" checked="checked"><span id="no1">No</span>
</div>
</div>
<!-- Radio -->
<div class="clear"></div>
<!-- CLOSING CLEAR -->
<div class="req_btn_wrapper">
<input name="submit" id="submit" type="image" src="images/btn_submit_request.png" value="" />
</div>
</div>
</form>
My Js script
// Validate signup form on keyup and submit
$("#contact").validate({
ignore: ":hidden",
onclick: false,
onfocusout: false,
onsubmit: true,
onkeyup: false,
onkeydown: false,
rules: {
// Insert fields from the form
email: {
email: true
},
zip: {
minlength: 5,
required: true,
checkLabel: true,
zipUS: true
},
city: {
checkLabel: true,
required: true
},
dayphone: {
required: true,
checkPhoneValue: true
},
state: {
required: true
},
firstname: {
required: true,
checkLabel: true
},
lastname: {
required: true,
checkLabel: true
},
},
messages: {
// Place custom error messages
CurriculumID: "Please select a program.",
firstname: "Please enter your first name.",
lastname: "Please enter your last name.",
dayphone: "Please enter a valid phone number.",
email: "Please enter a valid email address.",
zip: "Please enter a valid Zip code.",
gradyear: "Please select H.S. graduation year.",
city: "Please enter your city.",
state: "Please select your state."
},
// Error placement
showErrors: function(errorMap, errorList) {
try {
if (submitted) {
var summary = "Please fix the following: \n\n";
$.each(errorList, function() {
summary += " - " + this.message + "\n";
});
alert(summary);
submitted = false;
}
//this.defaultShowErrors();
} catch (err) {
Raven.captureException(err);
}
},
invalidHandler: function(form, validator) {
try {
submitted = true;
} catch (err) {
Raven.captureException(err);
}
}
}); // END FORM VALIDATION
$(document).ready(function() {
$('#form_step2').hide();
var validateStep1 = function() {
var isValid_1 = $('#CurriculumID').valid();
var isValid_2 = $('#firstname').valid();
var isValid_3 = $('#lastname').valid();
if (isValid_1 && isValid_2 && isValid_3) {
$('#form_step1').hide();
$('#form_step2').show();
return false;
}
}
// Show step 2
$('#next').click(function() {
validateStep1();
});
$('#back-button').click(function() {
$('#form_step1').show();
$('#form_step2').hide();
});
// Check input value against inline label
jQuery.validator.addMethod("checkLabel", function(value, element) {
return this.optional(element) || value != element.title;
}, "Please enter a value.");
})
You have a couple issues that could break the expected behavior of the jQuery Validate plugin...
$("#contact").validate({
ignore: ":hidden",
onclick: false,
onfocusout: false,
onsubmit: true, // <- NEVER set to 'true'
onkeyup: false,
onkeydown: false, // <- No such thing
....
There is absolutely no such thing called onkeydown. Please refer to the documentation for all available options.
The onsubmit option must never be set to true as this breaks the built-in onsubmit function. This option can only be set to false or an over-riding function. If you want to keep the default submit functionality un-altered, then you must remove the onsubmit option from your .validate() method.
See: jqueryvalidation.org/validate/#onsubmit
"Set to false to use only other events for validation.
Set to a Function to decide for yourself when to run validation.
A boolean true is not a valid value".
The continue btn validating without an issue. But it doesn't give the alert like the final submit btn.
As far as your issue, you need to look at your JavaScript error console.
ReferenceError: Can't find variable: submitted
I removed the if (submitted) conditional within showErrors and got your "next" button working...
DEMO: http://jsfiddle.net/vpgmnLg0/

AngularJS reset form completely

I have a pretty big form that's being validated on the client side by Angular. I am trying to figure out how to reset the state of the form and its inputs just clicking on a Reset button.
I have tried $setPristine() on the form but it didn't really work, meaning that it doesn't clear the ng-* classes to reset the form to its original state with no validation performed.
Here's a short version of my form:
<form id="create" name="create" ng-submit="submitCreateForm()" class="form-horizontal" novalidate>
<div class="form-group">
<label for="name" class="col-md-3 control-label">Name</label>
<div class="col-md-9">
<input required type="text" ng-model="project.name" name="name" class="form-control">
<div ng-show="create.$submitted || create.name.$touched">
<span class="help-block" ng-show="create.name.$error.required">Name is required</span>
</div>
</div>
</div>
<div class="form-group">
<label for="lastName" class="col-md-3 control-label">Last name</label>
<div class="col-md-9">
<input required type="text" ng-model="project.lastName" name="lastName" class="form-control">
<div ng-show="create.$submitted || create.lastName.$touched">
<span class="help-block" ng-show="create.lastName.$error.required">Last name is required</span>
</div>
</div>
</div>
<button type="button" class="btn btn-default" ng-click="resetProject()">Reset</button>
</form>
And my reset function:
$scope.resetProject = function() {
$scope.project = {
state: "finished",
topic: "Home automation"
};
$("#create input[type='email']").val('');
$("#create input[type='date']").val('');
$scope.selectedState = $scope.project.state;
// $scope.create.$setPristine(); // doesn't work
}
Also if you could help me clear the input values of the email and date fields without using jQuery would be great. Because setting the $scope.project to what's defined above doesn't reset the fields for some reason.
Try to clear via ng-model
$scope.resetProject = function() {
$scope.project = {
state: "finished",
topic: "Home automation"
};
$("#create input[type='email']").val('');
$("#create input[type='date']").val('');
$scope.selectedState = $scope.project.state;
$scope.project = {
name: "",
lastName: ""
};
}
As mentioned in the comments, you can use $setUntouched();
https://docs.angularjs.org/api/ng/type/form.FormController#$setUntouched
This should set the form back to it's new state.
So in this case $scope.create.$setUntouched(); should do the trick
Ref all that jquery. You should never interact with the DOM via controllers. That's what the directives are for
If you want to reset a given property then do something like:
$scope.resetProject = function() {
$scope.project = {
state: "finished",
topic: "Home automation"
};
$scope.project.lastName = '';
$scope.project.date= '';
}

ng-disabled in Angular validation not working as expected

http://plnkr.co/edit/9Yq6aZHtKCuZMtPbjBIN?p=preview
I've tried and tried to get this to work but I've had no luck. I'm trying to disable the submit button using angularJS and the built in validation function. What I find is that when you first load the form, the submit button is active--not disabled!
I've tested and tried and I've found that my validation code accepts an empty string / null string in the Team Name, despite me requiring the input.
Does anyone know how to format this correctly? The ONLY way I've gotten it to work is to fudge the data with replacing an empty string with a single space...in production this is unacceptable...
Here is the index.html:
<body ng-controller="EnterController as enter">
<div class="panel panel-primary">
<div class="panel-body">
<form name="enterFormNew" ng-submit="enter.TeamNameNext()" autocomplete="off" novalidate>
<div class="row">
<div class="col-xs-8 col-md-6">
<div class="form-group">
<label for="teamname">Team Name</label>
<input name="TeamName" ng-required ng-minlength="2" ng-maxlength="40" ng-model="enter.Team.Name" type="text" id="teamname" class="form-control" />
<p ng-show="enterFormNew.TeamName.$touched && enterFormNew.TeamName.$invalid">This is not a valid team name.</p>
</div>
<div class="form-group">
<label for="division">Division</label>
<select name="selectDivision" ng-required ng-model="enter.Team.Division" id="division" class="form-control" ng-options="division.Name for division in enter.Divisions track by division.Id ">
<option value="">Select...</option>
</select>
<p ng-show="enterFormNew.selectDivision.$touched && enterFormNew.selectDivision.$invalid">A valid Division needs to be selected.</p>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-2">
<button type="submit" class="btn btn-primary" ng-disabled="enterFormNew.$invalid">Next</button>
</div>
</div>
</form>
</div>
</div>
</body>
And here is the app.js:
angular.module('Enter', [])
.controller("EnterController", [
function() {
this.RegistrationPhase = 0;
this.Divisions = [{ Id: 1,Name: "Normal"}, {Id: 2,Name: "Not Normal"}];
this.Team = { Name: "", ResumeKey: null, Division: { Id: -1 }, Players: []};
this.TeamNameNext = function() {
//Code removed
alert("Made it to the submit function!")
};
}
]);
the attribute ng-required requires a value. Don't get confused with HTML5 attribute required that doesn't require a value.
ng-required="true"
Because "Team.Division" is not undefined in your controller code.
If you could use the code below, you will get what you extected.
this.Team = { Name: "", ResumeKey: null, Division: undefined, Players: []};
You can use null or "" instead of undefined.

jQuery hide validation errors on dropdown change

I have a form that shows additional fields based on what the selected option is.
When the form is validated (with error), an error message appears under the additional field that has been shown. That's the expected behaviour.
If I then select a different option, the old option input hides (expected) but the old validation error message remains.
How can I hide the validation error message?
Form code:
<div class="row">
<section class="col col-12">
<label class="label">Type</label>
<label class="select">
<select id="type" name="type">
<option value="" selected>Select a cancelation type</option>
<option value="c1">Cancel and keep all payments</option>
<option value="c2">Cancel and issue deposit refund</option>
<option value="c3">Cancel and issue partial refund</option>
<option value="c4">Cancel and issue full refund</option>
<option value="c5">Cancel and add aditional charges</option>
</select>
<i></i>
</label>
</section>
</div>
<div class="ammount">
<div class="row">
<section class="col col-12">
<label id="ammountt" class="label" style="display:none;">Refund ammount</label>
<label class="input" id="ammountl" style="display:none;>
<i class="icon-prepend fa fa-gbp"></i>
<input class="" id="ammount" type="text" pattern="\d+(\.\d{2})?" placeholder="" name="ammount" value="" >
</label>
<label id="aditionalt" class="label" style="display:none;">Aditional charge ammount</label>
<label class="input" id="aditionall" style="display:none;>
<i class="icon-prepend fa fa-gbp"></i>
<input class="" id="aditional" type="text" pattern="\d+(\.\d{2})?" placeholder="" name="aditional" value="" ></label>
</section>
</div>
JS:
$(document).ready(function() {
$("#type").change(function () {
var choice = jQuery(this).val();
if ($(this).val() == 'c3') {
$('#ammountt').show();
$('#ammountl').show();
} else {
$('#ammountt').hide();
$('#ammountl').hide();
}
if ($(this).val() == 'c5') {
$('#aditionalt').show();
$('#aditionall').show();
} else {
$('#aditionalt').hide();
$('#aditionall').hide();
}
});
var $CancelBookingForm = $("#cancel-booking-form").validate({
// Rules for form validation
rules : {
name : {
required : true
},
ammount : {
required: true
},
aditional : {
required: true
},
},
// Messages for form validation
messages : {
name : {
required : 'Please select an upsell from the drop down.'
},
ammount : {
required: 'Please enter a refund ammount.'
},
aditional : {
required: 'Please enter an aditional charge ammount.'
},
},
// Do not change code below
errorPlacement : function(error, element) {
error.insertAfter(element.parent());
}
});
})
You need to find the invalid class and then remove it
$("#type").change(function () {
var choice = jQuery(this).val();
//if you just want to remove them all
$(".input em.invalid").remove();
if ($(this).val() == 'c3') {
$('#ammountt,#ammountl').show();
} else {
$('#ammountt,#ammountl').hide();
$('#ammountt,#ammount1').siblings("em.invalid").remove();
}
if ($(this).val() == 'c5') {
$('#aditionalt,#aditionall').show();
} else {
$('#aditionalt,#aditionall').hide();
$('#aditionalt,#aditionall').siblings("em.invalid").remove();
}
});

Categories