Di tutorial ini kita akan bersama-sama membuat proses CRUD pada Angular 8. Pada tutorial ini, yang dibutuhkan adalah Angular versi 8 untuk membuat frontendnya, dan Laravel untuk membuat web servicenya. Tabel yang digunakan adalah mysql, nama database bebas, nama tabel yang akan kita gunakan adalah tabel employee :
1 2 3 4 5 6 7 8 9 10 |
CREATE TABLE `employee` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `first_name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, `last_name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, `email` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, `status` int(11) DEFAULT 1, `created_at` timestamp NULL DEFAULT NULL, `updated_at` timestamp NULL DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; |
Membuat Web Service dengan Laravel
Buat aplikasi laravel baru :
1 |
laravel new api |
Buat tabel employees melalui migration :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateEmployeeTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('employee', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('first_name')->nullable(); $table->string('last_name')->nullable(); $table->string('email')->nullable(); $table->integer('status')->default(1); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('employee'); } } |
Jalankan migrasi.
Buat Employee model :
1 2 3 4 5 6 7 8 9 10 11 |
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Employee extends Model { protected $fillable = ['first_name', 'last_name', 'email']; protected $table = 'employee'; } |
Buat Empl0yeeController.php
1 |
php artisan make:controller EmployeeController --api |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Employee; class EmployeeController extends Controller { /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index() { return Employee::all(); } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { return Employee::create($request->all()); } /** * Display the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function show($id) { return Employee::find($id); } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param int $id * @return \Illuminate\Http\Response */ public function update(Request $request, $id) { $employee = Employee::findOrFail($id); $employee->update($request->all()); return $employee; } /** * Remove the specified resource from storage. * * @param int $id * @return \Illuminate\Http\Response */ public function destroy(Request $request, $id) { $employee = Employee::findOrFail($id); $employee->delete(); return 204; } } |
Buat routes/api.php untuk endpoint API :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?php use Illuminate\Http\Request; /* |-------------------------------------------------------------------------- | API Routes |-------------------------------------------------------------------------- | | Here is where you can register API routes for your application. These | routes are loaded by the RouteServiceProvider within a group which | is assigned the "api" middleware group. Enjoy building your API! | */ Route::get('employees', 'EmployeeController@index'); Route::get('employee/{id}', 'EmployeeController@show'); Route::post('employee', 'EmployeeController@store'); Route::put('employee/{id}', 'EmployeeController@update'); Route::delete('employee/{id}', 'EmployeeController@destroy'); |
Jalankan server, nantinya url ini akan bisa kita buka di http://localhost:8000
1 |
php artisan serve --port=8000 |
Membuat Aplikasi Frontend Dengan Angular 8
Setelah menginstall angular/cli, buat aplikasi angular baru :
1 |
ng new angular-crud |
Jawab yes untuk membuat routing dan pilih SCSS untuk stylingnya.
Install bootstrap dan jquery :
1 |
npm i bootstrap jquery --save |
Install Font Awesome Free :
1 |
npm install --save-dev @fortawesome/fontawesome-free |
Tambahkan style dan script bootstrap serta font awesome pada angular.json
1 2 3 4 5 6 7 8 9 10 |
"styles": [ "node_modules/bootstrap/dist/css/bootstrap.min.css", "src/styles.scss", "node_modules/@fortawesome/fontawesome-free/css/all.min.css" ], "scripts": [ "node_modules/jquery/dist/jquery.min.js", "node_modules/bootstrap/dist/js/bootstrap.min.js", "node_modules/@fortawesome/fontawesome-free/js/all.min.js" ] |
Jalankan angular :
1 |
ng serve |
Untuk mengetes apakah jquery, fontawesome, dan bootstrap udah berhasil di load, modifikasi app.component.html :
1 2 3 4 5 |
<div class="container"> <div class="col-md-12"> <button class="btn btn-primary"><i class="fa fa-plus-circle"></i> Testing</button> </div> </div> |
Serta app.component.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import { Component, OnInit } from '@angular/core'; declare var $; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent implements OnInit { title = 'angular-crud'; ngOnInit() { $(document).ready(() => { alert('jquery test'); }); } } |
Buka browser di localhost:4200 dan apabila sudah muncul alert, icon, dan tombol bootstrap berartik kita berhasil mengaktifkan bootstrap, jquery, dan fontawesome :
Buat file proxy.conf.jsonÂ
Untuk mengambil data dari web server yang kita buat dengan laravel, buat file proxy.conf.json :
1 2 3 4 5 6 7 8 9 10 11 |
{ "/api/*": { "target" : "http://localhost:4444/api", "secure" : false, "logLevel" : "debug", "changeOrigin" : true, "pathRewrite" : { "^/api": "" } } } |
Modifikasi package.json di bagian start :
1 2 3 4 5 6 7 8 |
"scripts": { "ng": "ng", "start": "ng serve --proxy-config proxy.conf.json", "build": "ng build", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e" }, |
Nantinya kita akan mengaktifkan angular dengan perintah :Â npm start
Buat Employee ModelÂ
Buat employee.ts di dalam folder src/app :
1 2 3 4 5 6 7 |
export class Employee { id: number; first_name: string; last_name: string; email: string; status: number; } |
Buat Component
Component yang akan kita buat : create-employee, employee-detail, employee-list, update-employee. Ketikan masing-masing perintah berikut di dalam terminal :
1 2 3 4 |
ng g c create-employee --skipTests=true ng g c update-employee --skipTests=true ng g c employee-list --skipTests=true ng g c employee-detail --skipTest=true |
Buat juga employee.service.ts dengan perintah:
1 |
ng g s employee --skipTests=true |
Modifikasi employee.service.ts untuk mengakomodir api route :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { HttpClient } from '@angular/common/http'; import { Employee } from './employee'; @Injectable({ providedIn: 'root' }) export class EmployeeService { constructor( private http: HttpClient ) { } getEmployees(): Observable<Employee[]> { return this.http.get<Employee[]>('api/employees'); } createEmployee(employee: Employee): Observable<Employee> { return this.http.post<Employee>('api/employee', employee); } getEmployee(id: number): Observable<any> { return this.http.get(`api/employee/${id}`); } updateEmployee(id: number, value: any): Observable<object> { return this.http.put(`api/employee/${id}`, value); } deleteEmployee(id: number): Observable<any> { return this.http.delete(`api/employee/${id}`, { responseType: 'text' }); } } |
app.module.ts
Jangan lupa menambahkan HttpClientModule pada app.module.ts :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { CreateEmployeeComponent } from './create-employee/create-employee.component'; import { EmployeeListComponent } from './employee-list/employee-list.component'; import { UpdateEmployeeComponent } from './update-employee/update-employee.component'; import { HttpClientModule } from '@angular/common/http'; import { EmployeeDetailComponent } from './employee-detail/employee-detail.component'; @NgModule({ declarations: [ AppComponent, CreateEmployeeComponent, EmployeeListComponent, UpdateEmployeeComponent, EmployeeDetailComponent ], imports: [ BrowserModule, AppRoutingModule, HttpClientModule, FormsModule, ], providers: [], bootstrap: [AppComponent] }) export class AppModule { } |
app-routing.module.ts
Kita akan buat app-routing.module.ts di dalam folder app untuk mengatur routing :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { EmployeeListComponent } from './employee-list/employee-list.component'; import { CreateEmployeeComponent } from './create-employee/create-employee.component'; import { UpdateEmployeeComponent } from './update-employee/update-employee.component'; import { EmployeeDetailComponent } from './employee-detail/employee-detail.component'; const routes: Routes = [ { path: '', redirectTo: 'employees', pathMatch: 'full' }, { path: 'employees', component: EmployeeListComponent }, { path: 'add', component: CreateEmployeeComponent }, { path: 'update/:id', component: UpdateEmployeeComponent }, { path: 'details/:id', component: EmployeeDetailComponent }, ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { } |
app.component.htmlÂ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<nav class="navbar navbar-expand-sm bg-primary navbar-dark"> <!-- Links --> <ul class="navbar-nav"> <li class="nav-item"> <a routerLink="employees" class="nav-link" routerLinkActive="active">Employee List</a> </li> <li class="nav-item"> <a routerLink="add" class="nav-link" routerLinkActive="active">Add Employee</a> </li> </ul> </nav> <div class="container"> <br> <h2 style="text-align: center;">{{title}}</h2> <hr> <div class="card"> <div class="card-body"> <router-outlet></router-outlet> </div> </div> </div> |
app.component.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import { Component, OnInit } from '@angular/core'; declare var $; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit { title = 'Angular 8 Crud'; ngOnInit() { } } |
Employee List
employee-list.component.htmlÂ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
<div class="panel panel-primary"> <div class="panel-heading"> <div class="row"> <div class="col-md-8"> <h2>Employee List</h2> </div> <div class="col-md-4 text-right"> <span><a class="btn btn-success" href routerLink="../add" routerLinkActive="active"><i class="fa fa-plus"></i> Add Employee</a></span> </div> </div> </div> <div class="panel-body"> <table class="table table-striped"> <thead> <tr> <th>Firstname</th> <th>Lastname</th> <th>Email</th> <th class="text-center">Actions</th> </tr> </thead> <tbody> <tr *ngFor="let employee of employees"> <td>{{employee.first_name}}</td> <td>{{employee.last_name}}</td> <td>{{employee.email}}</td> <td class="text-center"> <button (click)="deleteEmployee(employee.id)" class="btn btn-danger"><i class="fa fa-trash"></i> Delete</button> <button (click)="updateEmployee(employee.id)" class="btn btn-primary" style="margin-left: 10px"><i class="fa fa-edit"></i> Update</button> <button (click)="employeeDetails(employee.id)" class="btn btn-info" style="margin-left: 10px"><i class="fa fa-info-circle"></i> Details</button> </td> </tr> </tbody> </table> </div> </div> |
employee-list.component.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
import { Component, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; import { Employee } from '../employee'; import { EmployeeService } from '../employee.service'; import { Router } from '@angular/router'; @Component({ selector: 'app-employee-list', templateUrl: './employee-list.component.html', styleUrls: ['./employee-list.component.scss'] }) export class EmployeeListComponent implements OnInit { employees: Employee[]; constructor( private employeeService: EmployeeService, private router: Router ) { } ngOnInit() { this.reloadData(); } reloadData(): void { this.employeeService.getEmployees() .subscribe((response) => { this.employees = response; }); } employeeDetails(id: number) { this.router.navigate(['details', id]); } deleteEmployee(id: number) { this.employeeService.deleteEmployee(id) .subscribe( data => { console.log(data); this.reloadData(); }, error => console.log(error)); } updateEmployee(id: number) { this.router.navigate(['update', id]); } } |
Jalankan npm start :Â
Create Employee
Create Employee bisa dilakukan dengan menekan tombol Add Employee pada Navigation Bar atau pada Employee List :
create-employee.component.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
import { Component, OnInit } from '@angular/core'; import { Employee } from '../employee'; import { EmployeeService } from '../employee.service'; import { Router } from '@angular/router'; @Component({ selector: 'app-create-employee', templateUrl: './create-employee.component.html', styleUrls: ['./create-employee.component.scss'] }) export class CreateEmployeeComponent implements OnInit { employee: Employee = new Employee(); submitted = false; constructor( private employeeService: EmployeeService, private router: Router ) { } ngOnInit() { } newEmployee(): void { this.submitted = false; this.employee = new Employee(); } save() { this.employeeService.createEmployee(this.employee) .subscribe(data => console.log(data), error => console.log(error)); this.employee = new Employee(); this.gotoList(); } onSubmit() { this.submitted = true; this.save(); } gotoList() { this.router.navigate(['/employees']); } } |
create-employee.component.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<h3>Create Employee</h3> <div [hidden]="submitted" style="width: 1060px;"> <form (ngSubmit)="onSubmit()"> <div class="form-group"> <label for="name">First Name</label> <input type="text" class="form-control" id="first_name" required [(ngModel)]="employee.first_name" name="first_name"> </div> <div class="form-group"> <label for="name">Last Name</label> <input type="text" class="form-control" id="last_name" required [(ngModel)]="employee.last_name" name="last_name"> </div> <div class="form-group"> <label for="name">Email</label> <input type="text" class="form-control" id="email" required [(ngModel)]="employee.email" name="email"> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <div [hidden]="!submitted"> <h4>You submitted successfully!</h4> <!-- <button class="btn btn-success" (click)="newEmployee()">Add</button> --> </div> |
Employee Detail
employee-detail.component.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<h2>Employee Details</h2> <hr/> <div *ngIf="employee"> <div> <label><b>First Name: </b></label> {{employee.first_name}} </div> <div> <label><b>Last Name: </b></label> {{employee.last_name}} </div> <div> <label><b>Email Id: </b></label> {{employee.email}} </div> </div> <br> <br> <button (click)="list()" class="btn btn-primary">Back to Employee List</button><br> |
employee-detail.component.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
import { Employee } from '../employee'; import { Component, OnInit, Input } from '@angular/core'; import { EmployeeService } from '../employee.service'; import { EmployeeListComponent } from '../employee-list/employee-list.component'; import { Router, ActivatedRoute } from '@angular/router'; @Component({ selector: 'app-employee-detail', templateUrl: './employee-detail.component.html', styleUrls: ['./employee-detail.component.scss'] }) export class EmployeeDetailComponent implements OnInit { id: number; employee: Employee; constructor( private route: ActivatedRoute, private router: Router, private employeeService: EmployeeService) { } ngOnInit() { this.employee = new Employee(); this.id = this.route.snapshot.params.id; this.employeeService.getEmployee(this.id) .subscribe(data => { this.employee = data; }, error => console.log(error)); } list() { this.router.navigate(['employees']); } } |
Hasilnya :
Update Employee
employee-update.component.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<h3>Update Employee</h3> <div [hidden]="submitted" style="width: 400px;"> <form (ngSubmit)="onSubmit()"> <div class="form-group"> <label for="name">First Name</label> <input type="text" class="form-control" id="firstName" required [(ngModel)]="employee.first_name" name="firstName"> </div> <div class="form-group"> <label for="name">Last Name</label> <input type="text" class="form-control" id="lastName" required [(ngModel)]="employee.last_name" name="lastName"> </div> <div class="form-group"> <label for="name">First Name</label> <input type="text" class="form-control" id="emailId" required [(ngModel)]="employee.email" name="emailId"> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> |
employee-update.component.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
import { Component, OnInit } from '@angular/core'; import { Employee } from '../employee'; import { ActivatedRoute, Router } from '@angular/router'; import { EmployeeService } from '../employee.service'; @Component({ selector: 'app-update-employee', templateUrl: './update-employee.component.html', styleUrls: ['./update-employee.component.scss'] }) export class UpdateEmployeeComponent implements OnInit { id: number; employee: Employee; submitted = false; constructor( private route: ActivatedRoute, private router: Router, private employeeService: EmployeeService) { } ngOnInit() { this.employee = new Employee(); this.id = this.route.snapshot.params.id; this.employeeService.getEmployee(this.id) .subscribe(data => { console.log(data); this.employee = data; }, error => console.log(error)); } updateEmployee() { this.employeeService.updateEmployee(this.id, this.employee) .subscribe(data => console.log(data), error => console.log(error)); this.employee = new Employee(); this.gotoList(); } onSubmit() { this.updateEmployee(); } gotoList() { this.router.navigate(['/employees']); } } |
Delete Employee
Delete employee bisa dilakukan dengan menekan tombol delete pada Employee List: