I have following Angular 2 form:
<register>
<form [ngFormModel] = "registrationForm">
<div class = "form-group">
<label class = "control-label" for="email">Email</label>
<input class = "form-control" type="email" id="email" ngControl="email" #email="ngForm">
</div>
<div *ngIf = "email.touched && email.errors">
<div *ngIf = "!email.errors.required && email.errors.underscoreNotFound" class = "alert alert-danger">
<span>Underscore is required</span>
</div>
<div *ngIf = "email.errors.required" class = "alert alert-danger">
<span>Email is required</span>
</div>
</div>
<div class = "form-group">
<label class = "control-label" for="password">Password</label>
<input class = "form-control" type="password" id="password" ngControl="password" #password="ngForm">
</div>
<div *ngIf = "password.touched && password.errors">
<div *ngIf = "password.errors.minLength && !password.errors.required" class = "alert alert-danger">
<span>Password should contain 6 characters</span>
</div>
<div *ngIf = "password.errors.required" class = "alert alert-danger">
<span>Password is required</span>
</div>
</div>
</form>
</register>
This is my Component where I have implemented validators:
import {Component} from '#angular/core';
import {Control, ControlGroup, FormBuilder, Validators} from '#angular/common';
import {CustomValidator} from './CustomValidator';
#Component({
selector: 'register',
templateUrl: './app/authentication/register_validation/register.html',
})
export class RegisterComponent{
registrationForm: ControlGroup;
constructor(formBuilder:FormBuilder)
{
this.registrationForm = formBuilder.group({
email: ['',Validators.compose([Validators.required, CustomValidator.underscore])],
password: ['',Validators.compose([Validators.required,Validators.minLength(6)])]
});
}
}
In this form, email field is working fine for both validators i.e. when I do not type anything , it gives "Email is required" message, when I start typing something, it gives "Underscore is required" message and when I type "_" all error messages disappears. However, when I try to apply such 2 validators on password field, it's not working. When I do not type password it gives message as "Password is required". But when I type something less than 6 characters, minLength message doesn't appear at all. What is wrong in this code?
The error key is minlength and not minLength:
<div *ngIf = "password.hasError('minlength') && !password.hasError('required')" class = "alert alert-danger">
<span>Password should contain 6 characters</span>
</div>
This really caught me out as well as I matched the key in my markup to what I had in code which is incorrect.
Sample Code
password1: ['', [Validators.required, Validators.minLength(8)]],
Sample Markup
*ngIf="registrationRequest.get('password1').hasError('minlength')"
Note in the code it's minlength entirely in lower case.
I was facing the same issue but after so many research I got a solution with this:
Use minlength instead of minLength
Here is the example:
<div *ngIf = "password.errors.minlength && !password.errors.required" class = "alert alert-danger">
<span>Password should contain 6 characters</span>
</div>
Instead of:
<div *ngIf = "password.errors.minLength && !password.errors.required" class = "alert alert-danger">
<span>Password should contain 6 characters</span>
</div>
I had the same problem where I wanted to validate a number field that contained the year, so I used Validators.maxLength(4) to make sure someone does not accidently type 5 numbers for a year. Turns out when you set the input type to number:
<input type="number" formControlName='year'>
then maxLength does not "work" anymore. Which actually makes sense if you think about it for half a second.
So I changed my date input to:
year: [null, [Validators.required, Validators.min(1990), Validators.max(2050)]],
Which is the right approach when working with a number field.
This worked for me for password validation.
<input type="password" class="form-control" name="password" placeholder="Password" [(ngModel)]="register.password" #password="ngModel" minlength="6" required>
field: ['', Validators.compose([Validators.required, Validators.minLength(8)])]
This only works with multiple validators.
<div *ngIf = "password.errors.minLength && !password.errors.required" class = "alert alert-danger">
<span>Password should contain 6 characters</span>
</div>
minLength must be lowercase minlength
This might not really be related to the question asked here. But in my case, it was happening due to the input type defined in the HTML.
Validator was initiated like this in my case:
this.OTPForm = this.fb.group({
otp: [null, [Validators.required, Validators.minLength(6), Validators.maxLength(6)]]
})
Validators.minLength and Validators.maxLength won't work for below as the input type is number/non-string hence the length cannot be really checked here.
<input type="number" nz-input formControlName="otp" placeholder="Enter OTP" />
While for below where the input type is stated as "text", the comparison can be done. And so the Validators.minLength and Validators.maxLength worked here.
<input type="text" nz-input formControlName="otp" placeholder="Enter OTP" />
Related
is there any possibility to get error message without ts file, I used this i could validate my input
<form #form="ngForm" (ngSubmit)="logForm(form)" novalidate>
<ion-item>
<ion-label style="color: black;" fixed>User Name</ion-label>
<ion-input type="text" name="username" placeholder="valid user name" [(ngModel)]="username" pattern="[A-Za-z0-9]{3}" required></ion-input>
</ion-item>
<ion-item>
<ion-label style="color: black;" fixed>Email Id</ion-label>
<ion-input type="email" name="email" placeholder="Examples#gmail.com" [(ngModel)]="email"
pattern="[a-z0-9._%+-]+#[a-z0-9.-]+\.[a-z]{2,3}$" required></ion-input>
</ion-item>
<button ion-button type="submit" value="Submit" block>Login</button>
</form>
<p *ngIf=username.valid> The following problems have been found with the username: </p>
what i need is to display error message if the input is not valid, and i should not submit empty form
import { Component } from '#angular/core';
import { NavController, NavParams } from 'ionic-angular';
#Component({
selector: 'page-login',
templateUrl: 'login.html'
})
export class LoginPage {
constructor(public navCtrl: NavController
) {}
ionViewDidLoad() {
console.log('ionViewDidLoad LoginPage');
}
logForm(form) {
console.log(form.value)
if(form.valid) {
console.log(form.value);
/*here i get user entered values as object*/
}
}
You need to add to your form attributes something that will identify what fields we're going to validate, so for username, let's say this:
#userName="ngModel"
You can loose the [(ngModel)] in this case.
and then your validation:
<div *ngIf="userName.errors?.required && userName.touched">
Name is required
</div>
<div *ngIf="userName.errors?.pattern && userName.touched">
Not valid
</div>
So you just use the different validations you have set for input and check whether they match the validations, e.g required, pattern with the prefix of the name of the form control and errors?
So here's how your username validation would look like:
<ion-item>
<ion-label style="color: black;" fixed>User Name</ion-label>
<ion-input type="text" name="username" ngModel #userName="ngModel"
required pattern="[A-Za-z0-9]{3}"></ion-input>
</ion-item>
<div *ngIf="userName.errors?.required && userName.touched">
Name is required
</div>
<div *ngIf="userName.errors?.pattern && userName.touched">
Not valid
</div>
Here's a plunker.
I am currently using hibernate-distribution-3.6.4.Final. New to Hibernate Validator.
Problem:
How should I retrieve error messages I got from adding annotations to databean/formbean? I know in Spring that everyone seems to use messages.properties file from the classpath?
But how about pure hibernate 3, is there any file like that or what should i do instead? (Didn't find good answers online...)
Hope this will help. Source is : Mastering Spring MVC
You will need to add a few more things for validation to work. First, the controller needs to say that it wants a valid model on form submission. Adding the javax.validation.Valid as wel as
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
annotation to the parameter representing the form does just that:
#RequestMapping(value = "/profile", method = RequestMethod.POST)
public String saveProfile(#Valid ProfileForm profileForm,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return "profile/profilePage";
}
System.out.println("save ok" + profileForm);
return "redirect:/profile";
}
Note that you do not redirect the user if the form contains any errors. This will allow you to display them on the same web page. Speaking of which, you need to add a place on the web page where those errors will be displayed.
Add these lines in profilePage.html:
<form th:action="#{/profile}" th:object="${profileForm}"
....">
<div class="row">
<div class="input-field col s6">
<input th:field="${profileForm.twitterHandle}"
id="twitterHandle" type="text" th:errorclass="invalid"/>
<label for="twitterHandle">Twitter handle</label>
<div th:errors="*{twitterHandle}" class="redtext">
Error</div>
</div>
<div class="input-field col s6">
<input th:field="${profileForm.email}" id="email"
type="text" th:errorclass="invalid"/>
<label for="email">Email</label>
<div th:errors="*{email}" class="red-text">Error</div>
</div>
</div>
<div class="row">
<div class="input-field col s6">
<input th:field="${profileForm.birthDate}"
id="birthDate" type="text" th:errorclass="invalid" th:placeholder="${
dateFormat}"/>
<label for="birthDate">Birth Date</label>
<div th:errors="*{birthDate}" class="red-text">Error</
div>
</div>
</div>
<div class="row s12">
<button class="btn indigo waves-effect waves-light"
type="submit" name="save">Submit
<i class="mdi-content-send right"></i>
</button>
</div>
</form>
Yes Indeed, Spring Boot takes care of creating a message source bean for us.
The default location for this message source is in
src/main/resources/messages.
properties.
Create such a bundle, and add the following text:
Size.profileForm.twitterHandle=Please type in your twitter user name
Email.profileForm.email=Please specify a valid email address
NotEmpty.profileForm.email=Please specify your email address
PastLocalDate.profileForm.birthDate=Please specify a real birth date
NotNull.profileForm.birthDate=Please specify your birth date
typeMismatch.birthDate = Invalid birth date format
.
I am using validatious-custom-0.9.1.js framework in my project and I am trying to validate required fields for radio buttons. But it is not validating the radio buttons in IE8. I am getting the following error in console
Message: 'tagName' is null or not an object
Line: 7
Char: 9921
Code: 0
URI: http://validatious.org/design/js/validatious.0.9.1.min.js?1256063644
HTML code used.
<div>
<label for="_button_880">Radio List
<div>
<p>some text</p>
</div>
</label>
<div>
<ul>
<li>
<div>
<div>
<input type="radio" name="radio1" id="radio1" value="Radio1" class="required" title="Required."/>
<label for="radio1">Radio1</label>
</div>
</div>
</div>
</div>
JS where it is failing - First 2 are the examples that are given in the framework file. So you will get to know how it is implemented
/* A radio button field is assumed to be either a list - ordered or unordered -
with some element in front that acts as a label. This may be any element.
If it is not in a list (ie the element does not have "li" parent elements),
the label is assumed to be the element before the first input element.
Example1 (list approach):
<h2>Favourite food:</h2>
<ul>
<li>
<input type="radio" name="food" value="hamburger" id="food_hamburger" />
<label for="food_hamburger">Haburger</label>
</li>
<li>
<input type="radio" name="food" value="pizza" id="food_pizza" />
<label for="food_pizza">Pizza</label>
</li>
</ul>
getLabel() will in this case return the h2 element.
Example2 (no list).
<label class="groupLabel">Favourite food:</label>
<input type="radio" name="food" value="hamburger" id="food_hamburger" />
<label for="food_hamburger">Hamburger</label>
<input type="radio" name="food" value="pizza" id="food_pizza" />
<label for="food_pizza">Pizza</label>
getLabel() will in this case return the first label element
*/
Actual code
getLabel: function() {
var parent = this.__elements[0].parentNode;
//alert(parent1.nodeName); --- Gives 'nodeName' is null or not an object IN Ie8
if (parent1.tagName.toLowerCase() === 'li') { ---Gives 'tagName' is null or not an object
return v2.$(parent1.parentNode).previous();
}
var element = v2.$(this.__elements[0]).previous();
return element || this.base();
}
Required field validation in the js file
v.reg('required', function(field, value, params) {
return !v2.empty(value) && !(typeof value.length !== 'undefined' && value.length == 0);
}, null, null, 'not-empty', false);
It works fine in firefox, IE7 and IE9. But in Ie8, I get message tagName is null or not an object.
Can somebody please help me in this. If this is solved, then this framework will be very useful to avoid all the hardships in validating.
Thanks in advance..
I'd like to reproduce this html sequence of radio buttons with simple_form in order to make simple_form work with http://semantic-ui.com/ syntax :
<div class="grouped inline fields">
<div class="field">
<div class="ui radio checkbox">
<input type="radio" name="fruit" checked="">
<label>Apples</label>
</div>
</div>
<div class="field">
<div class="ui radio checkbox">
<input type="radio" name="fruit">
<label>Oranges</label>
</div>
</div>
<div class="field">
<div class="ui radio checkbox">
<input type="radio" name="fruit">
<label>Pears</label>
</div>
</div>
<div class="field">
<div class="ui radio checkbox">
<input type="radio" name="fruit">
<label>Grapefruit</label>
</div>
</div>
</div>
So I prepared a custom wrapper :
config.wrappers :semantic_radios, tag: 'div', class: "grouped fields", error_class: 'error', hint_class: 'with_hint' do |b|
b.use :html5
b.use :label
b.use :input
end
Set some options :
config.item_wrapper_tag = :div
config.item_wrapper_class = 'ui radio checkbox'
And call this code in my form :
=f.input :child_care_type, collection: [["option 1", 1],["option 2", 2]], as: :radio_buttons, wrapper: :semantic_radios
I don't know where to customize the div.field encapsulation :
<div class="field">
<div class="ui radio checkbox">
<input type="radio" name="fruit" checked="">
<label>Apples</label>
</div>
</div>
My code only render this :
<div class="ui radio checkbox">
<input type="radio" name="fruit" checked="">
<label>Apples</label>
</div>
Can you help me ? I didn't find more wrapper's customization for collection :s
Summary:
I had done something similar to this before by creating a custom input that inherits from SimpleForm::Inputs::CollectionRadioButtonsInput and overloading just a few methods. For more on custom input components, see https://github.com/plataformatec/simple_form/wiki/Adding-custom-input-components.
In any case, the code below produces your desired html markup almost exactly using simple_form v2.1.0 and rails v3.2.15.
Code:
# File: app/inputs/semantic_ui_radio_buttons_input.rb
class SemanticUiRadioButtonsInput < SimpleForm::Inputs::CollectionRadioButtonsInput
# Creates a radio button set for use with Semantic UI
def input
label_method, value_method = detect_collection_methods
iopts = {
:checked => 1,
:item_wrapper_tag => 'div',
:item_wrapper_class => 'field',
:collection_wrapper_tag => 'div',
:collection_wrapper_class => 'grouped inline fields'
}
return #builder.send(
"collection_radio_buttons",
attribute_name,
collection,
value_method,
label_method,
iopts,
input_html_options,
&collection_block_for_nested_boolean_style
)
end # method
protected
def build_nested_boolean_style_item_tag(collection_builder)
tag = String.new
tag << '<div class="ui radio checkbox">'.html_safe
tag << collection_builder.radio_button + collection_builder.label
tag << '</div>'.html_safe
return tag.html_safe
end # method
end # class
Then, in your form, just do:
-# File: app/views/<resource>/_form.html.haml
-# Define the collection
- child_care_coll = %w( Infant Toddler Preschool Kindergarten ).map!.with_index(1).to_a
-# Render the radio inputs
= f.input :child_care_type,
:collection => child_care_coll,
:label_method => :first,
:value_method => :last,
:as => :semantic_ui_radio_buttons
Results:
<div class="input semantic_ui_radio_buttons optional childcare_child_care_type">
<label class="semantic_ui_radio_buttons optional control-label">
Child care type
</label>
<div class="grouped inline fields">
<div class="field">
<div class="ui radio checkbox">
<input checked="checked" class="semantic_ui_radio_buttons optional" id="childcare_child_care_type_1" name="childcare[child_care_type]" type="radio" value="1">
<label for="childcare_child_care_type_1">Infant</label>
</div>
</div>
...
<div class="field">
<div class="ui radio checkbox">
<input class="semantic_ui_radio_buttons optional" id="childcare_child_care_type_4" name="childcare[child_care_type]" type="radio" value="4">
<label for="childcare_child_care_type_4">Kindergarten</label>
</div>
</div>
</div>
</div>
I was having trouble with the same problem until I looked through config/initializers/simple_form.rb.
Turns out you can set the option here (line ~51):
# Define the way to render check boxes / radio buttons with labels.
# Defaults to :nested for bootstrap config.
# inline: input + label
# nested: label > input
config.boolean_style = :inline
A bit further down you can also define the default wrapper tag and wrapper tag class for the collection (line ~81):
# You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none.
config.collection_wrapper_tag = :div
# You can define the class to use on all collection wrappers. Defaulting to none.
config.collection_wrapper_class = 'styled-radios'
Hope this helps someone :)
*using gem 'simple_form'
With updated versions 'simple_form', '~> 3.0.2' and Semantic UI 0.19.3, I achieved it with following code.
class SemanticCheckBoxesInput < SimpleForm::Inputs::CollectionCheckBoxesInput
def input
label_method, value_method = detect_collection_methods
options[:collection_wrapper_tag] = 'div'
options[:collection_wrapper_class] = 'grouped inline fields'
#builder.send("collection_check_boxes",
attribute_name, collection, value_method, label_method,
input_options, input_html_options, &collection_block_for_nested_boolean_style
)
end
protected
def item_wrapper_class
"ui checkbox field"
end
end
and in the view
= f.association :branches, as: :semantic_check_boxes
Here is the output:
I got a big XML. A snippet of that XML look like this:
<div class="x-column-inner" id="ext-gen422" style="width: 850px;">
<div id="ext-comp-1206" style="width: 14px;" class=" x-column">
<div tabindex="-1" class="x-form-item x-hide-label" id="ext-gen434">
<label class="x-form-item-label" style="width:100px;" for="ext-comp-1180" id="ext-gen435"></label>
<div style="padding-left:105px" id="x-form-el-ext-comp-1180" class="x-form-element">
<div class="x-form-check-wrap" id="ext-gen436" style="width: 14px; height: 28px;">
<input type="checkbox" name="ext-comp-1180" id="ext-comp-1180" autocomplete="off" class=" x-form-checkbox x-form-field">
<label class="x-form-cb-label" for="ext-comp-1180" id="ext-gen437"> </label>
</div></div> <div class="x-form-clear-left">
</div>
</div>
</div>
<div id="ext-comp-1207" style="width: 150px;" class=" x-column">
<label id="ext-comp-1203" style="width: 140px;">Add to Watchlist</label>
</div>
<div id="ext-comp-1208" style="width: 107px;" class=" x-column">
I need to find 'input' node of checkbox type based on label node having text 'Add to Watchlist'.
As both 'input' and 'label' node lies in different hierarchy, // syntax doesn't seem to work:
//div[label[contains(text(),'Add to Watchlist')]]
will just give parent div of child label.
I tried to start from the topmost node of this snippet
$x("//div[#class='x-column-inner' and //label[contains(text(),'Add to Watchlist')]]")
but that is giving 6 possible matches.
Note: #id attribute can't be used as this is getting assigned dynamically to nodes so next time page loads #id will be different.
I don't want to use position() predicate as that makes XPATH static and xpath may break with any change in position.
You could try something like this, but it looks very greedy... Basically what it does is searching in every axes of the input tags to see if there is an associated label tag. So for each input it searches in its ancestors, descendants and siblings.
There are certainly some smarter solutions.
//input[#type = 'checkbox' and (#id = ancestor::label/#for or #id = descendant::label/#for or #id = following::label/#for or #id = preceding::label/#for)]
However your snippet is not interesting no input tag will be matched, please consider providing a better snippet. It would improve the answers accuracy.
Edit : Here is a (non-tested) way to add the 'Add to Watchlist' constraint.
//input[#type = 'checkbox' and (#id = ancestor::label[. = 'Add to Watchlist']/#for or #id = descendant::label[. = 'Add to Watchlist']/#for or #id = following::label[. = 'Add to Watchlist']/#for or #id = preceding::label[. = 'Add to Watchlist']/#for)]
But once again, those xpath requests are very greedy and your are not guaranteed to match every input element associated to a label for example the following input won't be match in this snippet:
<div>
<div>
<label for="id">Add to Watchlist</label>
</div>
<div>
<input type="checkbox" id="id" />
</div>
<div>
There may be more efficient solutions in one xpath request, but you should consider doing several request.
For example, one request to find every for attribute value of the label elements with the text 'Add to Watchlist' and then doing another request to find the associated input elements.
I should also try to restrict your request to the scope a the underlying form element. Perhaps I will edit with a better request if I find the time.
Edit 2
Here is a working and smarter request
//form//input[#type = 'checkbox' and #id = ancestor::form[1]//label[. = 'Add to Watchlist']/#for]
You can confront it to this snippet
<html>
<form>
<label for="bar">Add to Watchlist</label>
<div>
<div>
<label for="id">Add to Watchlist</label>
</div>
<div>
<input type="checkbox" id="id" />
<input type="checkbox" id="foo" />
<input type="checkbox" id="bar" />
<input type="checkbox" />
<input type="checkbox" id="" />
</div>
</div>
</form>
<label for="foo">Add to Watchlist</label>
</html>
Bust the most important is that you understand how it works and why it is better. Please take the time to think about it.