This page needs JavaScript activated to work correctly !

This page will be redirect in 3 second !

Aplikasi CRUD Sederhana menggunakan PHP, MySQLi, dan Vue.js - Programming | IDRaya.com

Aplikasi CRUD Sederhana menggunakan PHP, MySQLi, dan Vue.js

Triawan PROGRAMMING 21/11/2023 0 Discuss 1.6K Views

Pembuatan aplikasi sederhana ini bertujuan untuk memberikan pengetahuan dan pengalaman bagaimana mengintegrasikan back-end dan front-end menggunakan PHP, MySQLi, dan Vue.js dalam membangun aplikasi Web dinamis. Namun penekanannya sendiri yaitu ke penggunaan framework Vue.js dalam berinteraksi dengan back-end maupun front-end untuk melakukan operasi CRUD (Create, Read, Update, dan Delete) sebagai user interface (UI) dan single-page application (SPA).

Directive dan Binding

Fungsi utama Vue.js terkait dengan rendering serta melakukan composition komponen (membuat fungsi atau variabel) dalam menangai SPA yang akan diterapkan kedalam directive dan binding. Oleh karen itu, jika tidak mengetahui kedua hal ini, maka tidak akan dapat membuat aplikasi Web menggunakan framework Vue.js.

Pada Vue.js, penggunaan istilah directive dapat diartikan sebagai cara menghubungkan atau mengikat (binding) data antara layer model (M)--melalui DOM--dengan layer view (V)--melalui variabel/fungsi--atau mudahnya metode untuk menghubungkan objek Vue.js (JavaScript) dengan dokumen HTML yang diterapkan/dipanggil melalui atribut atau kedalam elemen tag HTML dengan tujuan untuk memanipulasi Web Page itu sendiri.

Pada Vue, terdapat dua jenis binding untuk menghubungkan data model dengan tampilan.

  1. One-way Binding (satu arah): Data dari model dipetakan ke tampilan/view (MV) menggunakan direktif seperti {{ }} atau v-bind.
  2. Two-way Binding/ (dua arah): Perubahan di model mempengaruhi tampilan/view dan sebaliknya (MVVM) dengan menggunakan v-model.

Berikut ini beberapa directive Vue.js yang dapat digunakan beserta fungsinya.

  1. Directive Data Binding: v-bind, v-model, v-html, v-text, v-once
  2. Directive Conditional Rendering: v-if, v-else, v-else-if
  3. Directive Perulangan: v-for
  4. Directive Event: v-on

Berikut ini source code yang disimpkan kedalam file directive-bind.html, sebagai contoh penerapan directive-binding pada Vue.js secara sederhana.


<!DOCTYPE html>
<html>
<head>
   <title>Vue.js: Directive-Bind</title>
   <link rel="icon" type="image/x-icon" href="https://idraya.com/favicon.ico">
   <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
   <script src="https://cdn.jsdelivr.net/npm/axios@1.1.2/dist/axios.min.js"></script>
</head>
<body>
   <div id="app" style="padding: 45px;">
      <label>One-way Binding:</label><br>
      <input type="text" v-bind:value="message_one">
      <span>{{ message_one }}</span>
      <br><br>
      <label>Two-way Binding:</label><br>
      <input type="text" v-model="message_two">
      <span>{{ message_two }}</span>
   </div>
   
   <script type="text/javascript">
      var app = new Vue({
         el: '#app',
         data: {
            message_one: 'Hello World!',
            message_two: 'Hello World!'
         }
      });
   </script>
</body>
</html>

Berikut ini luaran dari source code diatas untuk melihat perbedaan antara One-way dengan Two-way binding pada Web Browser.

Directive-Binding One-Way Two-Way Binding Vue.js One-way Vs Two-way Binding

Contoh pada elemen html <input type="text" v-bind:value="message_one"> untuk mengaitkan atribut value (serbagai argumen) dengan nilai dari properti message_one dalam model Vue.js satu arah. Sementara <input type="text" v-bind:value="message_two"> mengaitkan input dengan data model dua arah.

Luaran pada Web Browser terlihat ketika mengubah nilai inputan Two-way, maka nilai inputan One-way akan kembali ke awal. Hal ini karena Vue.js bersifat reaktif, yaitu setiap elemen yang dijadikan objek Vue.js dapat menjadi triger/pemicu, sehingga properti data variable message_one dipanggil kembali. Untuk memastikan bahwa inputan One-way tidak ikut berubah (memastikan hanya satu kali perubahan), dapat menambahkan direktif v-once, contoh <input type="text" v-bind:value="message_one" v-once>.

Aplikasi CRUD

Aplikasi Web sederhana ini memiliki fungsi untuk menambahkan (create) data berupa data Mahasiswa yang terdiri dari data: Nama Lengkap (Full name), Nama Panggilan (Nickname), dan data Program Studi (Program). Selain untuk menambahkan  dan menampilkan (read) data, aplikasi Web ini dapat merubah (update) dan menghapus (delete) data Mahasiswa.

Projek ini dapat dikatakan lanjutan dari projek sebelumnya, untuk itu terlebih dahulu membuat folder misal dengan nama crud-student pada sub folder C:\xampp\htdocs\ (Direktori XAMPP pada OS Windows).

Aplikasi Vue.js yang dibangun ini menggunakan library axios untuk interaksi antara Front-end dan Back-end melalui HTTP client berbasis promise (memanfaatkan aync dan await untuk menangai aliran data yang tidak sinkron) sebagai API aplikasi.


1). front-end

Berikut ini source-code front-end yang terdiri dari file index.php, dan style.css. Secara garis besar skrip ini berfungsi untuk mengatur bagaimana suatu data akan ditampilkan pada halaman Web.

Berikut Source code file index.php


<!DOCTYPE html>
<html>
<head>
   <title>Student Biodata Information</title>
   <link rel="icon" type="image/x-icon" href="https://idraya.com/favicon.ico">
   <link rel="stylesheet" type="text/css" href="style.css">
   <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
   <script src="https://cdn.jsdelivr.net/npm/axios@1.1.2/dist/axios.min.js"></script>
</head>
<body>
   <div id="student" class="container">

      <div id="app-header" style="text-align: justify;">
         <h2 class="title" style="text-align: center;"><a href="index.php" style="text-decoration: none;">Faculty of Science and Technology (FTS)</a></h2>
         <p class="lead">Below is a list of science and technology faculty students consisting of several study programs, namely: Statistics, Mathematics, Biology, Food Technology, Agribusiness, Regional and City Planning, and Information Systems.</p> 
      </div>
      <hr><br>

      <div id="student-form">
         <form id="studentForm" action="javascript:void(0);" method="post">
            <input type="hidden" id="_identity" name="_identity" v-bind:value="student._identity" v-once>

            <label for="identity">Identity:</label>
            <input type="text" id="identity" name="identity" v-model:value="student.identity" autocomplete="off" placeholder="0123456789" required>

            <label for="fullName">Full Name:</label>
            <input type="text" id="fullName" name="fullName" v-model:value="student.fullname" autocomplete="off" placeholder="Nauzan Khalid" required>

            <label for="nickname">Nickname:</label>
            <input type="text" id="nickname" name="nickname" v-model:value="student.nickname" autocomplete="off" placeholder="Nau" required>

            <label for="program">Program:</label>
            <select name="program" id="program" v-on:change="onChange" v-model:value="student.program" required>
               <option value="">Choose...</option>
               <option value="statistics">Statistics</option> 
               <option value="mathematics">Mathematics</option> 
               <option value="biology">Biology</option> 
               <option value="food technology">Food Technology</option> 
               <option value="agribusiness">Agribusiness</option> 
               <option value="regional and city planning">Regional And City Planning</option> 
               <option value="information systems">Information Systems</option>
            </select>

            <div class="btn-group" v-if="edit">
               <input type="reset" value="Cancel" v-on:click="edit = false">
               <input type="submit" value="Update" v-on:click="updateStudent">
            </div>
            <div class="btn-group" v-else>
               <input type="reset" value="Reset">
               <input type="submit" value="Add" v-on:click="addStudent">
            </div>
   
         </form>
      </div>
      <br><hr><br>
      
      <div id="student-data" v-if="payload != null && payload.length > 0">
         <h2>Student Data</h2>
         <table>
            <tr>
               <th style="text-align: left;">No.</th>
               <th style="text-align: left;">#Identity</th>
               <th style="text-align: center;">Action</th>
            </tr>

            <tr v-for="(student, index) in payload">
               <td style="text-align: left;"><b>{{  index + 1 }}</b></td>
               <td style="text-align: left;">
                  <ul>
                     <li><b>{{ student.identity }}</b>: {{ student.fullname }} ({{ student.nickname }})</li>
                     <li>{{ ucFirstWord(student.program) }}</li>
                  </ul>  
               </td>
               <td style="text-align: center;">
                  <a href="javascript:void(0);" v-on:click="editStudent(student.identity);">Edit</a> | <a href="javascript:void(0);" v-on:click="deleteStudent(student.identity);">Delete</a>
               </td>
            </tr>

         </table>
      </div>
      <div id="log" v-else>
         <label for="log">Log</label>
         <textarea style="resize: none; width: 100%; height: 64px;">{{ log }}</textarea>
      </div>
      <br>

   </div>

   <script type="text/javascript">
   // instance of vue
   var app = new Vue({
      el: '#student',
      data: {
         log: 'You loaded this page on ' + new Date().toLocaleString(),
         payload: [{}],
         student: { 
            _identity: '',
            identity: '', 
            fullname: '',
            nickname: '',
            program: ''
         },
         edit: false
      },

      mounted: function() {
         this.getAllStudents();
      },
      methods: {

         getAllStudents: function() {
            axios.get('api.php').then(function (response) {
               // handle success
               // console.log(response.data);
               if(response.data.hasOwnProperty('log')) {
                  app.log = response.data.log;
               } 
               if(response.data.hasOwnProperty('payload')) {
                  app.payload = response.data.payload;
               }
            }).catch(function (error) {
               // handle error
               console.log(error);
            });
         },

         addStudent: function(e) {
            e.preventDefault();
            
            let studentForm = app.toFormData(app.student);

            if(app.formValidation()) {
               axios.post('api.php?crud=add', studentForm).then(function (response) {
                  console.log(response);
                  app.getAllStudents();
                  app.student._identity = '';
                  app.student.identity = '';
               }).catch(function (error) {
                  console.log(error);
               });
            }

         },

         deleteStudent: function(identity) {
            let sure = confirm('Are you sure to delete: ' + identity + "?");
            let studentForm = new FormData();
            studentForm.append('identity', identity);
            if(sure == true) {
               axios.post('api.php?crud=delete', studentForm).then(function (response) {
                  console.log(response);
                  app.getAllStudents();
               }).catch(function (error) {
                  console.log(error);
               });
            }
         },

         editStudent: function(identity) {
            let sure = confirm('Are you sure to edit: ' + identity + "?");
            let studentForm = new FormData();
            studentForm.append('identity', identity);
            if(sure == true) {
               axios.post('api.php?crud=edit', studentForm).then(function (response) {
                  console.log(response.data.payload);

                  app.edit = true;

                  let obj = response.data.payload;
                  app.student._identity = obj.identity;
                  app.student.identity = obj.identity;
                  app.student.fullname = obj.fullname;
                  app.student.nickname = obj.nickname;
                  app.student.program = obj.program;

               }).catch(function (error) {
                  console.log(error);
               });
            }
         },

         updateStudent: function(e) {
            e.preventDefault();
            let sure = confirm('Are you sure to update this data?');
            let studentForm = app.toFormData(app.student);

            if(sure == true) {
               if(app.formValidation()) {
                  axios.post('api.php?crud=update', studentForm).then(function (response) {
                     console.log(response);
                     
                     app.edit = false;
                     app.getAllStudents();

                     app.student._identity = '';
                     app.student.identity = '';
                     app.student.fullname = '';
                     app.student.nickname = '';
                     app.student.program = '';
                     
                  }).catch(function (error) {
                     console.log(error);
                  });
               }
            }

         },

         formValidation: function() {
            
            if(!app.student.identity) {
               alert('Identity required!');
            } else if(!app.student.fullname) {
               alert('Fullname required!');
            } else if(!app.student.nickname) {
               alert('Nickname required!');
            } else if(!app.student.program) {
               alert('Program required!');
            } else {
               return true;
            }

         },

         onChange: function(e) {
            console.log(event.target.value);
         },

         toFormData: function(obj) {
            let form_data = new FormData();
            for(let key in obj) {
               form_data.append(key, obj[key]);
            }
            return form_data;
         },

          ucFirstWord: function(str) {
            if(typeof str === 'string') {
               return str.split(" ").map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
            }
         }

      }

   });
</script>
</body>
</html>

Berikut Source code file style.css


body {
   font-family: Arial, sans-serif;
   background-color: #f0f0f0;
   margin: 0;
   padding: 0;
}

.container {
   max-width: 600px;
   height: 100%;
   margin: 0 auto;
   background-color: #ff88;
   padding: 20px;
   border-radius: 5px;
   box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
}

h1 {
   color: #333;
   text-align: center;
   margin-top: 0;
   padding-bottom: 5px;
   border-bottom: 1px solid #888;
}

h3 {
color: #333;
margin-top: 20px;
}

form {
   display: flex;
   flex-wrap: wrap;
   justify-content: space-between;
}

label {
   width: 45%;
   margin-bottom: 10px;
   font-weight: bold;
}


select {
   width: 48.75%;
   padding: 10px;
   border: 1px solid #ccc;
   border-radius: 3px;
   margin-bottom: 15px;
}

input[type="text"] {
   width: 45%;
   padding: 10px;
   border: 1px solid #ccc;
   border-radius: 3px;
   margin-bottom: 15px;
}

.btn-group {
   width: 100%;
}

input[type="submit"], input[type="reset"] {
   padding: 10px;
   border: none;
   border-radius: 3px;
   cursor: pointer;
   color: #f0f0f0;
   font-weight: bold;
}

input[type="submit"] {
   float: right;
   width: 65%;
   background-color: #007BFF;
}
input[type="submit"]:hover {
   background-color: #0056b3;
}

input[type="reset"] {
   width: 25%;
   background-color: #ff000c;
}
input[type="reset"]:hover {
   background-color: #ff0081;
}

textarea {
   margin-top: 10px;
   background-color: #ccc;
}

table {
   font-family: arial, sans-serif;
   border-collapse: collapse;
   width: 100%;
}

td, th {
   border: 1px solid #000000;
   text-align: left;
   padding: 8px;
}

tr:nth-child(odd) {
   background-color: #ffffff;
}

tr:nth-child(even) {
   background-color: #f2f2f2;
}
   
tr:hover {background-color: #ddd;}


ul {
   padding-left: 20px;
}


2). Back-end

Berikut ini source-code back-end yang hanya terdiri dari satu file api.php. Secara garis besar skrip ini ditulis menggunakan bahasa pemrograman PHP berfungsi untuk berinteraksi dengan database MySQLi menggunakan pendekatan OOP (object oriented programming).


<?php
mysqli_report(MYSQLI_REPORT_STRICT);

$servername = "localhost";
$username = "root";
$password = "";
$dbname = "db_fst";

$output = array('log' => null, 'payload' => null);

// to check database connection
try { 
   $conn = new mysqli($servername, $username, $password);
   $sql = 'CREATE DATABASE IF NOT EXISTS ' . $dbname;
   $conn->query($sql);
   $conn->close();
} catch (\Exception $e) {
   $output['log'] = $e->getMessage();
   header("Content-type: application/json");
   echo json_encode($output);
   die();
} 


try { // to check table
   $conn = new mysqli($servername, $username, $password, $dbname);
   $sql = "CREATE TABLE IF NOT EXISTS t_student (
      identity INT(12) NOT NULL,
      fullname VARCHAR(48) NOT NULL,
      nickname VARCHAR(24) NOT NULL,
      program VARCHAR(64) NOT NULL,
      PRIMARY KEY(identity)
   ) ENGINE=InnoDB;";
   $conn->query($sql);
   $conn->close();
} catch (\Exception $e) {
   $output['log'] = $e->getMessage();
   header("Content-type: application/json");
   echo json_encode($output);
   die();
}

// to crud operation

$crud = "read";
if(isset($_GET['crud'])) {
   $crud = $_GET['crud'];
}

if($crud == "read") {

   try {
      $conn = new mysqli($servername, $username, $password, $dbname);
      $sql = "SELECT identity, fullname, nickname, program 
               FROM t_student 
               ORDER BY identity DESC";

      $query = $conn->query($sql);
      $student = array();
      while($row = $query->fetch_array()){
         array_push($student, $row);
      }
      $output['payload'] = $student;
      $conn->close();
      header("Content-type: application/json");
      echo json_encode($output);
      die();
   } catch (\Exception $e) {
      $output['log'] = $e->getMessage();
      header("Content-type: application/json");
      echo json_encode($output);
      die();
   }

} else if($crud == "add") {

   try {
      $identity = htmlspecialchars(trim($_POST['identity']));
      $fullname = htmlspecialchars(trim($_POST['fullname']));
      $nickname = htmlspecialchars(trim($_POST['nickname']));
      $program = htmlspecialchars(trim($_POST['program']));

      $conn = new mysqli($servername, $username, $password, $dbname);   
      $sql = "INSERT INTO t_student(identity, fullname, nickname, program) 
               VALUES('$identity', '$fullname', '$nickname', '$program')";
   
      $conn->query($sql);
      $conn->close();
      die();
   } catch (\Exception $e) {
      $output['log'] = $e->getMessage();
      header("Content-type: application/json");
      echo json_encode($output);
      die();
   }
   
} else if($crud == "delete") {

   try {
      $identity = htmlspecialchars(trim($_POST['identity']));
      $conn = new mysqli($servername, $username, $password, $dbname);   
      $sql = "DELETE FROM t_student WHERE identity = '$identity'";
      $conn->query($sql);
      $conn->close();
      die();
   } catch (\Exception $e) {
      $output['log'] = $e->getMessage();
      header("Content-type: application/json");
      echo json_encode($output);
      die();
   }

} else if($crud == "edit") {

   try {
      $identity = htmlspecialchars(trim($_POST['identity']));
      $conn = new mysqli($servername, $username, $password, $dbname);
      $sql = "SELECT identity, fullname, nickname, program 
               FROM t_student 
               WHERE identity = '$identity'";

      $student = $conn->query($sql);
      $output['payload'] = $student->fetch_assoc();
      $conn->close();
      header("Content-type: application/json");
      echo json_encode($output);
      die();
   } catch (\Exception $e) {
      $output['log'] = $e->getMessage();
      header("Content-type: application/json");
      echo json_encode($output);
      die();
   }

} else if($crud == 'update') {

   try {
      $_identity = htmlspecialchars(trim($_POST['_identity']));
      $identity = htmlspecialchars(trim($_POST['identity']));
      $fullname = htmlspecialchars(trim($_POST['fullname']));
      $nickname = htmlspecialchars(trim($_POST['nickname']));
      $program = htmlspecialchars(trim($_POST['program']));

      $conn = new mysqli($servername, $username, $password, $dbname);   
      $sql = "UPDATE t_student 
               SET identity = '$identity', 
                  fullname = '$fullname', 
                  nickname = '$nickname', 
                  program = '$program'
               WHERE identity = '$_identity'";
   
      $conn->query($sql);
      $conn->close();
      die();
   } catch (\Exception $e) {
      $output['log'] = $e->getMessage();
      header("Content-type: application/json");
      echo json_encode($output);
      die();
   }

}

3). Demo Aplikasi

Berikut demonstrasi aplikasi CRUD sederhana berdasarkan source code diatas (back-end dan front-end). Mudahnya untuk menjalankan aplikasi Web ini, cukup lakukan copy-paste dan simpan kedalam file dengan nama yang sesuai: index.php, style.css, dan api.php. Kemudian jalankan Webserver.

Pada XAMPP untuk mengakses database MySQL melalui alamat http://localhost/phpmyadmin. Untuk database beserta tabel demo aplikasi, akan terbentuk otomatis, karena didefenisikan melalui skrip pada file api.php. Penjelasan mengenai source code akan dipaparkan saat dikelas.

Kesimpulan

Direktif/Directive secara bahasa diartikan sebagai pengarah, petunjuk, atau perintah. Namun pada Vue.js, directive adalah atribut khusus yang didefenisikan pada elemen html sebagai tempat penunjuk untuk menjalakan perintah/ekpresi JavaScript pada DOM.

Pada Vue, perenderan deklaratif merupakan teknik/metode untuk merender (menghasilkan luaran data) ke DOM secara langsung melalui directive sebagai interpolasi data (mendapatkan/menemukan nilai diatara dua data/lebih).

Agus Triawan/Triawan

 matriawan@gmail.com

Triawan is just an ordinary person, founder idraya[dot]com who just a little bit knows also likes try and error about devices, networks and programming/applications to solve challenges related to information technology.

If there is question, please discuss below. Very welcome and expected to provide corrections, criticisms, and suggestions.


We'll not share/display your email.
Example: Say <b>Hello</b> &lt;?php echo 'World'; ?&gt;
Output: Say Hello <?php echo 'World'; ?>
Words can come true for you, so be wise in speaking.

Be the first :D