For a day I fiddled around with getting form validation to work with the new ng-messages on generated fields with no success. I read in the angular documentation and on a github issue ng-repeat is not supported by ng-messages because it does not interpolate its fields. So, I decided to go the jquery route build the dom myself compile it and replace the element with my generated code, which after of course I don't get to work either. So some help would be much appreciated. Here's my html:
....
<app-field ng-repeat="field in fields" field="field" ng-model="selected[field.name]" form="form" type="input"></app-field>
<fieldset class="form-group">
<label for="field1s">static field 1</label>
<input name="field1s" type="text" ng-model="selected['field1']" class="form-control" required="">
<ng-messages for="form['field1'].$error">
<ng-message when="required">Is required</ng-message>
</ng-messages>
<label for="field2s">static field 2</label>
<input name="field2s" type="text" ng-model="selected.field2" class="form-control" required="" ng-maxlength="10" ng-minlength="2">
<ng-messages for="form.field2s.$error">
<ng-message when="required">Is required</ng-message>
<ng-message when="maxlength">Max length 10</ng-message>
<ng-message when="minlength">MIn length 2</ng-message>
</ng-messages>
</fieldset>
I've added some statically typed fields too so i could monitor the data source and the form. The directive app-field generates the dom which is cooked up with some jquery soup but it turned out to work quite well. I mean the generated dom looks like it is supposed to but ... but compiled it does not agree with angular, angular doesn't throw any errors but it just refuses to bind the dynamic fields to the form correctly. It updates the underlying object but does not do form validation let alone trigger the ng-messages and according to this post: Angularjs: Form validation on input field generated by directive I see no reason why it shouldn't. Here's a plunk: http://plnkr.co/edit/ZzC4jS9M9Ev5i6gxUVxB?p=preview
Any help is appreciated...
You need to have ng-form element inside every ng-repeat for dynamic field validation to work. I have fixed the problem in below plunker for field 1.
http://plnkr.co/edit/xQTLDa3TptXky8KIcSsh?p=preview
<form name="form">
<ng-form name="myform">
<input name="field1s" type="text" ng-model="selected['field1']" class="form-control" ng-required="true" ng-pattern="/^[0-9a-zA-Z]+$/">
<ng-messages for="form.myform['field1s'].$error">
<ng-message when="required">Is required</ng-message>
<ng-message when="pattern">alpha error </ng-message>
</ng-messages>
</ng-form>
</form>
I have commented out the custom JQuery code you had written. Since it is no longer required.
Please refer to this - https://github.com/angular/angular.js/issues/10165 for more info. on this problem.
Related
I'm working on a form which is supporting multiple languages by using data-i18n, and I want to use jquery to add the message below the form if the input of the form cannot be validated.
(The multi-language message content of all sites is included in the local json files: the form page is named as formPage and the input section is named as inputDescription)
But the message content doesn't show up although I'm using $(jquery).attr(), can anyone help to check if I do anything wrong or what should I do to make it works?
Thanks in advance!
$(".msg").attr("data-i18n", "formPage.inputDescription" );
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form>
<input type="number" step=any class="form-control" min="5000" max="1000000" value="">
<small data-i18n="" class="form-text msg"></small>
</form>
Finally got the answer, post and share here. It's necessary to call localize $(jquery).localize() again after the attribution $(jquery).attr(), although localize has been called in the html file.
In Angular 4+, I've following template driven form:
<form #addForm="ngForm" (ngSubmit)="onFormSubmit($event, addForm)" >
<div class="form-group">
<label for="item_name">Item Name</label>
<input id="item_name" name="item_name" [(ngModel)]="itemName"
#item_name="ngModel" autofocus class="form-control"
required minlength="4" maxlength="20"
aria-describedby="itemNameHelpBlock">
<small *ngIf="(item_name.invalid && item_name.touched)" id="itemNameHelpBlock" class="form-text text-error" >
Value must be at least 4 characters and must not exceed 20 characters
</small>
</div>
<div class="form-group">
<label for="item_type">Item Type</label>
<input id="item_type" name="item_type" [(ngModel)]="itemType"
#item_type="ngModel" class="form-control" required minlength="2"
maxlength="20" aria-describedby="itemTypeHelpBlock">
<small *ngIf="(item_type.invalid && item_type.touched)" id="itemTypeHelpBlock" class="form-text text-error" >
Value must be at least 2 characters and must not exceed 20 characters
</small>
</div>
<button class="btn btn-output-primary btn-lg" [disabled]="!addForm.form.valid">Add</button>
</form>
In the component section, I want to access the form field (ie item_name, item_type) as ElementRef so that I can access their corresponding DOM element through the nativeElement method of ElementRef class.
I've tried with #ViewChild but, it returns NgModel class object:
#ViewChild('item_name') item_name: ElementRef;
ngAfterViewInit() {
console.log(this.item_name); // it returns NgModel class object
}
But, I need to access the DOM HTMLElement of #item_name form field so that I can reset document focus to #item_name input field after every form submission. Now, I don't know how I can do it without directly accessing the DOM and I don't wanna directly access the DOM via DOM api.
I would be glad if I get some help here.
I would simply add read option to ViewChild query:
#ViewChild('item_name', { read: ElementRef }) item_name: ElementRef;
^^^^^^^^^^^^^^^
Stackblitz Example
See also
How to get reference of the component associated with ElementRef in Angular 2
Just to give a use case, you can point #item_name to ngModel to access some attributes of the model itself, for example if it's currently considered valid.
<input id="item_name" name="item_name" [(ngModel)]="itemName" #item_name="ngModel"
autofocus class="form-control">
<!-- here's where you can access the attributes if it's pointed to ngModel-->
<small [hidden]="password.valid">
The item name is not valid
</small>
If you don't need this rather fancy stuff, you can just remove it, as Andriy proposed. Then it's working out of the box with no further changes.
If you need to keep it however, you can give your input field an additional reference which you can use to get the ElementRef.
<input id="item_name" name="item_name" [(ngModel)]="itemName"
#item_name="ngModel" #itemNameField autofocus class="form-control">
You just have to reference the one that is not pointing to ngModel.
#ViewChild('itemNameField') itemNameField: ElementRef;
Angular does not complain about having multiple references on one field (as far as I tested it)
In your HTML, do not point template reference #item_name to ngModel, just leave it empty like:
<div class="form-group">
<label for="item_name">Item Name</label>
<input id="item_name"
class="form-control"
name="item_name"
[(ngModel)]="itemName"
#item_name
autofocus>
</div>
then, you can access DOM element using #ViewChild decorator (as you did) like:
this.item_name.nativeElement,
I noticed, you have a typo in your submit button: opening '[' is missing just before disabled property.
Plunker: https://plnkr.co/edit/XHqOiEBmuFrA3slZSlrD?p=preview
I am trying to validate an auto-generated form (via AngularJS v1.3) which inputs' names are in format:
form_name[field_name]
The very basic example would be:
<form name="morgageCalculator">
<input type="text" class="form-control"
name="morgageCalculator[homeValue]" value="0"
data-ng-model="data.homeValue" required="required"/>
</form>
As you can see, the input name is morgageCalculator[homeValue]. Now I would like to add an error message below it:
<div class="error"
data-ng-show="!morgageCalculator.morgageCalculator[homeValue].$pristine && morgageCalculator.morgageCalculator[homeValue].$invalid">
Please enter a number
</div>
For very obvious syntax reasons this expression is not valid:
morgageCalculator.morgageCalculator[homeValue].$pristine
But this one also does not work:
morgageCalculator["morgageCalculator[homeValue]"].$pristine
So, the question, is there any sane way of accessing those fields? I wouldn't mind moving the validation to some controller function, but I was faced with same issue of inability to access field object.
Any help/hint would be greatly appreciated.
With help of #dfsq from comment section, I was able to find the error. Unlike my SO question, my code was missing data-ng-model.
Validation will not fire at all if input was not bound to model....
The correct snippet:
<form name="morgageCalculator">
<input type="text" class="form-control"
name="morgageCalculator[homeValue]" value="0"
data-ng-model="data.homeValue" required="required"/>
<div class="error"
data-ng-show="!morgageCalculator['morgageCalculator[homeValue]'].$pristine && morgageCalculator['morgageCalculator[homeValue]'].$invalid">
Please enter a number
</div>
</form>
I am dealing with two versions of a page. The first one has a search input field as part of a form, and I can get that value no problem with
document.getElementsByClassName('search-input')[0].value
i.e. this will update as it's being typed. On the other version of the page (which I have no control over) the input field is not part of a form, and now the above code doesn't work (the class of the input field is still "search input").
Here is the html where it's working fine:
<form action="search-landing.aspx" method="GET">
<input class="search-input" autofocus="autofocus" placeholder="City, State or Zip" name="location" required="">
<button id="searchButton" tabindex="0" class="search-btn" type="submit">Search</button>
</form>
And here is the code where it's not
<div class="search-box">
<input type="text" class="search-input" placeholder="City, State or Zip">
</div>
Does anyone know why I'm having this issue? Is there a way around it (i.e. to grab a value from an input field that is NOT part of a form)?
Thanks
Rooster correctly pointed out that I may have more than 1 input field of class "search-input". There were two identical fields, one hidden so document.getElementsByClassName('search-input')[1].value was the answer in this case
Say I have the following form:
<form>
<input type="text" required ng-model='myValue' ng-maxlength='5'></input>
{{myValue}}
{{myValue.length}}
</form>
When the length of the text in the input exceeds the maxlength, the model becomes empty. Is there any way to prevent this behaviour while applying this validation, without rolling a custom form level validator?
at first, input element no end mark(</input), the correct like this:<input name="test" type="text"/>
you can handle form.test.$error.maxlength to deal something, example code:
<form name="form">
<input name="name" type="text" required ng-model='myValue' ng-maxlength='5'/>
<div>value:{{myValue}}</div>
<div>length:{{myValue.length}}</div>
<div>validate:{{form.name.$error.maxlength}}</div>
</form>
According your means, the invalid value lead to null model, I think this is no problem.