AngularJS : Form dan Validasi

Mahir Koding – Jika program yang kita bangun akan berhubungan dengan form, maka penting bagi kita untuk melakukan validasi setiap input yang masuk dari user. Validasi wajib dilakukan di sisi front end dan back end. Mengapa? Agar tidak terlalu memberatkan kinerja server untuk melakukan validasi. Biarkan browser masing-masing client yang bekerja jika validasi terjadi di sisi front end. Untuk masalah validasi, di AngularJS juga sudah tersedia beberapa build in function untuk melakukan validasi walaupun tidak selengkap function yang ada di javascript.

  • angular.isNumber
  • angular.isString
  • angular.isObject
  • angular.isArray
  • angular.isFunction
  • angular.isDefined
  • angular.isUndefined
<!DOCTYPE html>
<html>
<head>
	<title>AngularJS - Tutorial</title>
	<script type="text/javascript" src="js/angular.min.js"></script>
</head>
<body ng-app="myApps">
	<div ng-controller="basicValid">
		isNumber? {{ isnumber }}<br>
		isString? {{ isstring }}<br>
		isObject? {{ isobject }}<br>
		isArray? {{ isarray }}<br>
		isFunction? {{ isfuntion }}<br>
		isDefined? {{ isdefined }}<br>
		isUndefined? {{ isundefined }}<br>
	</div>
</body>
<script type="text/javascript" >
	var app = angular.module("myApps", []);
	app.controller("basicValid", function($scope){
		function a(){
			alert("a");
		}
		var temp = {name:"Bluejack"};
		var unknown;

		$scope.isnumber = angular.isNumber(2); //true
		$scope.isstring = angular.isString("2"); //true
		$scope.isobject = angular.isObject(temp); //true
		$scope.isarray = angular.isArray(temp); //false 
		//(note : in javascipt, array also an object but object not an array)

		$scope.isfuntion = angular.isFunction(a); // true
		$scope.isdefined = angular.isDefined(unknown); //false
		$scope.isundefined = angular.isUndefined(unknown); //true
	});
</script>
</html>

Jika ingin menggunakan validasi untuk form, maka kita akan mengenal beberapa state :

  • ng-untouched – State dimana form component belum “disentuh” sama sekali atau sudah.
  • ng-touched – State dimana form component telah “disentuh” atau belum.
  • ng-pristine – State dimana form component telah di modif isinya atau belum. Kalau statusnya pristine true, maka sudah pasti touched Tetapi belum tentu sebaliknya.
  • ng-dirty – State dimana form component telah di modif atau belum.
  • ng-valid – State dimana form component telah valid atau tidak.
  • ng-invalid – State dimana form component tidak valid atau iya.

Untuk state valid dan invalid, penentuannya sesuai dengan attribute/type pada component (HTML5 version). Ada beberapa attribute yang menjadi patokan apakah form tersebut valid atau tidak, diantaranya :

email | max | maxlength | min| minlength | number | pattern | required | url | date | datetimelocal | time | week | month

Untuk referensi, cek aturan penggunaan attribute/type diatas pada halaman ini : https://www.w3schools.com/html/html_form_input_types.asp

<form name="userForm">
	<table>
		<tr>
			<td>Name</td><td>:</td>
			<td><input type="text" name="nameInput" ng-model="user.name" required></td>
		</tr>
		<tr>
			<td>Gender</td><td>:</td>
			<td>
				<input type="radio" name="radioGender" ng-model="user.gender" value="Male" required> Male
				<input type="radio" name="radioGender" ng-model="user.gender" value="Female" required> Female
			</td>
		</tr>
		<tr>
			<td>Age</td><td>:</td>
			<td><input type="number" name="ageInput" ng-model="user.age" required></td>
		</tr>
		<tr>
			<td>Country</td><td>:</td>
			<td><select name="countrySelect" ng-model="user.country" ng-options="country for country in countries" required></select></td>
		</tr>
		<tr>
			<td>Address</td>
			<td>:</td>
			<td><textarea name="addressInput" ng-model="user.address" required></textarea></td>
		</tr>
		<tr>
			<td>Blog</td>
			<td>:</td>
			<td><input type="url" name="blogInput" ng-model="user.blog"></td>
		</tr>
		<tr>
			<td colspan="3">
				<button ng-disabled="userForm.$invalid">Save</button>
				<button ng-click="reset()">Reset</button>
			</td>
		</tr>
	</table>
</form>
<p>
	{{ user | json }}
</p>

Error Messages :

<span ng-show="userForm.nameInput.$invalid && userForm.nameInput.$dirty">Name can't be empty<br></span>
<span ng-show="userForm.ageInput.$invalid && userForm.ageInput.$dirty">Age can't be empty<br></span>
<span ng-show="userForm.radioGender.$invalid && userForm.radioGender.$dirty">Gender must be selected<br></span>
<span ng-show="userForm.countrySelect.$invalid && userForm.countrySelect.$dirty">Country must be selected<br></span>
<span ng-show="userForm.addressInput.$invalid && userForm.addressInput.$dirty">Address must be filled<br></span>
<span ng-show="userForm.blogInput.$invalid && userForm.blogInput.$dirty">Not a url format</span>

Error messages akan muncul ketika kondisi di dalam ng-show bernilai true.

Untuk mengambil state dari sebuah form component, bisa bisa mengakses attribute name-nya. Bukan mengakses modelnya. Misalnya untuk nameInput, bisa diakses dengan mengakses name form terlebih dahulu [dot] nameInput. Lalu, kondisi $dirty sengaja ditambahkan agar errormessages tidak muncul langsung ketika form di load tetapi akan muncul jika sudah di modif sebelumnya.

Seperti yang saya jelaskan diatas, state valid dan invalid ditentukan oleh attribute/input type HTML5. Contohnya untuk blogInput, kondisi error akan muncul karena type inputan untuk blogInput adalah url (new HTML5 features).

Lalu, bagaimana jika ingin validasi umur harus diatas 17 misalnya. Sebenarnya , kita juga bisa mengakses value dari modelnya lalu menambakan compare operator layaknya if seperti biasa.

<span ng-show="user.age < 17 && userForm.ageInput.$dirty">Age must be older than 17</span>

Note : Directive ng-show/ng-hide/ng-if/ng-disabled bisa diisi dengan kondisi if seperti biasa. Jadi boleh ditambahkan compare operator, ataupun negasi (!).

<script type="text/javascript" >
	var app = angular.module("myApps", []);
	app.controller("registerCtrl", function($scope){
		$scope.countries = ["Indonesia", "Singapore", "Malaysia", "Japan"];
		$scope.defaultValue = {
			name : "John Doe",
			gender : "Male",
			age : 20,
			country : "Indonesia",
			address : "Jln. Raya",
			blog : "http://www.mahirkoding.com"
		}
		$scope.reset = function(){
			$scope.user = angular.copy($scope.defaultValue);
		}
	});
</script>

angular.copy() merupakan salah satu build in function dari AngularJS untuk menduplikasi isi object ke object lain. Perlu diketahui, kalau seandainya kita langsung mengassignnya menggunakan tanda = maka kedua object tersebut akan sama value dan referencenya. Ketika object a diubah, maka object b akan ikut berubah. So, gunakan angular.copy() untuk mengcopy isinya saja tanpa menyamakan referencenya.

Full Code

<!DOCTYPE html>
<html>
<head>
	<title>AngularJS - Tutorial</title>
	<script type="text/javascript" src="js/angular.min.js"></script>
</head>

<span ng-show="user.age < 17 && userForm.ageInput.$dirty">Age must be older than 17</span>

<body ng-app="myApps">
	<div ng-controller="registerCtrl">
		<span ng-show="userForm.nameInput.$invalid && userForm.nameInput.$dirty">Name can't be empty<br></span>
		<span ng-show="userForm.ageInput.$invalid && userForm.ageInput.$dirty">Age can't be empty<br></span>
		<span ng-show="userForm.radioGender.$invalid && userForm.radioGender.$dirty">Gender must be selected<br></span>
		<span ng-show="userForm.countrySelect.$invalid && userForm.countrySelect.$dirty">Country must be selected<br></span>
		<span ng-show="userForm.addressInput.$invalid && userForm.addressInput.$dirty">Address must be filled<br></span>
		<span ng-show="userForm.blogInput.$invalid && userForm.blogInput.$dirty">Not a url format</span>
		<form name="userForm">
			<table>
				<tr>
					<td>Name</td><td>:</td>
					<td><input type="text" name="nameInput" ng-model="user.name" required></td>
				</tr>
				<tr>
					<td>Gender</td><td>:</td>
					<td>
						<input type="radio" name="radioGender" ng-model="user.gender" value="Male" required> Male
						<input type="radio" name="radioGender" ng-model="user.gender" value="Female" required> Female
					</td>
				</tr>
				<tr>
					<td>Age</td><td>:</td>
					<td><input type="number" name="ageInput" ng-model="user.age" required></td>
				</tr>
				<tr>
					<td>Country</td><td>:</td>
					<td><select name="countrySelect" ng-model="user.country" ng-options="country for country in countries" required></select></td>
				</tr>
				<tr>
					<td>Address</td>
					<td>:</td>
					<td><textarea name="addressInput" ng-model="user.address" required></textarea></td>
				</tr>
				<tr>
					<td>Blog</td>
					<td>:</td>
					<td><input type="url" name="blogInput" ng-model="user.blog"></td>
				</tr>
				<tr>
					<td colspan="3">
						<button ng-disabled="userForm.$invalid">Save</button>
						<button ng-click="reset()">Reset</button>
					</td>
				</tr>
			</table>
		</form>
		<p>
			{{ user | json }}
		</p>
	</div>
</body>
<script type="text/javascript" >
	var app = angular.module("myApps", []);
	app.controller("registerCtrl", function($scope){
		$scope.countries = ["Indonesia", "Singapore", "Malaysia", "Japan"];
		$scope.defaultValue = {
			name : "John Doe",
			gender : "Male",
			age : 20,
			country : "Indonesia",
			address : "Jln. Raya",
			blog : "http://www.mahirkoding.com"
		}
		$scope.reset = function(){
			$scope.user = angular.copy($scope.defaultValue);
		}
	});
</script>
</html>

Jika ada pertanyaan yang kurang jelas silahkan berkomentar di bawah. Atau, jika ingin request tutorial juga dapat ke halaman ini. Dukung terus Mahir Koding agar dapat selalu mengupdate artikel dengan share dan like artikel ini. Terima Kasih.