AngularJS validation ng-invalid class only after submit - javascript

In my from I have several inputs with validation, I need for the ng-invalid class to only be applied once the user has submitted the form.
On submit I can set a value on the scope as such...
$scope.submitForm = function () {
$scope.submited = true;
// other bits
}
... but I cant figure out how to conditionally display ng-invalid without changing the validation itself.
I am running angular 1.1.5

Demo
<input type="email" name="email" ng-model="formData.email" required />
<span ng-show="(myForm.email.$dirty || submitted) && myForm.email.$error.required">
Email is required
</span>
Use $dirty flag to show the error only after user interacted with the input:

<div ng-app>
<div ng-controller="testController">
<form name="formValidate">
<input type="text" name="testing" required ng-model="testField" ng-class="{ invalid: submitted && formValidate.testing.$invalid }"/>
<button ng-click="test()">Test</button>
</form>
</div>
</div>
<script>
var app = angular.module('', []);
function testController($scope)
{
$scope.submitted = false;
$scope.test= function()
{
$scope.submitted = true;
console.log($scope.formValidate.$invalid);
}
}
</script>
<style>
.invalid
{
border:1px solid red;
}
</style>

For custom errors I suggest to use the $setValidity method within each field.
$scope.formName.fieldName.$setValidity('custom_error_name', true);
so you will have more control over the css part too, because this kind of workflow will create also a custom class inside your field like "ng-custom_error_name" so you can deal with that.

Related

Show Error is User Enter Special Character in Textbox Angular Js

I am new to AngularJs. I have an input field and i want to show the red line error and restrict the user if user enter the special character in Textbox.
here is my Html
<input data-toggle="password" class="form-control" data-placement="after" type="password"
placeholder="User Name"
ng-model="obj.username" maxlength="16" style="text-transform: lowercase"/>
I want to restrict the user and show the error "Special Character are not allow please Try Another one" and also restrict the user.. How can i handle this in Controller
I have two possible solutions for you:
Simply use the HTML input pattern attribute, in this way you can disallow anything you want from being submitted, with native HTML validation.
<form>
<input type="text" pattern="^[a-zA-Z0-9]+$" />
<button>Submit</button>
</form>
Create a method with angular, that validates the input, on each change event.
var myApp = angular.module('myApp',[]);
myApp.controller('myController', ['$scope', function($scope) {
$scope.input = "";
$scope.error = false;
// Validation function, that sets error=true, if special chars in input.
$scope.validForm = function() {
var regex = new RegExp("^[a-zA-Z0-9]+$");
if (!regex.test($scope.input)) {
$scope.error = true;
console.log("true");
} else {
$scope.error = false;
console.log("false");
}
}
// Validation on each input change
$scope.change = function() {
$scope.validForm();
};
// Initial validation
$scope.validForm();
}]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="myApp">
<form ng-controller="myController">
<!-- Input with change function that triggers validation -->
<input type="text" ng-model="input" ng-change="change()">
<!-- Error message shown if validation has errors -->
<div ng-show="error">
Error! Please fill and don't use special chars!
</div>
<!-- Disabled submit if validation has errors -->
<div>
<button ng-disabled="error">Submit</button>
</div>
</form>
</div>

AngularJS apply class to parent element on event?

I have a form field:
<div class="form-group">
<label>Name</label>
<input type="text" name="name" class="form-control" ng-model="abc.user.name" ng-focus="abc.setFocus('name')" required>
</div>
What I need to do is set add a class to the parent element, here <div class="form-group">, when the input has focus and remove it when the field loses focus.
I know how to do this in jQuery, but not in an Angular way. I have many form fields that need to behave like this, so I'm trying to avoid setting a variable and looking for that with an ng-class. I'd rather have some way for the field to simple act on its parent, which I can use the same method in every form field.
A directive is possibly the simplest generic approach if all you need to do is manipulate the dom.
<div class="form-group" focus-class="focused">
<label>Name</label>
<input name="name" class="form-control" ng-model="abc.user.name" required>
</div>
JS
angular.module('myApp').directive('focusClass', function(){
return {
link:function(scope, elem, attrs){
elem.find('input').on('focus', function(){
elem.toggleClass(attrs.focusClass);
}).on('blur', function(){
elem.toggleClass(attrs.focusClass);
});
}
}
});
You can perform this
<div class="form-group {{focusIsSet ? 'is-focused': ''}}">
<label>Name</label>
<input type="text" name="name" class="form-control" ng-model="abc.user.name" ng-focus="focusIsSet = true" ng-blur="focusIsSet = false" required>
</div>
Where $scope.focusIsSet a boolean property. So depends of its state you can manage classes in <div class="form-group"> with that expression {{focusIsSet ? 'is-focused': ''}}
You change it with ng-focus and ng-blur directives
UPDATE
I think you can hold states for each input with that way
<div class="form-group {{checkFocusState('abc.user.name') ? 'is-focused': ''}}">
<label>Name</label>
<input type="text" name="name" class="form-control" ng-model="abc.user.name" ng-focus="setFocus('abc.user.name')" ng-blur="setBlur('abc.user.name')" required>
</div>
</div>
JS code
var inputsFocusState = {};
$scope.checkFocusState = function(propertyPathName) {
if(inputsFocusState[propertyPathName] == true) {
return true;
}
return false
}
$scope.setBlur = function(propertyPathName) {
inputsFocusState[propertyPathName] = false;
}
$scope.setFocus = function(propertyPathName) {
inputsFocusState[propertyPathName] = true;
}
Otherwise, you can create each focus property for each input in html template
P.S. ng-class is good option too
P.S.S I had similar case, but forms were completely dynamic.
So I split each property in object like user.name = {value: 'john', buttons: [...], label: 'Name', //and much more}.
Also better to change 'user.name.path' to something like 'user-name-path'.

Validation messages not removed after resetting the form

I have a html form and I am using angular JS for validation. Here, after submitting the form I am calling the reset method which will reset the form input fields to default.
But, when I submit and call reset method, the validation messages appears in the input field. I have used the below code. I don't want to see the validation messages after submitting the form.
HTML
<form name="createvalidation" role="form" class="col-lg-12" novalidate>
<div class="form-group">
</div>
<div class="form-group">
<input type="text" placeholder="Challenge name" class="form-control input-sm" name="name" ng-model="challenge.challengename" required>
<span ng-show="(createvalidation.name.$dirty || submitted) && createvalidation.name.$error.required">Name is reqiured</span>
</div>
<div class="form-group">
<textarea class="form-control input-sm" rows="2" placeholder="Write more about this challenge..." name="description" ng-model="challenge.challengedescription" required></textarea>
<span ng-show="(createvalidation.description.$dirty || submitted) && challengecreatevalidation.description.$error.required">Description is reqiured</span>
</div>
</form>
<div>
<button type="button" ng-click="createChallenge()">Create</button>
</div>
JS CODE
$scope.createChallenge = function() {
//get the field and store in db
$scope.resetForm();
}
$scope.master = {};
$scope.resetForm = function() {
$scope.challenge = angular.copy($scope.master);
$scope.createvalidation.$setPristine();
}
$scope.createChallenge = function() {
//get the field and store in db
$scope.resetForm();
}
$scope.master = {};
$scope.resetForm = function() {
$scope.submitted = false; //Try adding this
$scope.challenge = angular.copy($scope.master);
$scope.createvalidation.$setPristine();
}
You appear to be copying the pristine state of the form from within the resetForm function. This means that it will only have the version of the form when resetForm is called. Instead perhaps you should be doing that copy whenever the form is setup and pristine.

How to implement form validation with Angular JS and Bootstrap?

At a user registration web form I validate via ajax whether a username already exists in DB. When a username already exists, the corresponding input-text will go .has-error class.
Edit
I changed the ng-class attribute to {'has-error':signup.userUnavaliable()} but even though that the input is not seemly getting such class, in other words the mail input text is not getting red.
I place the directive at the wrapper as this is how the Bootstrap docs tell it.
This is how my form looks like now:
<form class="form-inline" role="form">
<div class="form-group" ng-class="{'has-error':signup.userUnavaliable()}">
<input type="email" class="form-control input-lg" ng-model="signup.mail" placeholder="e-mail" ng-change="signup.userExists(signup.mail)">
</div>
<div class="form-group">
<input type="password" class="form-control input-lg" placeholder="ContraseƱa" ng-nodel="signup.password">
</div>
<div class="checkbox">
<label>
<input type="checkbox" ng-model="signup.role" value="admin"> Administrador
</label>
</div>
<button type="submit" class="btn btn-primary" ng-disabled="signup.unavaliable">Registrar</button>
</form>
And this is my Controller:
app.controller('SignUpController',function ($scope, $http) {
$scope.userUnavaliable = function() {
return $scope.unavaliable
}
$scope.print = function(msg) {
console.log(msg)
}
this.userExists = function(mail) {
if (mail) {
var who = $http.get("/existingUsers/"+mail)
who.success(function(data,status, headers, config) {
if (data.mail) {
$scope.unavaliable = true
console.log(data.mail + " ya existe en la DB")
}
else{
$scope.unavaliable = false
}
});
who.error(function(data, status, headers, config) {
alert("AJAX failed!");
})
}
}
})
Also, I'm trying to disable the button and it's not gettin such effect, so I think my controller has any issue.
As given in bootstrap validation states, if you want your label color to be changed according to the validation state of the input, you will have to apply ng-class on that.
Here is the sample code that I had written a little while. Please note that to take advantage of Angular JS validation states on form elements, you need to provide name to all input types.
This code would turn the input box plus label color red or green depending upon the validation state.
<div class="form-group"
ng-class="( newProfileForm.email.$dirty ? (newProfileForm.email.$valid ? 'has-success has-feedback' : 'has-error has-feedback' ) : ' ')"
>
<label class="col-sm-4 control-label">Email</label>
<div class="col-sm-6">
<input type="email" name="email" class="form-control" ng-model="user.mail" ng-required='true'>
<!-- Invalid Span -->
<span ng-if='newProfileForm.email.$invalid && newProfileForm.email.$dirty' class="glyphicon glyphicon-remove form-control-feedback"></span>
<!-- Valid Span -->
<span ng-if='newProfileForm.email.$valid' class="glyphicon glyphicon-ok form-control-feedback"></span>
<p ng-show="newProfileForm.email.$invalid && newProfileForm.email.$dirty" class="bg-danger pad">Please enter valid email.</p>
</div>
</div>
[EDIT] Explanation for name attribute.
Angular makes use of name attribute to determine the state of the input control. So, if you have a input control with name username. Even your form should have a name for angular validation states.
AngularJS would use the fallowing variables to check its validation state.
formname.username.$valid = if username is alright according to validation rules.
formname.username.$invalid = if username is invalid
formname.username.$dirty = if user has edited the input box
formname.username.$pristine = if user has not edited the input box.
Angular makes use of name attribute for validaiton.
And if you want your button to be disabled depending upon the availability of the user.
Use something like
<button class="btn btn-default" ng-disabled="unavaliable">Submit</button>
try
<div class="form-group" ng-class="{'has-error':signup.userUnavaliable()}">

How to manually trigger a form's submit in AngularJS?

I have a form that I wanted be nested, but it is not possible since HTML can't accept nested form. Is there a way I can manually invoke the submit(triggers the validation, e.g. required) on first form on AngularJS?
Here's how the code looks like:
<div ng-conroller="ContactController">
<form ng-submit="saveHeaderAndDetail()">
<label for="Description">Description</label>
<input type="text" ng-model="Description" required/>
<input type="text" style="visibility:hidden" />
</form>
<form ng-submit="addToDetail()">
...
</form>
<input type="button"
ng-click="what code could trigger the first form's submit?"/>
</div>
Btw, both forms are under one controller if that helps
Try creating a directive that catches an event:
var app = angular.module('myApp', []);
function MyCtrl($scope) {
$scope.triggerSubmit = function() {
$scope.$broadcast('myEvent');
console.log('broad');
};
$scope.onSubmitted = function() {
alert('submitted!');
};
}
app.directive('submitOn', function() {
return {
link: function(scope, elm, attrs) {
scope.$on(attrs.submitOn, function() {
//We can't trigger submit immediately, or we get $digest already in progress error :-[ (because ng-submit does an $apply of its own)
setTimeout(function() {
elm.trigger('submit');
});
});
}
};
});
<link href="http://twitter.github.com/bootstrap/assets/css/bootstrap.css" rel="stylesheet"/>
<script src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script src="http://code.angularjs.org/1.0.0/angular-1.0.0.js"></script>
<div ng-controller="MyCtrl">
<form submit-on="myEvent" ng-submit="onSubmitted()">
Form...
</form>
<hr />
<a class="btn" ng-click="triggerSubmit()">Submit</a>
</div>
Original source:
http://jsfiddle.net/unWF3/
I've answered a similar question here AngularJS - How to trigger submit in a nested form
Basically, you can trigger validation by firing $validate event
isFormValid = function($scope, ngForm) {
$scope.$broadcast('$validate');
if(! ngForm.$invalid) {
return true;
}
For working code example & a small utility method which is helpful in showing validation messages, see answer in the above link.
You can have nested forms with ng-form directive. It will be like:
<form name="accountForm">
<div data-ng-form="detailsForm">
<input required name="name" data-ng-model="name">
</div>
<div data-ng-form="contactsForm">
<input required name="address" data-ng-model="address">
</div>
<button type="submit">Save</button>
</form>
That way when submit will be triggered for the accountForm it will validate nested ng-forms also.
There's an easier way to do that, You can give a name for each form that you have in your app, then you'll be able to send the entire angular object of the form that you want to trigger or do whatever you want with it. Example:
<div ng-conroller="ContactController">
<form name="myFirstForm" ng-submit="saveHeaderAndDetail()">
<label for="Description">Description</label>
<input type="text" ng-model="Description" required/>
<input type="text" style="visibility:hidden" />
</form>
<form name="mySecondForm" ng-submit="addToDetail()">
...
</form>
<input type="button"
ng-click="saveHeaderAndDetail(myFirstForm)"/>
</div>
Then in your function
saveHeaderAndDetail (myFirstForm) {
myFirstForm.$submitted = true
...
}
We can always submit a form directly using the submit
() function from javascript.
document.getElementById("myform").submit()
In this way, we can validate the form using angularjs first and if the form is valid then submit it using the submit method.

Categories

Resources