HTML5 validation with vue.js multi form - javascript

I have a vue.js form with multiple form steps that needs html5 validation simplified it looks like this:
<template>
<div>
<div v-if="activeForm === 1">
<h2>
How much does {{ form.name }} weight?
</h2>
<text-input
v-model="form.weight"
name="weight"
:errors="form.errors"
type="number"
placeholder="For example: 20 kg"
required>
</text-input>
</div>
<div v-if="activeForm === 2">
<h2>
Search here
</h2>
<select-search></select-search>
</div>
<button v-if="activeForm > 1"
#click="previousForm()">
Previous
</button>
<button #click="nextForm">
Finish
</button>
<div>
</template>
<script>
export default {
data() {
return {
activeForm: 1,
totalForm: 6
}
},
methods: {
previousForm() {
if (this.activeForm > 1) {
this.activeForm--;
}
},
nextForm() {
if (this.activeForm < 6) {
this.activeForm++;
}
}
}
}
</script>
Right now obviously the HTML5 validation is not working. But how could I validate it for every form step any ideas (I want to submit the form with 1 ajax call)?

To use HTML validation you need to set the type of your input tags but that will not be enough because right now the specification only covers some inputs types like: date, email, number, (for number you can set a range with Min and Max). We would need to check your text-input component to see why is not working the HTML validation.
If you only need to verify that each input was filled by the user you can add the required attribute to those elements.

Related

How to cut short multiple if else statements in Javascript

I recently came across a situation where I was working on a huge form with atleast 60 fields and I wanted that form to only submit if all fields were filled and if not, I wanted to show a custom message (Sweetalert) for every field not filled.
For example, If first name was left empty, show the message "Please enter your first name", If country of residence was not selected, show them the message that "Please select your country of residence" so on and so forth.
While I was writing tons of if and else statements to match every field using document.getElementById(), this thought of not doing things right came into my mind. I tried searching the web for this but was unable to find a suitable way of doing such things. Can anyone suggest me a better way rather then writing if else statements of 100 lines ?
By adding a specific class to your form controls you'd be able to retrieve them and iterate through them in order to check which ones are not filled.
Let's say this is your form:
<form id="myForm" name="myForm" novalidate>
<div>
<label for="control_1">Label_1:</label>
<input type="text" id="control_1" name="control_1" class="control" />
</div>
<div>
<label for="control_2">Label_2:</label>
<input type="text" id="control_2" name="control_2" class="control" />
</div>
<div>
<label for="control_3">Label_3:</label>
<input type="text" id="control_3" name="control_3" class="control" />
</div>
<div>
<label for="control_4">Label_4:</label>
<select id="control_4" name="control_4" class="control">
<option value="option_1">Option 1</option>
<option value="option_2">Option 2</option>
<option value="option_3">Option 3</option>
</select>
</div>
<div>
<input type="submit" value="Submit!" />
</div>
</form>
Then you can use the .control class to retrieve all controls and check them:
function onSubmit(e) {
e.preventDefault();
const controls = document
.getElementById("myForm")
.querySelectorAll(".control");
controls.forEach(control => {
if (!isControlFilled(control)) {
console.log(control.id);
// Do whatever you want with control's id
}
});
}
// This is just for illustrative purposes
// Should be adapted to cover all control types
function isControlFilled(control) {
return control.value ? true : false;
}

Vuejs get form data from array

I have a form which is showing multiple input based on database data and I need to get each input value when I submit my form.
Code
<form ref="form" :model="form">
<div class="row">
<div
class="col-md-6"
v-for="(field, index) in fields"
:key="index"
>
<input
class="form-control"
v-model="form.field"
:placeholder="field.title"
/>
</div>
</div>
<vs-button
class="mt-3"
#click="onSubmit"
native-type="submit"
gradient
>
Generate
</vs-button>
</form>
data() {
return {
fields: [],
form: {
field: [],
},
};
},
Issue
My issue is that currently when I fill 1 input others get the same value, I need to fill each input individually.
Screenshots
Any idea?
You're using your v-model pointing to form.field, try to use v-model="form.field[index]"

How can I get a input required with vuejs

I have my chat and I dont want people to send empty message so I would like that my input become required. Thanks for your help.
I tried to put "required='required'" in the input line, I also tried veeValidate but it broke my chat when I use it, I also tried to put "Required = true" in Props and data but without a good result
This is ChatForm.vue
<template>
<div class="input-group" >
<input id="btn-input" type="text" name="message" class="form-control input-sm" placeholder="Ecrire..." v-model="newMessage" #keyup.enter="sendMessage">
<span class="input-group-btn">
<button class="btn btn-primary btn-sm" id="btn-chat" #click="sendMessage">
&#10003
</button>
</span>
</div>
</template>
<script>
export default {
props: ['user'],
data() {
return {
newMessage: '',
}
},
methods: {
sendMessage() {
this.$emit('messagesent', {
user: this.user,
message: this.newMessage
});
setTimeout(function() {
const messages = document.getElementById('mess_cont');
messages.scrollTop = messages.scrollHeight;
}, 200);
this.newMessage = '';
}
}
}
</script>
And this is my form in the app.blade.php
<div id="app" class="container-chat">
<div class="row">
<div class="col-md-12 col-md-offset-2">
<div class="col-md-12 col-md-offset-2">
<div class="panel-body panel-content" id="mess_cont">
<chat-messages id="mess" :messages="messages" :currentuserid="{{Auth::user()->id}}"></chat-messages>
</div>
<div class="panel-footer">
<chat-form
v-on:messagesent="addMessage"
:user="{{ Auth::user() }}"
></chat-form>
</div>
</div>
</div>
</div>
</div>
Try to change your ChatForm.vue like this:
<template>
<form #submit.prevent="sendMessage">
<div class="input-group" >
<input id="btn-input" type="text" name="message" class="form-control input-sm" placeholder="Ecrire..." v-model="newMessage" required>
<span class="input-group-btn">
<button class="btn btn-primary btn-sm" type="submit" id="btn-chat">
&#10003
</button>
</span>
</div>
</template>
You are not treating the input in the correct way, the input which is required needs to be inside a form and the required keyword will prevent the form submission if the input field is empty.
There are a few things I would do differently.
1/ Wrap your chat form in a tag, and execute the sendMessage() method on submit. This will give your users a nicer experience, as they can just to submit the message.
2/ Convert the button into a submit button so it triggers the form.submit event.
3/ You can easily disable the button by checking whether newMessage has contents. I don't think you need vee validate or anything else to achieve this; for something as simple as a chat form, your user doesn't need much more feedback than seeing a disabled button to realise (s)he needs to write something first.
4/ in the addMessage method you can just check the contents of newMessage and not do anything when it's empty. This is perfectly fine because you already hinted the user by disabling the button too.
I think this is a subtle way where you guide your user, but don't overdo it.
Please add name attributes to all of your form elements. Some of the element in my form had name attribute and some didn't. Element which had name attributes worked correctly but the one's which didn't had name failed.

Why is my boolean always true when passing it as value to a radio component?

so I am learning vue and have spent some time going through the documents and haven't seen the answer that solves my question. A lot of this is due to the nomenclature between using the CLI(which I am) and not.
I am trying to make it so that when one radio button is clicked it shows a div and when the other one is clicked it shows the other. Here is what I have.
Template:
<div id="daySelection">
<div class="o-m-day">
<div id="oneDay">
<p>One day?</p><input v-model="selected" type="radio" name="oneDay" id="" class="r-button" value="true">
</div>
<div id="multipleDays">
<p>Multiple days?</p> <input v-model="selected" type="radio" name="multDays" id="" class="r-button" value="false">
</div>
</div>
<!-- the div where the conditional render will be rendered -->
<div>
<!-- multiple days -->
<div v-show="selected" id="ta-multDays">
<textarea rows="10" cols="80" name="multDays" type="text" />
</div>
<!-- one day -->
<div v-show="!selected" id="i-oneDay">
<input type="text" name="r-oneDay">
</div>
</div>
</div>
Here is the script:
export default {
name: 'CreateTournamentForm',
data: function(e) {
return {
selected: Boolean,
}
},
}
above I was getting an error in the console that was saying that data needs to be a function that returns a new instance. I see many people and examples using vue instances differently where it is:
const app = new Vue({
el: '#app',
data: {
selected: true,
}
});
However whenever trying this Vue sends me a warning saying that it needs to be a function.
[Vue warn]: The "data" option should be a function that returns a per-instance value in component definitions.
I am also aware that v-show toggles the display so I have tried both setting the display of the divs to:
display: none;
as well as not.
The problem is that the value of selected is a string, whereas you expect it to be a boolean.
The following watcher:
watch: {
selected(newValue) {
console.log("selected changed to", newValue, "which is a", typeof newValue);
}
}
Will tell you this:
selected changed to true which is a string
selected changed to false which is a string
The reason is that you give the fields value a string instead of a boolean. To fix this, instead of writing value="true", write :value="true".
You can play with a live example here.
There are two problems as far as I can see here:
In a component, the data key must be a function and the value for the selected key in the object returned by the data function must be an actual boolean value true or false (which will be initial value)
export default {
name: 'CreateTournamentForm',
data: function(e) {
return {
selected: true,
}
},
}
By default, v-model values are treated as strings so your true and false values are actually the strings "true" and "false" which are both truthy. Changing your template code to the below (or alternatively using a number or string value instead) should fix it
<div v-show="selected === 'true'" id="ta-multDays">
<textarea rows="10" cols="80" name="multDays" type="text" />
</div>
I solved it by changing it from a 'v-show' to 'v-if'
<div>
<p>One day?</p>
<input
v-model="selected"
type="radio"
name="oneDay"
id="oneDay"
class="r-button"
value="onlyOneDay" />
</div>
<div id="multipleDays">
<p>Multiple days?</p>
<input
v-model="selected"
type="radio"
name="multDays"
id="multDays"
class="r-button"
value="multipleDays" />
</div>
then the div to be shown as follows:
<div v-if="selected === 'multipleDays'" id="ta-multDays">
<textarea rows="10" cols="80" name="" type="text" />
</div>
<div v-if="selected === 'onlyOneDay'" id="i-oneDay">
<input type="text" name="">
</div>

Form validation summary in AngularJS with custom message per field

I'm trying to render a validation summary on a page using AngularJS. Here's what I have so far:
<div ng-app>
<div ng-controller="ctrl">
<form name="userForm">
<fieldset>
<legend>User Info</legend>
<p><label>Name: <input type="text" required ng-maxlength="15" name="name" ng-model="name" /></label></p>
<p><label>Age: <input type="number" required name="age" ng-model="age" /></label></p>
<p><label>Favorite Color: <input type="text" required name="favColor" ng-model="favColor" /></label></p>
<p><input type="button" value="Submit" ng-click="submitForm()" /></p>
</fieldset>
</form>
<div id="validationSummary" ng-show="hasValidationErrors()">
<ul>
<li ng-repeat="error in validationErrors">{{ error }}</li>
</ul>
</div>
</div>
</div>
In my controller, I'm creating an array with all of the errors.
function ctrl($scope) {
$scope.hasValidationErrors = function () {
return $scope.validationErrors && $scope.validationErrors.length > 0;
};
$scope.submitForm = function() {
$scope.validationErrors = [];
for (var property in $scope.userForm) {
if ($scope.userForm.hasOwnProperty(property) && $scope.userForm[property].$invalid) {
$scope.validationErrors.push($scope.userForm[property].$name);
}
}
}
}
The thing I can't figure out is: how can I get more than just the name of each field that is invalid? I've noticed that there is also an $error property on each field. Outputting this instead of $name gives me the following:
{"required":true,"maxlength":false}
{"required":true,"number":false}
{"required":true}
So I can get the field name, and I can get an object that describes what is wrong with that particular field. How can I define an error message, so that if a field is required it will output "{name} is required"? It seems like this could be a data- attribute on the input element itself, although I don't know how I would access that attribute.
Of course, it's also possible that I'm making things entirely too difficult on myself. Is there a better way to approach this while staying in the "AngularJS" world?
Here's a link to the jsFiddle I've been working on.
A far easier and cleaner way is demonstrated here
Simply put (where form1 is your form name attribute):
<ul>
<li ng-repeat="(key, errors) in form1.$error track by $index"> <strong>{{ key }}</strong> errors
<ul>
<li ng-repeat="e in errors">{{ e.$name }} has an error: <strong>{{ key }}</strong>.</li>
</ul>
</li>
</ul>
A totally dynamic validation summary based on AngularJS 1.5.7 with ngMessages using field names that the user recognizes
A template with error messages:
<script type="text/ng-template" id="error-messages">
<span ng-message="required">This field is required.</span>
<span ng-message="email">Please enter a valid email.</span>
</script>
Display of the error summary (here for a form named "candidateForm"):
<div data-ng-if="candidateForm.$submitted && candidateForm.$invalid">
Please correct these fields and then try to send again:
<ul>
<li data-ng-repeat="field in candidateForm" data-ng-if="candidateForm[field.$name].$invalid">
<div>
{{ getValFieldName(field) }}
<span data-ng-messages="candidateForm[field.$name].$error" role="alert">
<span data-ng-messages-include="error-messages"></span>
</span>
</div>
</li>
</ul>
</div>
A helper function to get the name of the label associated with the input field (instead of displaying input field names or "internal ID codes" to users):
$scope.getValFieldName = function (field) {
return $("label[for=" + field.$name + "]").text(); // to get label associated with input field
// return $("#" + field.$name).attr("placeholder"); // to get placeholder of input field
};
You can reuse this set of standard error messages on multiple forms, ngMessages ensure only one error displayed per field, and looks like the fields are listed in the order they appear in the HTML.
Should probably be made into a directive instead of the jQuery-style helper function, and might even want to add a click-handler on each error message to scroll to the input field with the error. Maybe another will run with that idea?
Use below line to get values of every text box
var value = $scope.userForm[property].$name;
var vl =$('*[name="' + value + '"]').data('required-message')
$scope.validationErrors.push(vl);

Categories

Resources