(This is the note of angular course from HKUST)
With the help of Angular form validation, we can do most validation work in the client side.
For a very usual case - string, we can use regular expression to do the validation.
About the two way binding, I wrote a very simple example, which can add different elements to the list.
<!DOCTYPE html>
<html lang="en" ng-app="testApp">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head
content must come *after* these tags -->
<title>two-way binding</title>
<!-- Bootstrap -->
<!-- build:css styles/main.css -->
<link href="../bower_components/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="../bower_components/bootstrap/dist/css/bootstrap-theme.min.css" rel="stylesheet">
<link href="../bower_components/font-awesome/css/font-awesome.min.css" rel="stylesheet">
<!-- endbuild -->
</head>
<body>
<div class="container" ng-controller="TwoWayBindingController">
<div class="row row-content">
<div class="tab-content">
<ul>
<li ng-repeat="comment in comments">{{comment}}</li>
</ul>
</div>
<hr>
<form class="form-horizontal" role="form" name="commentForm" ng-submit="sendComment()">
<p>Your input: {{inputTemp}}</p>
<br>
<input type="text" class="form-control" id="comment" name="comment"
placeholder="Comment" ng-model="inputTemp" required>
<button type="submit" class="btn btn-primary" ng-disabled="commentForm.$invalid">Send</button>
</form>
</div>
</div>
<!-- build:js scripts/main.js -->
<script src="../bower_components/angular/angular.min.js"></script>
<script>
var app = angular.module('testApp',[]);
app.controller('TwoWayBindingController', ['$scope', function($scope) {
$scope.comments=[
"abc1",
"abc2",
"abc3"
];
$scope.inputTemp="";
$scope.sendComment = function() {
// alert($scope.inputTemp)
$scope.comments.push($scope.inputTemp);
$scope.inputTemp = ""
// alert($scope.inputTemp)
};
}]);
</script>
<!-- endbuild -->
</body>
</html>
for a complicated form case, here is the example of Angular Form from course.
The HTML,
<!DOCTYPE html>
<html lang="en" ng-app="FormApp">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head
content must come *after* these tags -->
<title>Ristorante Con Fusion: About Us</title>
<!-- Bootstrap -->
<!-- build:css styles/main.css -->
<link href="../bower_components/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="../bower_components/bootstrap/dist/css/bootstrap-theme.min.css" rel="stylesheet">
<link href="../bower_components/font-awesome/css/font-awesome.min.css" rel="stylesheet">
<link href="styles/bootstrap-social.css" rel="stylesheet">
<link href="styles/mystyles.css" rel="stylesheet">
<!-- endbuild -->
</head>
<body>
<div class="container" ng-controller="ContactController">
<div class="row row-content">
<div class="col-xs-12">
<h3>Send us your Feedback</h3>
</div>
<div class="col-xs-12 col-sm-9" ng-controller="FeedbackController">
<!-- use 'novalidate' to disable the HTML5 validation work -->
<form class="form-horizontal" role="form" name="feedbackForm" ng-submit="sendFeedback()" novalidate>
<div class="form-group" ng-class="{'has-error' : feedbackForm.firstname.$error.required && !feedbackForm.firstname.$pristine }">
<label for="firstname" class="col-sm-2 control-label">First Name</label>
<div class="col-sm-10">
<!-- use the ng-model to bind the value, it can access the object in outter controller! -->
<input type="text" class="form-control" id="firstname" name="firstname"
placeholder="Enter First Name" ng-model="feedback.firstName" required>
<span ng-show="feedbackForm.firstname.$error.required && !feedbackForm.firstname.$pristine" class="help-block">
Your First name is required.
</span>
</div>
</div>
<div class="form-group" ng-class="{'has-error' : feedbackForm.lastname.$error.required && !feedbackForm.lastname.$pristine }">
<label for="lastname" class="col-sm-2 control-label">Last Name</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="lastname" name="lastname"
placeholder="Enter Last Name" ng-model="feedback.lastName" required>
<span ng-show="feedbackForm.lastname.$error.required && !feedbackForm.lastname.$pristine" class="help-block">
Your Last name is required.
</span>
</div>
</div>
<div class="form-group">
<label for="telnum" class="col-sm-2 control-label">Contact Tel.</label>
<div class="col-xs-5 col-sm-4 col-md-3">
<div class="input-group">
<div class="input-group-addon">(</div>
<!-- the tel.areaCode is not exsited in the JS file now, it will be auto created -->
<input type="tel" class="form-control" id="areacode" name="areacode"
placeholder="Area code" ng-model="feedback.tel.areaCode" required>
<div class="input-group-addon">)</div>
</div>
</div>
<div class="col-xs-7 col-sm-6 col-md-7">
<!-- auto create the nested js object -->
<input type="tel" class="form-control" id="telnum" name="telnum"
placeholder="Tel. number" ng-model="feedback.tel.number" required>
</div>
</div>
<div class="form-group" ng-class="{'has-error has-feedback' : feedbackForm.emailid.$invalid && !feedbackForm.emailid.$pristine }">
<label for="emailid" class="col-sm-2 control-label">Email</label>
<div class="col-sm-10">
<input type="email" class="form-control" id="emailid" name="emailid"
placeholder="Email" ng-model="feedback.email" required>
<span ng-show="feedbackForm.emailid.$invalid && !feedbackForm.emailid.$pristine"
class="glyphicon glyphicon-remove form-control-feedback" aria-hidden="true"></span>
<span ng-show="(feedbackForm.emailid.$invalid || feedbackForm.emailid.$error.required) && !feedbackForm.emailid.$pristine"
class="help-block">Enter a valid email address.</span>
</div>
</div>
<!-- this part is a little bit complicated -->
<div class="form-group" ng-class="{'has-error' : invalidChannelSelection}">
<div class="checkbox col-sm-5 col-sm-offset-2">
<label class="checkbox-inline">
<input type="checkbox" ng-model="feedback.agree">
<strong>May we contact you?</strong>
</label>
</div>
<div class="col-sm-3 col-sm-offset-1" ng-show="feedback.agree">
<select class="form-control" ng-model="feedback.mychannel"
ng-options="channel.value as channel.label for channel in channels">
<option value="">Tel. or Email?</option>
</select>
<span ng-show="invalidChannelSelection" class="help-block">
Select an option.
</span>
</div>
</div>
<div class="form-group">
<label for="feedback" class="col-sm-2 control-label">Your Feedback</label>
<div class="col-sm-10">
<textarea class="form-control" id="feedback" name="feedback"
rows="12" ng-model="feedback.comments"></textarea>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary" ng-disabled="feedbackForm.$invalid">Send Feedback</button>
</div>
</div>
</form>
</div>
<div class="col-xs-12 col-sm-3">
<h3>Your Current Feedback:</h3>
<p>{{feedback.firstName}} {{feedback.lastName | uppercase}}</p>
<p>Contact Tel.: ({{feedback.tel.areaCode}}) {{feedback.tel.number}}</p>
<p>Contact Email: {{feedback.email}}</p>
<p ng-show="feedback.agree">Contact by: {{feedback.mychannel}}</p>
<p>Comments: {{feedback.comments}}</p>
</div>
</div>
</div>
<!-- build:js scripts/main.js -->
<script src="../bower_components/angular/angular.min.js"></script>
<script src="scripts/angular.js"></script>
<!-- endbuild -->
</body>
</html>
and here is the js code:
'use strict';
var app = angular.module('FormApp',[]);
app.controller('ContactController',['$scope', function($scope){
$scope.feedback = {mychannel:"", firstName:"", lastName:"", agree:false, email:""};
$scope.channels = [{value:"tel", label:"Tel."}, {value:"Email", label:"Email"}];
$scope.invalidChannelSelection = false;
}])
.controller('FeedbackController',['$scope', function($scope){
$scope.sendFeedback = function() {
console.log($scope.feedback);
if ($scope.feedback.agree && ($scope.feedback.mychannel == "") && !$scope.feedback.mychannel) {
$scope.invalidChannelSelection = true;
console.log('incorrect');
}
else {
$scope.invalidChannelSelection = false;
$scope.feedback = {mychannel:"", firstName:"", lastName:"", agree:false, email:"" };
$scope.feedback.mychannel = "";
$scope.feedbackForm.$setPristine();
console.log($scope.feedback);
}
};
}]);