I'm using ui-router and the view below accesses the controller using the 'Controller As' syntax. I'm adding the 'invalid' class onto the 'shift'-radios container. When form loads you can see both validation required messages (for requestDate and shift). When requestDate and shift are set validation messages disappear. Form's $valid is true. The only problem is that the 'invalid' class on the radio-wrapper div stays.
What am I doing wrong?
<form novalidate ng-submit="_form.$valid && formCtrl.getFormData()" name="_form">
<div class="datepicker-wrapper clearfix">
<datepicker date-format="yyyy-MM-dd">
<input required ng-model="formCtrl.requestDate" name="requestDate" type="text" />
</datepicker>
</div>
<div ng-messages="_form.requestDate.$error" role="alert">
<div ng-message="required">Введите дату</div>
</div>
<div class="radio-wrapper clearfix" ng-class="{invalid: _form.shift.$error}">
<div ng-repeat="shift in formCtrl.shifts" class="item half-width pull-left">
<label for="<% shift.name %>">
<input required ng-model="formCtrl.currentShift"
name="shift"
ng-value="shift"
id="<% shift.name %>"
type="radio" />
<span class="text"><span ng-bind="shift.text"></span></span>
</label>
</div>
</div>
<div ng-messages="_form.shift.$error" role="alert">
<div ng-message="required">Укажите смену</div>
</div>
<!-- other inputs... -->
</form>
I think you need to use the $invalid property, which is a boolean, instead of the $error property, which is a hash.
See: https://docs.angularjs.org/api/ng/type/ngModel.NgModelController
Your ng-class definition is checking the wrong property of the form controller. You are checking the truthyness of _form.shift.$error. This object will always exist, even if there are no validation errors. When you don't have any errors, the value of _form.shift.$error is empty object {} which is truthy.
You should instead check the _form.shift.$invalid property which will properly update whether there are any problems with that form field.
There is no _form.shift. The input shift is declared inside an ng-repeat so it is a property on the _form.
To fix you could for example, move your ng-class inside the ng-repeat and reference the shift using ng-form to create a sub-grouping:
<div ng-repeat="shift in formCtrl.shifts" ng-form='nestedShiftForm'>
<div ng-class="{invalid: nestedShiftForm.shift.$error}">
<input name="shift" />
Related
I am having troubles with aplying validations on radio buttons in angular, on other input types, i usualy just create the #templateRefVariable on the input and can then access the NgControl that allows me to use things like the touched property of the control.
What im trying to achieve currently is setting the touched property of the div acording to if any of the radio buttons in the group were touched. (seting it in the div because of css dependencies if it is not in that outer div the validations will not show), but typeCode is always undefined.
<div class="form-group">
<label>Label</label>
<div class="btn-group btn-group-toggle w-100"
[class.ng-invalid]="!viewmodel.typeCode"
[class.ng-touched]="typeCode?.touched">
<label *ngFor="let domain of types" class="btn btn-toogle"
[class.active]="domain.code==viewmodel.typeCode">
<input type="radio" [(ngModel)]="viewmodel.typeCode"
#typeCode="ngModel" name="typeCode"
[value]="domain.code">
{{domain.description}}
</label>
</div>
<validation-message *ngIf="!viewmodel.typeCode"
[message]="'Required'"></validation-message>
</div>
With invalid i can workarround it by using the information in the view model to see if it was set already but the information on touched is not in the view model.
And i cant do the same for ng-touched because i need to set touched when there is an atempt to submit the form (even if the inputs were not actualy touched).
Any idea why typeCode (templateVariableRef) is undefined while using it in radio buttons ? i suspect it might be because of there being multiple in the page but i am not sure.
P.S: Using template driven forms
StackBlitz as requested (note errors on console because of typeCode undefined):
https://angular-5vqi5c.stackblitz.io
It is because ngFor is a structural directive and creates a nested template, and therefore these template variable(s) are out of scope.
Would moving your logic inside the ngFor be an option for you e.g.?
<div class="btn-group btn-group-toggle w-100"
[class.ng-invalid]="!viewmodel.typeCode">
<ng-container *ngFor="let domain of types">
<div [class.ng-touched]="typeCode?.touched>
<label class="btn btn-toogle"
[class.active]="domain.code==viewmodel.typeCode">
<input type="radio" [(ngModel)]="viewmodel.typeCode"
#typeCode="ngModel" name="typeCode"
[value]="domain.code">
{{domain.description}}
</label>
</div>
</ng-container>
</div>
PS. I haven't tested the code above.
I am trying to set the select field in the view to be required. So I'm having the below tags in my view.html
<form name="homeForm">
<div class="form-group col-md-6 md-padding">
<div>
<label style="font-size: medium">Laboratory Name</label>
<select name="labName" class="form-control" ng-model="request.labName" required>
<option ng-repeat="lab in labList" value="{{lab.id}}">{{lab.value}}</option>
</select>
<div style="color:maroon" ng-messages="homeForm.labName.$error"
ng-if="homeForm.requestTypeName.$touched">
<div ng-message="required">This field is required</div>
</div>
</div>
I was hoping the This field is required will show up only when there is no data selected. But irrespective of the field has data or not This field is required shows up like below
Is there something I am missing here
You need to set the same input name in your input and in your ng-message. Doing this, you don't even need to have ng-if. For example:
<form name="form">
<input name="fullname" type="text" ng-model="fullname" required/>
<div ng-messages="form.$submitted && form.fullname.$error">
<p ng-message="required" class="help-block">This field is required</p>
</div>
</form>
In this case I am using form.$submitted. You can remove that, replace it with touched/dirty or whatever. The principle is the same.
The ng-messages directive is in a separate library module and must be included as a dependency.
Example
<script src="//unpkg.com/angular/angular.js"></script>
<script src="//unpkg.com/angular-messages/angular-messages.js"></script>
JS
angular.module("app",["ngMessages"])
For more information, see AngularJS ngMessages Module API Reference.
You are using homeForm.requestTypeName in the ng-if, and there is no input control named requestTypeName, i guess you must use homeForm.labName as you use in the ng-message attribute.
Basically, change the ng-if to ng-if="homeForm.labName.$touched"
TL;DR;
You could use as well the homeForm.labName.$error.required for checking if actually the end user has passed away that field without entering some input.
Source: https://docs.angularjs.org/api/ng/directive/ngRequired
Say I have the following HTML...
<div class="row">
<div class="col-xs-3 align-right">
<p>Email</p>
</div>
<div class="col-xs-7">
<input type="text" class="form-control" ng-model="registrationForm.email.value"/>
<span class="error-label" ng-hide="registrationForm.email.valid"><span class="glyphicon glyphicon-remove"></span>Must be a valid email!</span>
</div>
</div>
This bit of HTML creates an email field, with an error label that is shown if the email provided is invalid. This works perfectly, and is not part of my question.
I would like to slightly alter the behavior of this label. When the user first visits the form, I don't want to display the error label unless the user has changed the value of the form input.
It seems like the $pristine and $dirty properties are the key, but I'm confused on how to go about using them. If I try to access them of properties of email.value (I.E. registrationForm.email.value.$pristine) the property seems to be undefined.
I would like to avoid enclosing these inputs in an HTML form. Is there still a way I can retain use of these properties, and if so, how?
When you create your <form> element, it will create a $scope variable with the name of your form. For example:
<form name="regForm">
<div class="row">
<div class="col-xs-3 align-right">
<p>Email</p>
</div>
<div class="col-xs-7">
<input type="text" class="form-control" name="email" ng-model="registrationForm.email.value"/>
<span class="error-label" ng-hide="registrationForm.email.valid"><span class="glyphicon glyphicon-remove"></span>Must be a valid email!</span>
</div>
</div>
</form>
You can access the $pristine using $scope.regForm.email.$pristine.
Without a <form>, simply use ng-form, which will give you the functionality of the form, without needing an actual <form> element. See this post for more information.
I have an AngularJS Form with 3 required fields inside (using ng-required). Without touching anything on the form and just simply pressing the 'Submit' button (ng-click="submit"), how do I trigger validation for the required fields AND prevent form submission? I've tried doing:
ng-required="form.$submitted && !firstName"
which triggers the validation, but also submits the form even though the form is technically $invalid??
I would take a look at angular-validator: https://github.com/turinggroup/angular-validator. It is quite useful and really leans out your validation code. ng-Message is nice but you end up maintaining more HTML and therefore it seems it would be more watches.
<form name="categoryForm" id="categoryForm" class="smart-form" angular-validator angular-validator-submit="save(true)" novalidate autocomplete="off">
<fieldset>
<section ng-class="{ 'has-error' : categoryForm.title.$invalid}">
<label class="label">Title</label>
<label class="input">
<input name="title" type="text" ng-model="category.title" id="title" placeholder="Title" required
validate-on="dirty" required-message="'Title is required'">
</label>
</section>
<section ng-if="isAdmin()">
<div class="row">
<section class="col col-6" >
<label class="checkbox">
<input type="checkbox" name="checkbox" ng-model="category.isGlobal">
<i></i><span>Global</span></label>
</section>
</div>
</section>
</fieldset>
<footer>
<button type="submit" class="btn btn-primary" ng-disabled="(categoryForm.$dirty && categoryForm.$invalid) || categoryForm.$pristine">
Submit
</button>
</footer>
</form>
Since you mention that you are doing validation for individual elements and don't know to check whether the entire form is valid or not. You can use the following condition to check whether the form is valid or not
$scope.yourFormName.$valid
Use the above condition to check whether the form is valid or not. The above condition will become true only when all the required validations inside the form are valid. Hope this is what you're looking for
I used the ng-submit directive as it triggers form.$submitted and validates ng-required fields properly before submitting.
For the case where you have multiple buttons, for I added an ng-click to each button and simply changed a $scope variable (e.g. $scope.pressedBtn). In the function that ng-submit points to, you could do something like:
if ($scope.pressedBtn === 'button1') {
// submit
}
else if ($scope.pressedBtn === 'button2') {
// save
}
I have a form with an ng-repeat directive. I'm using ng-show to display validation error messages. I'm attempting to add a validation message within the ng-repeat directive, but I'm having trouble. This is what I have so far:
<form name="rentalApp" ng-controller="RentalAppCtrl">
<label for="name">Full Name</label>
<input id="name" name="name" ng-model="app.name">
<div ng-show="rentalApp.name.$invalid">Please enter your name</div>
<div ng-repeat="history in app.history">
<label for="address{{ $index }}">Street Address</label>
<input id="address{{ $index }}" name="address{{ $index }}" ng-model="history.address">
<div ng-show="rentalApp.('address' + $index).$invalid">Please enter an address</div>
</div>
</form>
As you can see, I am using the $index variable to make sure my IDs and names are unique.
In the rest of my form I'm doing something along the lines of:
<div ng-show="rentalApp.whatever.$invald">Error Message</div>
What I'm having trouble with is that within the ng-repeat directive, the indexes are dynamic. I've been fiddling around with this for a while, and the closest I think I've gotten to a solution is this line:
<div ng-show="rentalApp.('address' + $index).$invalid">Please enter an address</div>
However that doesn't work.
How can I properly concatenate the word "address" with the $index variable, to create a string along the lines of address0, which can then be used in my ng-show directive to determine if the form element is invalid? Or, alternatively, am I going about this completely wrong (not the "Angular way")?
EDIT
I'm looking at the rentalApp object from the console, and AngularJS is not evaluating the name attribute as I would expect. Specifically, the rentalApp object contains a address{{ $index }} object, instead of address0. So it looks like I can't use the expression {{ $index }} within the name attribute.
UPDATE
I make a research and find out it is not possible to give dynamic value to name besides create a custom directive for it...
but there is a solution for you to validate dynamic form with ng-form directive for each individual ng-repeat element...
<div ng-repeat="history in app.history">
<ng-form name="addressForm">
<label>Street Address</label>
<input name="address" ng-model="history.address" ng-required="true">
<div ng-show="rentalApp['address' + $index].$invalid">Please enter an address</div>
<span class="alert error" ng-show="addressForm.address.$invalid">Please enter an address</span>
</ng-form>
</div>
and here is your PLUNKER...
Just put:
<input name="{{input.name}}"></input>