AngularJS form validation - at least one input with value - add class - angularjs

I have a form where at least one input must contain data, so I'm using the following to disable the submit until at least one input has data:
<form novalidate>
<input type="text" ng-model="caption.topCap" id="topCap" class="pull-left" required>
<input type="text" ng-model="caption.bottomCap" id="bottomCap">
<input type="submit" value="Caption It" class="btn btn-block btn-success btn-lg" ng-disabled="!(caption.topCap || caption.bottomCap)">
</form>
This is the controller:
capApp.controller('captionFormController', ['$scope', function($scope) {
$scope.master = { topCap: "Top Line", bottomCap: "Bottom Line" };
$scope.update = function(caption) {
$scope.master = angular.copy(caption);
};
$scope.reset = function() {
$scope.caption = angular.copy($scope.master);
};
$scope.reset();
}]);
The problem is that I cannot use required on the fields because only one or the other is required, therefore I never get a class of ng-invalid added to the input, so although both fields might be empty, and I have a disabled submit button, I want to have a class added if both fields are empty.
Is there a way to have a class added to the fields, if they have been touched but are both empty? They are prefilled on page load by the way.

ng-required allows you to use an expression to set if the field should be marked as required or not, you could make the fields reference each other values there.
For details and a very nice working example see the response for the following question: How can I conditionally require form inputs with AngularJS?

could probably use ng-required
input(ng-required="!caption.bottomCap, ng-model="caption.topCap")
input(ng-required="!caption.topCap, ng-model="caption.bottomCap")

Related

Angular: Disable button on click after required fields are filled in the form

I need to disable the submit button after clicking on the button to prevent multiple submissions but before the it has to ensure that the required fields are filled.
I tried
<body ng-app="ngToggle">
<div ng-controller="AppCtrl">
<form name="newUserForm">
<input type="text" required>
<input type="text" required>
<input type="text">
<button ng-click="disableClick()" ng-disabled="isDisabled"
ng-model="isDisabled">Disable ng-click</button>
</form>
</div>
</body>
angular.module('ngToggle', [])
.controller('AppCtrl',['$scope', function($scope){
$scope.isDisabled = false;
$scope.disableClick = function() {
alert("Clicked!");
$scope.isDisabled = true;
return false;
}
}]);
but this will only disable the button without any validation
Ok, I get what you mean/want so I'll try to help and come up with some code - which is obviously missing but if it wasn't missing the necessary code, you'd have the solution :)
First, you'll have to properly write your form:
<form name="newUserForm" ng-submit="disableClick(newUserForm.$valid)" novalidate>
<input type="text" name="input1" ng-model="form.input1" required>
<input type="text" name="input2" ng-model="form.input2" required>
<input type="text" name="input3" ng-model="form.input3"> //not required
<button type="submit" ng-disabled="isDisabled">Disable ng-click</button>
</form>
so what we've got here, which you're missing:
You did name your form, but you're missing a submit, in the form as ng-submit or the button with type="submit", which will submit the form and that's when the validation happens
In order for Angular to validate your inputs, they need to have ng-model, otherwise it will not validate (HTML5 validation would, but read on)
I've added novalidate so we tell the browser "Hey, we need this validated but not by you, so do nothing", and Angular takes over
And last but not least, Angular adds a couple of properties to the form (see more here: Angular form Docs), $valid being one of them, which is set to true when all validated inputs are valid.
So this sums up the changes you needed to do to your form.
As for the Javascript part, there is just one small change:
$scope.disableClick = function(valid) {
if(valid && !$scope.isDisabled) {
$scope.isDisabled = true;
}
return false;
}
I guess the change is obvious, but I'll explain anyway - check that newUserForm.$valid (boolean) and if it's true (meaning form has passed validation) disable this button.
Of course, you'll have to add checks not to run the code on any type of submits and not just disabling the button (which can easily be re-enabled via Dev Tools), so that's why I added !$scope.isDisabled to the if statement.
Hope this answers your question :)
P.S. Here's a running demo in Plunker

Elegant way in Angular to enable submit if all child forms but the last are valid

In the simple Angular app I'm working on there is a parent form with various child forms that are created from an ng-repeat. I'd like a submit button to be tied to the parent form's $valid property OR some other simple way to enable the submit button when the form is what I consider to be valid. However, due to the user workflow a new child form is added after the fields of the last child form are completed. Thus, even a perfect form's last row is always empty & thus invalid (as there are required fields). Any suggestions on how to handle enable/disable of a submit button in this situation? I've created a fiddle that shows the issue. There is a submit button linked to the parent form's $valid, which does not show up unless the last form (row) is valid. Then there's a second submit button, whose enabled property I control by explicitly looking at all child forms and setting a scope variable to true or false based on my requirements. I think this solution is inelegant and there's got to be a better way.
https://jsfiddle.net/godinger/r5yx5z4b/
Here's the HTML form:
<div ng-app="myApp" ng-controller="myCtrl">
<pre>Parent Form Valid: {{parentForm.$valid}}</pre>
<ng-form name="parentForm">
<div ng-repeat="person in people">
<ng-form name="childForm" novalidate>
<input name="firstName"
required
ng-model="person.firstName"
ng-init="person.form=childForm"/>
<input name="lastName"
required
ng-model="person.lastName"
ng-init="person.form=childForm"/>
<span>Valid: {{childForm.$valid}}</span>
</ng-form>
</div>
<button ng-submit ng-disabled="parentForm.$invalid">
Submit
</button>
<button ng-submit ng-disabled="!enableSubmit">
Workaround Submit
</button>
</ng-form>
</div>
And here's the Angular code:
var myApp = angular.module("myApp", []);
myApp.controller("myCtrl", function($scope) {
$scope.enableSubmit = false;
$scope.people = [
{firstName: 'John', lastName: "Adams"},
{firstName: 'Alex', lastName: 'Hamilton'},
{firstName: '', lastName:''}];
$scope.$watch(updateSubmit);
function updateSubmit(){
if (!$scope.people){
$scope.enableSubmit = false;
return;
}
var numberOfPeople = $scope.people.length;
for (var i=0; i<numberOfPeople-1; i++){
var personForm = $scope.people[i].form;
if (personForm.$invalid){
$scope.enableSubmit = false;
return;
}
}
var lastPerson = $scope.people[numberOfPeople-1];
var lastPersonForm = lastPerson.form;
if (lastPersonForm.$valid){
$scope.enableSubmit = true;
return;
}
if (lastPerson.firstName || lastPerson.lastName){
$scope.enableSubmit = false;
return;
}else{
$scope.enableSubmit = true;
return;
}
}
});
I'm not sure that your implementation makes the most sense, but if want you want to do is provide "different html" based on the last element in ng-repeat, the simplest way is to use the $last element local variable. There are a number of ways to do this...but here is the simplest answer to your question:
<ng-form ng-if="!$last" name="childForm" novalidate>
<input name="firstName" placeholder="First name"
ng-model="person.firstName"
ng-init="person.form=childForm"/>
<input name="lastName"
required placeholder="First name"
ng-model="person.lastName"
ng-init="person.form=childForm"/>
<span>Valid: {{childForm.$valid}}</span>
</ng-form>
<div ng-if="$last">
Do Other Logic / Show other stuff (this could even be repeat all the form elements again, but remove all of the 'required' properties)
</div>

How to use Angular input fields email validation inside controller?

I'm trying to validate a variable as email inside Angular controller.
var valid = $filter('email')($scope.email);
The email filter doesn't exists, generates "unknown provider error". What's the correct way to access email validation from inside the controller?
Thanks.
Later edit: don't put me to create a custom filter, it must be a way using angular validation.
You can create a hidden input type email:
<input type="email" hidden id="emailValidator" required ng-model="x" />
Then in js set the value to that input and check validity:
var validator = $('#emailValidator')[0];
validator.value = "someemail#tovalidate.com";
return validator.checkValidity();
Also this documentation could be helpful: https://docs.angularjs.org/guide/forms
You could use form and prevent form submission by adding ng-disabled to the submit button:
<form name="form">
<input type="email" ng-model="email" name="email" required/>
<button type="submit"
ng-disabled="form.$invalid">Submit</button>
</form>
{{form.email.$valid}}
As the point of validation is to prevent submission and show error messages. I think it's enough to do it there instead of controllers where you handle your business logic.
DEMO
You can write your own filter:
angular.module(/**some module description here**/).
filter('email',function(){
var validateEmail = function(email) {
var re = /^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(email);
}
return function(input){
return validateEmail(input);
};
});
Regular expression is borrowed from here

AngularJS not validating email field in form

I have the html below where I have a form that I want to submit to the AngularJS Controller.
<div class="newsletter color-1" id="subscribe" data-ng-controller="RegisterController">
<form name="registerForm">
<div class="col-md-6">
<input type="email" placeholder="your#e-mail.com" data-ng-model="userEmail" required class="subscribe">
</div>
<div class="col-md-2">
<button data-ng-click="register()" class="btn btn-primary pull-right btn-block">Subsbcribe</button>
</div>
</form>
</div>
And the controller is below
app.controller('RegisterController', function ($scope,dataFactory) {
$scope.users = dataFactory.getUsers();
$scope.register = function () {
var userEmail = $scope.userEmail;
dataFactory.insertUser(userEmail);
$scope.userEmail = null;
$scope.ThankYou = "Thank You!";
}
});
The problem is that no validation is taking place when I click the button. It is always routed to the controller although I do not supply a correct email. So every time I click the button I get the {{ThankYou}} variable displayed. Maybe I do not understand something.
AngularJS does not disable enable any functionality for form validations. What is does is, it makes the state of the form and its control in terms of validation available on the current scope. You are required to implement the behaviour yourself.
In your case if you need to check user email is valid your html input should have a name attribute like
<input type="email" placeholder="your#e-mail.com" data-ng-model="userEmail" required class="subscribe" name='userEmail'>
Then on your controller you can check
$scope.registerForm.userEmail.$invalid property.
You can use the same property to disable the button on the form using ng-disabled
<button data-ng-click="register()" class="btn btn-primary pull-right btn-block" ng-disabled='registerForm.userEmail.$invalid'>Subsbcribe</button>
Basically the registerForm object is a ngFormController and userEmail is ngModelController. Please read the developer guide for forms
You are missing some part to achieve what you want. Normally you will need to add some code to enable disable the submit button base on the state of the form i.e valid/invalid. In your case this can be done like that :
<button data-ng-click="register()" class="btn btn-primary pull-right btn-block" ng-disabled="registerForm.$invalid">Subsbcribe</button>
Notice the ng-disabled="registerForm.$invalid".
You can as well provided inline feedback to the user with something like :
<input type="email" placeholder="your#e-mail.com" data-ng-model="userEmail" required="" class="subscribe" name="userName"/>
<span ng-show="registerForm.userName.$error.required">Please enter a name</span>
Or with CSS like that :
input.ng-invalid-required {
background-color: #FA787E;
}
You have a working plunker here

prevent default on submit :- Angularjs

I want to prevent-default action of http-post to '/signUp' if e-mail is null upon filling form.
Controller Code:-
$scope.signUp = function() {
if($scope.email = null);
preventdefault;
}
html (jade) :-
form(name="input", action="/signUp", method="post")
input(type="submit", value="submit")
When you have the action attribute specified for the form, angularjs will not do preventDefault.
If you remove it and add ng-submit instead:
<form name="myForm" method="post" ng-submit="signUp(myForm)" novalidate>
<input type="email" name="email" ng-model="newSignup.email" required>
<button type="submit">sign up</button>
</form>
In this case the form will always have preventDefault and on submit your $scope.signUp() function will be called where you can proceed with an ajax post to the backend /signup or further validation.
Note that by using proper validation attributes on your inputs (like type="email" and required), angularjs will perform some basic validation for you.
You can have an extra ng-disabled="!myForm.$valid" on the submit button to keep the button disabled while the email is not correctly entered.
By using ng-model on the inputs like in my example, your scope will get a $scope.newSignup object which you can check in your signUp() function for further validation:
$scope.signUp = function(htmlForm) {
if ($scope.newSignup.email !== 'some#email.com') {
return false; // you should really show some info to the user
}
...
}

Resources