Sebenarnya topik ini sudah agak basi, tetapi berhubung saya ingin mendokumentasikan "eksperimen" saya pada framework frontend dan backend untuk pengembangan aplikasi berbasis web, maka saya tetap ingin menulis artikel ini. Bagi teman-teman yang belum mengenal framework AngularJS, bisa membaca FAQ-nya di halaman FAQ AngularJS. Intinya AngularJS adalah framework untuk membangun antarmuka aplikasi web berbasis Javascript. Ada dua versi Angular, AngularJS (versi 1) dan Angular (versi 2) yang full terintegrasi dengan Node.js, yang saya bahas adalah versi pertama dimana kita tidak perlu menggunakan Node.js. Kenapa saya memilih versi ini karena versi pertama bisa kita integrasikan dengan project aplikasi web yang sudah dengan backend apapun, dalam artikel ini saya menggunakan PHP.



Instalasi


Untuk menggunakan AngularJS kita perlu mengunduh (download) file Javascript-nya AngularJS terlebih dahulu. Setelah file Javascript AngularJS telah terunduh berikutnya kita tinggal me-link file Javascript tersebut dari dalam kode HTML kita. Pada artikel ini saya menempatkan file angular.min.js pada direktori libs/js/angular.min.js. Apabila kita masukkan pada kode HTML akan seperti ini:

<!doctype html>
<html ng-app="arsipApp"><head>
<title>Aplikasi Web Arsip</title>
<script src="libs/js/angular.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css" integrity="sha384-PsH8R72JQ3SOdhVi3uxftmaW6Vc51MKb0q5P2rRUpPvrszuE4W1povHYgTpBfshb" crossorigin="anonymous">
</head>

Atau apabila aplikasi web kita sudah kita letakkan pada server dan sudah terkoneksi dengan jaringan Internet maka kita bisa memanfaatkan layanan CDN:
<!doctype html>
<html ng-app="arsipApp"><head>
<title>Aplikasi Web Arsip</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.6/angular.min.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css" integrity="sha384-PsH8R72JQ3SOdhVi3uxftmaW6Vc51MKb0q5P2rRUpPvrszuE4W1povHYgTpBfshb" crossorigin="anonymous">
</head>

Pada kode di atas saya juga me-link file HTML dengan framework CSS Bootstrap agar tampilan aplikasi web sedikit lebih nyaman dilihat.

Frontend static


Bagi teman-teman yang sudah menggunakan aplikasi web Gmail atau Google Mail maka akan melihat bahwa Google membangun antarmukanya dengan menggunakan Javascript yang kemungkinan juga merupakan cikal bakal dari lahirnya framework AngularJS ini. AngularJS menganut prinsip MVW (Model-View-Whatever), dimana file HTML merupakan View (tampilan) dan kode Javascript yang mengandung logika aplikasi dan model (controller). Untuk contoh aplikasi web yang saya buat untuk artikel ini saya akan membuat aplikasi web untuk pendataan Arsip sederhana. Untuk melihat cara kerja dari AngularJS ada baiknya kita coba dengan menggunakan halaman web sederhana yang menggunakan data tidak permanen (data tidak disimpan secara permanen ke backend). Buatlah sebuah file HTML dengan nama index.html dan isikan dengan kode HTML berikut:


index.html


<!doctype html>
<html ng-app="arsipApp">
<head>
<title>Aplikasi Web Arsip</title>
<script src="libs/js/angular.min.js"></script>
<script src="controllers/arsip.js"></script>
<link rel="stylesheet" type="text/css" href="libs/bootstrap/css/bootstrap.min.css" />
</head>
<body>
<div class="container">
<h2>Aplikasi Arsip</h2>
<hr/>
<div ng-controller="arsipController as arsip">
<input type="text" ng-model="arsip.cari" class="form-control" style="border-radius: 50px;" placeholder="Masukkan kata kunci untuk mencari" />
<hr/>
<h5>Tambah Data Arsip</h5>
<form name="formArsip" ng-submit="arsip.tambah()">
<div class="row">
<div class="col">
<input type="text" ng-model="arsip.inputKode" class="form-control" placeholder="Kode arsip" required />
</div>
<div class="col">
<input type="text" ng-model="arsip.inputJudul" class="form-control" placeholder="Judul arsip" required />
</div>
<div class="col">
<input class="btn btn-primary" type="submit" value="Tambah" ng-disabled="formArsip.$invalid">
</div>
</div>
</form>
<hr/>
<div class="alert alert-info">Jumlah total arsip {{arsip.total()}}</div>
<table class="table table-bordered table-striped">
<thead>
<tr><th>Kode</th><th>Judul</th><th> </th></tr>
</thead>
<tbody>
<tr ng-repeat="data in arsip.data | filter:arsip.cari track by data.kode">
<td>{{data.kode}}</td>
<td>{{data.judul}}</td>
<td><button type="button" class="btn btn-danger" ng-click="arsip.hapus(data.kode)">Hapus</button></td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>


Buatlah sebuah direktori baru dengan nama controllers, dan didalam direktori baru ini buatlah sebuah file Javascript bernama arsip.js. Isikan file tersebut dengan kode berikut:



controllers/arsip.js


/**
* Modul "arsipApp"
* Controller "arsipController"
*/
angular.module('arsipApp', []).controller('arsipController', function() {
// variabel "arsip" merujuk kepada objek/instance dari "arsipController"
var arsip = this;

// controller "arsipController" memiliki property/anggota "data" untuk menampung data arsip
arsip.data = [];

// metode "tambah" untuk menambahkan data arsip
arsip.tambah = function() {
arsip.data.push({kode: arsip.inputKode, judul:arsip.inputJudul});
arsip.inputJudul = '';
arsip.inputKode = '';
};

// metode "hapus" untuk menghapus data arsip terpilih
arsip.hapus = function() {
var konf = confirm('Yakin akan menghapus data ini?');
if (konf) {
arsip.data.splice(this.$index, 1);
}
};

// metode "total" untuk mendapatkan jumlah total data arsip
arsip.total = function() {
var count = arsip.data.length;
return count;
};
});


Pada kode HTML index.html coba perhatikan pada atribut tag yang saya berikan warna kuning, atribut-atribut tersebut adalah atribut spesifik AngularJS atau biasa juga disebut directive. Atribut ng-app contohnya menandakan bahwa halaman web ini menggunakan modul arsipApp yang kita definisikan pada file controllers/arsip.js, sedangkan atribut ng-controller menetapkan bahwa semua yang berada di dalam scope atau cakupan dari tag tersebut bisa menggunakan controller arsipController yang instance/objek-nya bernama arsip sebagaimana tertulis arsipController as arsip. Atribut ng-repeat kita gunakan untuk melakukan iterasi/loop data. Atribut ng-model mengikat (binding) tag tersebut ke properti yang namanya didefinisikan di dalamnya. Atribut ng-click, ng-submit merupakan atribut terkait event yang terjadi pada browser, dimana nilai atribut-atribut ini biasanya memanggil metode-metode yang sudah kita definisikan pada controller arsipController. Adapun untuk menampilkan nilai (value) dari suatu variabel Javascript pada AngularJS kita menggunakan ekspresi {{namaVariabel}}. Apabila kita buka file index.html pada browser maka kita akan melihat tampilan seperti berikut ini:





Coba isikan beberapa data arsip untuk melihat hasilnya.



Frontend Dinamis dengan Backend server


Sayangnya pada contoh aplikasi yang kita buat sebelumnya, data arsip yang kita buat tidaklah permanen karena aplikasi sebenarnya hanya berjalan di sisi client saja (browser), sehingga ketika browser kita tutup maka data arsip yang sudah kita masukkan hilang. Agar kita bisa menyimpan data arsip secara permanen maka kita harus menggunakan backend server, salah satunya dengan menggunakan PHP. Kita bisa juga menggunakan solusi penyimpanan data cloud seperti Firebase atau Google Cloud. Untuk contoh kali ini kita akan membuat backend sendiri dengan menggunakan PHP dan database SQLite. Buatlah sebuah folder pada direktori web server dengan nama testws dan di dalamnya buatlah file PHP dengan nama index.php, db.php, post.php dan sebuah direktori kosong dengan nama db (sebagai tempat file database SQLite_. Isikan file index.php dengan kode sebagai berikut:



htdocs/testws/db.php


<?php
// koneksi ke database SQLite3
try {
$pdo = new PDO('sqlite:./db/arsip.sq3', null, null, array(PDO::ATTR_PERSISTENT => true));
} catch(Exception $e) {
$error = array('error' => 'Gagal terkoneksi ke database karena '.$e);
// tampilkan data dalam format json
header('Access-Control-Allow-Origin: *');
header('Content-type: application/json');
echo json_encode($error); die();
}

// buat tabel apabila belum ada
$table_def = 'CREATE TABLE IF NOT EXISTS arsip (kode VARCHAR PRIMARY KEY, judul VARCHAR NOT NULL)';
$create = $pdo->exec($table_def);
if ($create === false) {
$error = array('error' => 'Error ketika membuat tabel!');
// tampilkan data dalam format json
header('Access-Control-Allow-Origin: *');
header('Content-type: application/json');
echo json_encode($error); die();
}


Script PHP index.php melakukan koneksi ke database SQLite dengan nama arsip.sq3 dan membuat tabel arsip apabila belum ada sebelumnya.



htdocs/testws/index.php


<?php
// koneksi ke database SQLite3
require 'db.php';

// ambil data
$json = array();
$select_str = 'SELECT * FROM arsip';

// filter data berdasarkan kata kunci pencarian
$filter = filter_input(INPUT_GET, 'katakunci');
if ($filter) {
$select_str .= " WHERE kode LIKE '$filter%' OR judul LIKE '%$filter%'";
}
$query_data = $pdo->query($select_str);
while ($row = $query_data->fetch(PDO::FETCH_ASSOC)) {
$json[] = $row;
}

// tampilkan data dalam format json
header('Access-Control-Allow-Origin: *');
header('Content-type: application/json');
echo json_encode($json); die();


Script PHP index.php menampilkan data dalam format JSON.



htdocs/testws/post.php


<?php
// koneksi ke database SQLite3
require 'db.php';

// masukkan data
$post_data = file_get_contents('php://input');
$input = json_decode($post_data);
if (is_object($input)) {
$sth = $pdo->prepare('REPLACE INTO arsip VALUES (:kode, :judul)');
$data = array(':kode' => $input->kode, ':judul' => $input->judul);
$sth->execute($data);

$json = array('status' => 'sukses');
} else {
$json = array('status' => 'gagal');
}

// tampilkan data dalam format json
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: *');
header('Access-Control-Allow-Methods: POST');
header('Content-type: application/json');
echo json_encode($json); die();


Script PHP post.php menerima data dalam format JSON melalui front end AngularJS untuk dimasukkan ke database SQLite.




htdocs/testws/delete.php


<?php
// koneksi ke database SQLite3
require 'db.php';

// masukkan data
$kode_delete = file_get_contents('php://input');;
if (!empty($kode_delete)) {
$sth = $pdo->prepare('DELETE FROM arsip WHERE kode=:kode');
$data = array(':kode' => $kode_delete);
$sth->execute($data);

$json = array('status' => 'sukses');
} else {
$json = array('status' => 'gagal');
}

// tampilkan data dalam format json
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: *');
header('Access-Control-Allow-Methods: DELETE');
header('Content-type: application/json');
echo json_encode($json); die();


Script PHP delete.php menghapus record arsip pada database SQLite sesuai dengan kode yang dikirim melalui front end AngularJS. Kita juga harus mengubah kode controller Javascript kita pada file arsip.js agar menggunakan service $http yang disediakan oleh AngularJS untuk melakukan request AJAX ke backed server PHP yang sudah kita buat.



controllers/arsip.js


/**
* Modul "arsipApp"
* Controller "arsipController"
*/
angular.module('arsipApp', []).controller('arsipController', function($scope, $http) {
// variabel "arsip" merujuk kepada objek/instance dari "arsipController"
var arsip = this;

// controller "arsipController" memiliki property/anggota "data" untuk menampung data arsip
arsip.data = [];
// ambil data arsip dari server
$http.get('http://localhost/testws/index.php').then(function(response) {
arsip.data = response.data;
});

// metode "tambah" untuk menambahkan data arsip
arsip.tambah = function() {
var baru = {kode:arsip.inputKode, judul:arsip.inputJudul};
var updateIndex = arsip.data.findIndex(function(obj) {
return obj.kode == arsip.inputKode;
});
$http.post('http://localhost/testws/post.php', angular.toJson(baru))
.then(function() {
if (updateIndex > -1) {
arsip.data[updateIndex].kode = arsip.inputKode;
arsip.data[updateIndex].judul = arsip.inputJudul;
} else {
arsip.data.push(baru);
}
arsip.inputJudul = '';
arsip.inputKode = '';
}, function() {
alert('Data gagal dimasukkan ke database');
});
};

// metode "hapus" untuk menghapus data arsip terpilih
arsip.hapus = function(kode) {
var deleteIndex = arsip.data.findIndex(function(obj) {
return obj.kode == kode;
});
var konf = confirm('Yakin akan menghapus data ini?');
if (konf) {
$http.delete('http://localhost/testws/delete.php', {data: kode})
.then(function() {
arsip.data.splice(deleteIndex, 1);
}, function() {
alert('Data gagal dihapus ke database');
});
}
};

// metode "ubah" untuk mengubah data arsip
arsip.ubah = function(kode) {
var ubahIndex = arsip.data.findIndex(function(obj) {
return obj.kode == kode;
});
console.log(arsip.inputKode);
arsip.inputJudul = arsip.data[ubahIndex].judul;
arsip.inputKode = arsip.data[ubahIndex].kode;
};

// metode "total" untuk mendapatkan jumlah total data arsip
arsip.total = function() {
var count = arsip.data.length;
return count;
};
});


Pada kode view index.html kita ubah sedikit kode HTML pada bagian tag table menjadi seperti berikut ini:



index.html


...
<table class="table table-bordered table-striped">
<thead>
<tr><th>Kode</th><th>Judul</th><th> </th><th> </th></tr>
</thead>
<tbody>
<tr ng-repeat="data in arsip.data | filter:arsip.cari track by data.kode">
<td>{{data.kode}}</td>
<td>{{data.judul}}</td>
<td><button type="button" class="btn btn-info" ng-click="arsip.ubah(data.kode)">Ubah</button></td>
<td><button type="button" class="btn btn-danger" ng-click="arsip.hapus(data.kode)">Hapus</button></td>
</tr>
</tbody>
</table>
...




Dengan menggunakan kode baru ini maka aplikasi web AngularJS kita telah menggunakan data real-time ke server backend menggunakan PHP dan database SQLite, silahkan dicoba untuk memasukkan data, menghapus dan mengubah data. Selamat coding dan mencoba 😁.