How to write a more concise AngularJS form? - javascript

I'm trying to write a registration form with the help of AngularJS and using Bootstrap for the styling. I've got something working, but I'm pretty sure if I had more knowledge with Angular this could be greatly improved. So far I've got...
User-name field:
<div class="container" ng-controller="validateCtrl">
<form name="myForm">
<div class="form-group has-feedback" ng-class="{true: 'has-success'}[myForm.email.$dirty]" ng-class="{true: 'has-error'}[myForm.email.$invalid]">
<label for="email">Email</label>
<input class="form-control" type="email" name="email" ng-model="email" ng-maxlength="254" placeholder="Enter Email" required>
<span class="glyphicon glyphicon-remove form-control-feedback" ng-show="myForm.email.$dirty && myForm.email.$invalid"></span>
<span style="color:red" ng-show="myForm.email.$dirty && myForm.email.$invalid">
<span ng-show="myForm.email.$error.required">Email is required!</span>
<span ng-show="myForm.email.$error.email">Invalid email address!</span>
<span ng-show="myForm.email.$error.maxlength">Email is too long!</span>
</span>
<span class="glyphicon glyphicon-ok form-control-feedback" ng-show="myForm.email.$dirty && !myForm.email.$invalid"></span>
</div>
Password Field:
<div class="form-group has-feedback" ng-class="{true: 'has-success'}[myForm.password.$dirty]" ng-class="{true: 'has-error'}[myForm.password.$invalid]">
<label for="password">Password</label>
<input class="form-control" type="password" name="password" ng-model="password" ng-minlength="5" ng-maxlength="255" placeholder="Enter Password" required>
<span class="glyphicon glyphicon-remove form-control-feedback" ng-show="myForm.password.$dirty && myForm.password.$invalid"></span>
<span style="color:red" ng-show="myForm.password.$dirty && myForm.password.$invalid">
<span ng-show="myForm.password.$error.required">Password is Required!</span>
<span ng-show="myForm.password.$error.minlength">Password is too short! </span>
<span ng-show="myForm.password.$error.maxlength">Password is too long!</span>
</span>
<span class="glyphicon glyphicon-ok form-control-feedback" ng-show="myForm.password.$dirty && !myForm.password.$invalid"></span>
</div>
Password Confirm:
<div class="form-group has-feedback" ng-class="{true: 'has-success'}[myForm.passwordrepeat.$dirty]" ng-class="{true: 'has-error'}[myForm.passwordrepeat.$invalid]">
<label for="passwordrepeat">Confirm Password</label>
<input class="form-control" type="password" name="passwordrepeat" ng-model="passwordrepeat" placeholder="Confirm Password" required compare-to="password">
<span class="glyphicon glyphicon-remove form-control-feedback" ng-show="myForm.passwordrepeat.$dirty && myForm.passwordrepeat.$invalid"></span>
<span style="color:red" ng-show="myForm.passwordrepeat.$dirty && myForm.passwordrepeat.$invalid">
<span ng-show="myForm.passwordrepeat.$error.required">Second Password is Required!</span>
<span ng-show="myForm.passwordrepeat.$error">Passwords do not match!</span>
</span>
<span class="glyphicon glyphicon-ok form-control-feedback" ng-show="myForm.passwordrepeat.$dirty && !myForm.passwordrepeat.$invalid"></span>
</div>
Submit Button:
<button
class="btn btn-primary"
ng-disabled=
"myForm.email.$invalid ||
myForm.password.$invalid ||
myForm.passwordrepeat.$invalid">
Register
</button>
</form>
</div>
Can anyone advise on how I can make this code more concise? For starters, can this conditional ng-class expression be improved...
<div class="form-group has-feedback" ng-class="{true: 'has-success'}[myForm.passwordrepeat.$dirty]" ng-class="{true: 'has-error'}[myForm.passwordrepeat.$invalid]">
...this basically says, if the field is dirty, then if it's valid add the 'has-success' element else add 'has-error'. Is there a cleaner way of achieving this...
<span ng-show="myForm.email.$error.required">Email is required!</span>
<span ng-show="myForm.email.$error.email">Invalid email address!</span>
<span ng-show="myForm.email.$error.maxlength">Email is too long!</span>
Rather than listing every error? Finally, is there a preferred way of writing long expressions like this in the html template...
"myForm.email.$dirty && !myForm.email.$invalid"
I've tried to get my head around directives and I'm using one for the password confirm but I don't think they would make a big difference here (but I'm probably wrong).
Any help/advise on best practices greatly appreciated!

Your question is sort of vague, however here are some great articles that will help in your quest for better Angular based forms :)
Submitting AJAX Forms: The AngularJS Way
https://scotch.io/tutorials/submitting-ajax-forms-the-angularjs-way
AngularJS Form Validation
https://scotch.io/tutorials/angularjs-form-validation
And since you're using Bootstrap and Angular:
How to Correctly Use BootstrapJS and AngularJS Together
https://scotch.io/tutorials/how-to-correctly-use-bootstrapjs-and-angularjs-together
<!-- FORM -->
<!-- pass in the variable if our form is valid or invalid -->
<form name="userForm" ng-submit="submitForm(userForm.$valid)" novalidate> <!-- novalidate prevents HTML5 validation since we will be validating ourselves -->
<!-- NAME -->
<div class="form-group">
<label>Name</label>
<input type="text" name="name" class="form-control" ng-model="name" required>
</div>
<!-- USERNAME -->
<div class="form-group">
<label>Username</label>
<input type="text" name="username" class="form-control" ng-model="user.username" ng-minlength="3" ng-maxlength="8">
</div>
<!-- EMAIL -->
<div class="form-group">
<label>Email</label>
<input type="email" name="email" class="form-control" ng-model="email">
</div>
<!-- SUBMIT BUTTON -->
<button type="submit" class="btn btn-primary">Submit</button>
</form>
// create angular controller
validationApp.controller('mainController', function($scope) {
// function to submit the form after all validation has occurred
$scope.submitForm = function(isValid) {
// check to make sure the form is completely valid
if (isValid) {
alert('our form is amazing');
}
};
});

Related

jquery each method not working as expected

I am currently working on a website and this particular section requires the user to enter their details in a form. What I am trying to achieve is the following;
If the user hits the submit button and any fields are empty, I want a span element, which is initially set to CSS display none, to show up for each respective input field which has not been filled.
However, nothing seems to be happening when I click on the button. When I go to the console, it does not display any error message.
Can someone please assist? Many thanks.
HTML:
<!-- START OF 'YOUR DETAILS' FORM-->
<section>
<div class="container">
<h3>Step 3: Your Details</h3>
<!-- SLIDE-IN DIV TO REPRESENT DAY PASS -->
<div class="row chosenmembership">
<div class="col-md-12 text-center" id="yourdetails">
<form action="" method="">
<div class="form-group">
<label for="email">Email:</label>
<input type="email" placeholder="Email Address" id="email" class="form-control your-details">
<span class="warning"><i class="fa fa-exclamation-triangle" aria-hidden="true"></i>
Email is required!</span>
</div>
<div class="form-group">
<label for="name">Name:</label>
<input type="text" placeholder="Full Name" id="name" class="form-control your-details">
<span class="warning"><i class="fa fa-exclamation-triangle" aria-hidden="true"></i>
Name is required!</span>
</div>
<div class="form-group">
<label for="number">Contact Number:</label>
<input type="tel" placeholder="Contact Number" id="number" class="form-control your-details">
<span class="warning"><i class="fa fa-exclamation-triangle" aria-hidden="true"></i>
Contact Number is required!</span>
</div>
<div class="form-group">
<label for="postcode">Post Code:</label>
<input type="text" placeholder="Post Code" id="postcode" class="form-control your-details">
<span class="warning"><i class="fa fa-exclamation-triangle" aria-hidden="true"></i>
Post Code is required!</span>
</div>
<div class="form-group">
<label for="dob">Date of Birth:</label>
<input type="tel" placeholder="DD/MM/YYYY" id="dob" class="form-control your-details">
<span class="warning"><i class="fa fa-exclamation-triangle" aria-hidden="true"></i>
DOB is required!</span>
</div>
</form>
<div class="form-group">
<input type="submit" id="submit" value="CONTINUE">
</div>
</div>
</div>
</div>
</section>
<!-- END OF YOUR DETAILS FORM -->
JS / JQUERY:
$("#submit").click(function(){
var $formValues = $(".your-details");
var $warning = $(".warnings");
$($formValues).each(function(index){
if ($(this).val("")){
$($warning[index]).css("display","block");
}
})
})
When your running this code $($formValues).each(function(index){if ($(this).val("")){ console.log(this) and see in which context your function is running, the issue is that every time you write a function declaration it creates a new this context and thus the previous this is lost.
Your selectors are kind of redundant, keep the form from submission and show the warnings when any are empty seems to be your intent.
$("#submit").click(function(e) {
$(".your-details").each(function(index) {
if ($(this).val() =="") {
e.preventDefault();// no submit if not filled out
$(this).next('.warning').css("display", "block");// next sibling show
}
});
});
Thought about this for a bit and believe you might handle the form submit instead
$("form").on('submit', function(e) {
$(this).find('.warning').css("display", "none");// hide in case they fix input values
$(this).find(".your-details").each(function(index) {
if ($(this).val() =="") {
$(this).next('.warning').css("display", "block");// next sibling show
}
});
});
Alternately you might use a filter.
$("form").on('submit', function(e) {
$(this).find('.warning').css("display", "none");// hide in case they fix input values
var emptyInputs = $(this).find(".your-details")
.filter(function() {
return ($(this).val() =="");
});
if(!!emptyInputs) {
e.preventDefault();
emptyInputs.next('.warning').css("display", "block");
}
});
Except typo, there was one problem more, you are actually setting value, instead of checking it: if ($(this).val("")) If you change it, and fix typo, something like this should work. Simplified, your code could look like this:
$("#submit").click(function(){
var $formValues = $(".your-details");
$($formValues).each(function(index){
if ($(this).val()==''){
$(".warning").eq(index).css("display","block");
}
else {
$(".warning").eq(index).css("display","none");
}
})
})
Demo:
$("#submit").click(function(){
var $formValues = $(".your-details");
$($formValues).each(function(index){
if ($(this).val()==''){
$(".warning").eq(index).css("display","block");
}
else {
$(".warning").eq(index).css("display","none");
}
})
})
.warning {
display:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- START OF 'YOUR DETAILS' FORM-->
<section>
<div class="container">
<h3>Step 3: Your Details</h3>
<!-- SLIDE-IN DIV TO REPRESENT DAY PASS -->
<div class="row chosenmembership">
<div class="col-md-12 text-center" id="yourdetails">
<form action="" method="">
<div class="form-group">
<label for="email">Email:</label>
<input type="email" placeholder="Email Address" id="email" class="form-control your-details">
<span class="warning"><i class="fa fa-exclamation-triangle" aria-hidden="true"></i>
Email is required!</span>
</div>
<div class="form-group">
<label for="name">Name:</label>
<input type="text" placeholder="Full Name" id="name" class="form-control your-details">
<span class="warning"><i class="fa fa-exclamation-triangle" aria-hidden="true"></i>
Name is required!</span>
</div>
<div class="form-group">
<label for="number">Contact Number:</label>
<input type="tel" placeholder="Contact Number" id="number" class="form-control your-details">
<span class="warning"><i class="fa fa-exclamation-triangle" aria-hidden="true"></i>
Contact Number is required!</span>
</div>
<div class="form-group">
<label for="postcode">Post Code:</label>
<input type="text" placeholder="Post Code" id="postcode" class="form-control your-details">
<span class="warning"><i class="fa fa-exclamation-triangle" aria-hidden="true"></i>
Post Code is required!</span>
</div>
<div class="form-group">
<label for="dob">Date of Birth:</label>
<input type="tel" placeholder="DD/MM/YYYY" id="dob" class="form-control your-details">
<span class="warning"><i class="fa fa-exclamation-triangle" aria-hidden="true"></i>
DOB is required!</span>
</div>
</form>
<div class="form-group">
<input type="submit" id="submit" value="CONTINUE">
</div>
</div>
</div>
</div>
</section>
<!-- END OF YOUR DETAILS FORM -->
P.S. You can keep your: $($warning[index]) vars, but you should hide warnings, anyway (else block), if field is not empty.

How can I validate a input depending another input angularJS?

I have a problem validating my form. It is a form to change the password of a register user, the profile picture, and the biography of him. In that form the password is not required firstly, but when someone write the old password, the form requires the new password and the confirm password. I show it by an example.
Right now is not required, but if I write something in the input of old password I need that the new password and the confirm password become red. The code I have is it:
<div class="form-group">
<label for="oldpassword" class="cols-sm-2 control-label">Old Password</label>
<div class="cols-sm-10">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-lock fa-lg" aria-hidden="true"></i></span>
<input type="password" class="form-control" name="oldpassword" id="oldpassword"
placeholder="Enter your actual password" ng-model="oldPassword"/>
</div>
</div>
</div>
<div class="form-group">
<label for="password" class="cols-sm-2 control-label">New Password</label>
<div class="cols-sm-10">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-lock fa-lg" aria-hidden="true"></i></span>
<input type="password" class="form-control" name="password" id="password"
placeholder="Enter your new password"
ng-model="newPassword" pattern="^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}" require-pass/>
</div>
</div>
</div>
<div class="form-group">
<label for="confirm" class="cols-sm-2 control-label">Confirm Password</label>
<div class="cols-sm-10">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-lock fa-lg" aria-hidden="true"></i></span>
<input type="password" class="form-control" name="confirm" id="confirm"
placeholder="Confirm your new password" ng-model="confirm" require-pass confirm-directive
/>
</div>
</div>
</div>
The require-pass directive works but only when the user write something in the input of new password or confirm password. The confirm-directive is a directive to check if both password are equals (that directive works).
The require-pass directive is:
app.directive('requirePass', function () {
return {
require: 'ngModel',
link: function (scope, element, attr, mCtrl) {
function myValidation(value) {
var oldPass = $('#oldpassword').val();
console.log(oldPass);
if (oldPass!="") {
mCtrl.$setValidity('charE', false);
} else {
mCtrl.$setValidity('charE', true);
}
return value;
}
mCtrl.$parsers.push(myValidation);
}
}});
Thank you for the help!!
You don't need another custom directive for this. You can just use ng-required. Docs here: https://docs.angularjs.org/api/ng/directive/ngRequired
<input id="newPass" ng-required="oldPass" type="text" ng-model=... />
<input id="newPassConfirm" ng-required="oldPass" type="text" ng-model=... />
ng-required="oldPass" basically says "I require this field to be filled out if oldPass is not blank."

How to remove password saved by remember me option by browser using Angular.js and Javascript

I have one issue in my password field and user name field using Angular.js.I have a login page.Suppose user clicked on remember me option of browser after the login.These saved user name and password is displaying on my username field and password field.I am explaining my code below.
<div class="input-group bmargindiv1 col-md-12">
<span class="input-group-addon ndrftextwidth text-right" style="width:180px">User Name :</span>
<div ng-class="{ 'myError': billdata.uname.$touched && billdata.uname.$invalid }">
<input type="text" name="uname" id="uname" class="form-control" placeholder="add user Name" ng-model="login_name" ng-minlength="6" ng-keypress="clearField('uname');" tabindex="6" >
</div>
</div>
<div class="help-block" ng-messages="billdata.uname.$error" ng-if="billdata.uname.$touched">
<p ng-message="minlength" style="color:#F00;">This field is too short.The min length of your user name should be 6.</p>
</div>
<div class="input-group bmargindiv1 col-md-12" ng-hide="showpass">
<span style="position:absolute; right:5px; margin-top:6px; top:0px;"><button class="btn btn-xs btn-success"ng-mousedown="hideShowPassword();" ng-mouseup="hideShowPassword();" ng-mouseleave="hidePassAfterLeave();" ><i class="fa fa-eye"></i></button></span>
<span class="input-group-addon ndrftextwidth text-right" style="width:180px">Password :</span>
<div ng-class="{ 'myError': billdata.pass.$touched && billdata.pass.$invalid }">
<input type="{{inputType}}" name="pass" id="passno" class="form-control" placeholder="password" ng-model="password" ng-minlength="8" ng-pattern="/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[_!##\$%\^&\*])(?=.{8,})/" ng-keypress="clearField('passno');" tabindex="7" >
</div>
The Login credentials used by user at the time of login is available where ever the username and password filed is found which i dont need.Here I need blank user name and password field even the user clicked remember me option of browser.Please help me to resolve this issue .
Try to add 2 hidden inputs to start of your form:
<form autocomplete="off">
<div style="display: none;">
<input type="text" id="PreventChromeAutocomplete"
name="PreventChromeAutocomplete" autocomplete="username" />
<input type="password" id="PreventChromePasswordAutocomplete"
name="PreventChromePasswordAutocomplete" autocomplete="password" />
</div>
<!-- Rest form -->
</form>
you can try this
<input type="password" autocomplete="off" />
try adding autocomplete="off" on your form also
<form autocomplete="off" ...></form>
Try using javascript as :
$('#passno').attr("autocomplete", "off");
or add (autocomplete="off") attribute in html input tag :
For more info, refer http://www.w3schools.com/tags/att_input_autocomplete.asp
Try same for username field as well. :)

Implementing an Error-Class for an invalid input field in AngularJS

Firstly my HTML Code:
<form name="Form" novalidate>
<div class="form-group has-error has-feedback">
<input class="form-control" type="text" name="Name" ng-model="item.name" required="" aria-describedby="" />
<span class="glyphicon glyphicon-remove form-control-feedback" aria-hidden="true"></span>
<span class="sr-only">(error)</span>
<br />
<div class="has-error has-feedback" ng-show="Form.$submitted || Form.Name.$touched">
<span ng-show="Form.Name.$error.required">Name is invalid.</span>
</div>
</div>
I want to show div class "has-error has-feedback" and the glyphicon only, when the name is invalid. How can I develop this?
If you want to display according to it being invalid, you need to do this:
<div class="has-error has-feedback" ng-show="Form.Name.$invalid">
<span ng-show="Form.Name.$error.required">Name is invalid.</span>
</div>
Same for the glyphicon:
<span class="glyphicon glyphicon-remove form-control-feedback" aria-hidden="true" ng-show="Form.Name.$invalid"></span>

AngularJS - How can set the true value for ng-disabled directive, when the page is loaded first time?

I have this form with validation in AngularJS:
<form ng-app="myApp" ng-controller="validateCtrl as validate" name="myForm" action="sendEmail" novalidate>
<div class="form-group">
<input type="email" name="email" class="form-control" ng-model="validate.email" placeholder="Email" required>
<span style="color:yellow" ng-show="myForm.email.$dirty && myForm.email.$invalid">
<span ng-show="myForm.email.$error.required">Email is required.</span>
<span ng-show="myForm.email.$error.email">Invalid email address.</span>
</span>
</div>
<div class="form-group">
<input type="text" name="subject" class="form-control" ng-model="validate.subject" placeholder="Subject" required>
<span style="color:yellow" ng-show="myForm.subject.$dirty && myForm.subject.$invalid">
<span ng-show="myForm.subject.$error.required">Subject is required.</span>
</span>
</div>
<div class="form-group">
<textarea type="text" name="message" class="form-control" ng-model="validate.message" placeholder="Message..." required></textarea>
<span style="color:yellow" ng-show="myForm.message.$dirty && myForm.message.$invalid">
<span ng-show="myForm.message.$error.required">Message is required.</span>
</span>
</div>
<button type="submit" class="btn btn-lg btn-success"
ng-disabled="myForm.email.$dirty && myForm.email.$invalid ||
myForm.subject.$dirty && myForm.subject.$invalid ||
myForm.message.$dirty && myForm.message.$invalid"></button>
</form>
The button is disabled until the email, subject and message aren't correct. Ok, it's fine. But that is true, only if I have already interacted with the form.
In fact, when the page is loaded the first time and I haven't interacted with the form yet, the button is enabled. So, if I click it, I could send an empy email! I would that when the page is loaded the button is disabled and when I fill the fields become enabled.
How can I do that?
Thanks.
You first condition can be ng-disabled=" myForm.email.$invalid . Remove "myForm.email.$dirty
Try like this
<form name="postForm" method="POST" novalidate>
<div class="col-md-8">
<div class="col-md-12">
<div class="col-md-12"><legend>Submit New Post</legend></div>
</div>
<div class="col-md-12 form-group">
<div class="col-md-12" ng-class="{ 'has-error' : postForm.title.$invalid && !postForm.title.$pristine }">
<input type="text" placeholder="Write Title" class="form-control" name="title" ng-model="post.title" required>
<p ng-show="postForm.title.$invalid && !postForm.title.$pristine" class="text-danger">* Write Post Title</p>
</div>
</div>
<div class="col-md-12 form-group">
<div class="col-md-12" ng-class="{ 'has-error' : postForm.url.$invalid && !postForm.url.$pristine }">
<input type="url" placeholder="Write URL" class="form-control" name="url" ng-model="post.url" >
<p ng-show="postForm.url.$invalid && !postForm.url.$pristine" class="text-danger">* Write URL in http:// or https:// Format</p>
</div>
</div>
<div class="col-md-12">
<div class="col-md-12" >
<p class="text-danger">{{msg}}</p>
</div>
</div>
<div class="col-md-12 form-group">
<div class="col-md-12"><button type="submit" class="btn btn-info" ng-disabled="postForm.$invalid" ng-click="submitForm(....)">Submit</button>
<img src="img/loading.gif" ng-show="loading" /></div>
</div>
</div>
</form>
On your submit button, modify the ng-disabled to this:
ng-disabled="myForm.$invalid || myForm.$pristine">
In this case, you don't have to validate all your inputs separetely. Just test if your form is invalid OR if the user never interacted with it yet.
A form in AngularJS has two different states: pristine and dirty. The pristine indicates that your form was never touched. And dirty is the opposite. When the user set any value to one of your inputs, the angular change the state of your form from pristine to dirty.
I guess this post is a good reference to read about forms in angular

Categories

Resources