A BLOG POST
Advisory Program 2022 (Chapter 2) - Integrating Frontend & Backend
Tulisan ini adalah bagian dari serangkaian materi dari Advisory Program BCA, untuk source code nya bisa dilihat di sini.
In Chapter 1, we have successfully created our backend API. Let's make it usable by creating frontend application for the graphical user interface (GUI). The frontend application will be built with Angular as the Javascript framework and Tailwind as the CSS framework.
10/11/2024, 3:03:03 AM
471 times
- Angular
- NodeJS
- Tailwind CSS
- IDE (sesuai preferensi)
Seperti pada materi sebelumnya yakni Chapter 1, di tulisan ini saya tidak menjelaskan mengenai tutorial Angular. Namun apa yang saya jelaskan lebih ke bagaimana implementasi framework tertentu pada aplikasi sederhana dan integrasinya berdasarkan konsep yang dibahas, seperti misalnya model arsitektur BFF (Backend For Frontend).
Hal ini saya tujukan karena materi seperti tutorial-tutorial tersebut sangat mudah fellowdevs dapatkan melalui platform online course seperti Udemy atau bahkan video gratis seperti Youtube. Nyatanya, saya sendiri pun belajar banyak dari platform-platform tersebut. Akan sangat memakan waktu dan tenaga apabila saya berusaha membuat tutorial serupa yang berulang dimana saya sendiri tidak begitu yakin bahwa content yang saya deliver akan lebih baik dari para creator tersebut.
Ditambah lagi, saya ingin berfokus pada hal-hal lain yang lebih diperlukan pada dunia industri profesional. Misalnya seperti desain arsitektur aplikasi, security, common practices, tips & trik, atau bahkan sekedar memperkenalkan tools atau teknologi yang mungkin belum dikenal sebelumnya namun banyak digunakan di pekerjaan nantinya.
Oleh karena itu, saya mendorong fellowdevs peserta program untuk dapat lebih dahulu mempelajari konsep dasar dari stack yang akan digunakan, misalnya seperti mengerti konsep dasar Java, OOP, JavaScript, database, dll. Hal ini akan membantu fellowdevs dalam mengikuti program ini dengan lebih efektif.
Sebagai permulaan, untuk kamu yang belum familiar dengan framework Angular, kamu dapat memulai belajar melalui referensi ini:
Angular - Getting started with Angular
Kalau kalian lebih suka menonton video tutorial, video ini adalah salah satu yang cukup lengkap dan mendasar untuk pemula yang dapat saya rekomendasikan.
Tidak kalah penting juga untuk fellowdevs mengetahui tentang dasar ES6 (ECMAScript 2015) karena untuk mayoritas pemrograman JavaScript hari ini menggunakan versi ES6. Untuk ES6 sendiri, saya merekomendasikan artikel ini:
Untuk dapat memulai pemrograman dengan Angular, kita terlebih dahulu harus menginstall Angular CLI. Dan untuk dapat menginstall Angular CLI, kita harus terlebih dahulu menginstall NodeJS, karena kita membutuhkan Node Package Manager (NPM) di dalamnya.
Untuk menginstall NodeJS, fellowdevs dapat mengacu pada link ini. Saya rekomendasikan untuk menginstall versi LTS (Long Term Support). Setelah selesai menginstall NodeJS, kita dapat memastikannya melalui terminal dengan version check.
sh
1╭─ powershell
2╰─❯ node -v
3v18.12.1
4╭─ powershell
5╰─❯ npm -v
68.19.2
Kemudian langkah selanjutnya adalah menginstall Angular CLI. Sesuai dokumentasinya, kita dapat melakukannya melalui command:
sh
1npm install -g @angular/cli
Apabila sudah selesai, pastikan dengan version check:
sh
1╭─ powershell
2╰─❯ ng --version
3
4 _ _ ____ _ ___
5 / \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
6 / △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | |
7 / ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | |
8 /_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___|
9 |___/
10
11
12Angular CLI: 13.1.2
13Node: 18.12.1 (Unsupported)
14Package Manager: npm 8.19.2
15OS: win32 x64
16
17Angular:
18...
19
20Package Version
21------------------------------------------------------
22@angular-devkit/architect 0.1301.2 (cli-only)
23@angular-devkit/core 13.1.2 (cli-only)
24@angular-devkit/schematics 13.1.2 (cli-only)
25@schematics/angular 13.1.2 (cli-only)
Tenang saja apabila fellowdevs ada yang menggunakan versi seperti saya dan mendapatkan warning seperti berikut:
1Warning: The current version of Node (18.12.1) is not supported by Angular.
Hal ini terjadi karena versi Angular CLI yang saya gunakan adalah versi 13. Sedangkan NodeJS saya versi 18 yang tidak di-support oleh Angular CLI versi tersebut. Support NodeJS 18 hadir pada Angular 15. Namun tidak serta merta bahwa kita tidak dapat melakukan development karena hal ini. Memang saat melakukan build kemungkinan besar akan terjadi error. Namun hal itu akan kita atasi pada Chapter 4.
Kita akan disarankan untuk melakukan update, tapi pada kenyataannya di production, update/upgrade versi stack bukanlah hal sepele yang dapat dilakukan sewaktu-waktu. Malahan tidak jarang perusahaan tidak melakukan update karena khawatir kalau aplikasi mereka malah tidak bisa digunakan karena faktor breaking changes.
Apabila Angular CLI sudah ter-install, maka saatnya untuk kita bisa membuat project Angular. Jalankan command berikut.
sh
1ng new bcaadam-frontend
Tentu penamaan project dapat kalian ganti sendiri sesuai preferensi. Akan ada beberapa pertanyaan yang perlu kita jawab sebelum Angular CLI men-generate project untuk kita. Fellowdevs dapat mengikuti pilihan saya seperti berikut ini.
sh
1╭─ powershell
2╰─❯ ng new bcaadam-frontend
3? Would you like to add Angular routing? Yes
4? Which stylesheet format would you like to use? CSS
5....
Setelah proses generate selesai, kita dapat menjalankan project Angular kita dengan menggunakan command ng serve
atau npm run start
. By default, aplikasi Angular akan berjalan pada port 4200
. Untuk membuat command ini membuka browser secara otomatis, tambahkan parameter --open
menjadi ng serve --open
. Aplikasi Angular kita akan terlihat seperti ini.
Dari hasil generate Angular CLI, project kita terdiri dari beberapa files yang perlu kita pahami dulu fungsi dan kegunaannya.
1.
2├── src
3│ ├── app
4│ │ ├── app-routing.module.ts
5│ │ ├── app.component.spec.ts
6│ │ ├── app.component.css
7│ │ ├── app.component.html
8│ │ ├── app.component.ts
9│ │ └── app.module.ts
10│ ├── assets
11│ ├── favicon.ico
12│ ├── index.html
13│ ├── main.ts
14│ ├── polyfills.ts
15│ ├── environments
16│ │ ├── environment.prod.ts
17│ │ └── environment.ts
18│ └── test.ts
19├── angular.json
20├── package.json
21└── ... any other files that not related to this project
- Seperti halnya project Spring kita, di sini kita juga akan lebih banyak bekerja pada folder
/src/app
. Di dalamnya akan terdapat beberapa files yang akan kita buat untuk project ini main.ts
: Entry point JavaScript fileindex.html
: HTML entry point file/environments
, seperti halnya file.properties
pada project backend API kita, file di dalam folder ini merupakan konfigurasi aplikasi Angular kitaangular.json
, konfigurasi project Angular. This is actually an important file.package.json
, file konfigurasi project, dependency dan instruksi untuk NPM
Sebelum kita memulai ngoding, akan sangat bermanfaat bagi kita untuk mengetahui bagaimana cara kerja framework Angular yang kita gunakan ini, seperti bagaimana Angular memulai prosesnya saat dijalankan. Di lingkungan saya, banyak developer Angular yang handal tapi tidak mengerti proses ini. Nah supaya fellowdevs tidak bernasib sama setelah mengikuti program ini, kita pahami dulu yuk bagaimana Angular berjalan 😁
Pada dasarnya, setiap aplikasi web harus memiliki sebuah HTML entrypoint untuk diakses oleh browser. Pada Angular, HTML entrypoint yang akan diakses adalah file index.html
. Di dalam file ini, browser akan memproses dan me-load file-file yang dibutuhkan, seperti assets, styles, dan tidak terkecuali JavaScript.
index.html
1<!-- index.html -->
2<!DOCTYPE html>
3<html lang="en">
4<head>
5 <meta charset="utf-8">
6 <title>BCA ADAM</title>
7 <base href="/">
8 <meta name="viewport" content="width=device-width, initial-scale=1">
9 <link rel="icon" type="image/x-icon" href="favicon.ico">
10 <link rel="stylesheet" href="styles.09e2c710755k85667a460.css">
11</head>
12<body>
13 <app-root></app-root>
14 <script src="runtime.e227d1a0e31cqwfcbf8ec.js" defer></script>
15 <script src="polyfills.a4021de6744558bb0fec14.js" defer></script>
16 <script src="main.1feaffbe857qpockf7ee0db.js" defer></script>
17</body>
18</html>
File index.html
ini harus memiliki setidaknya satu root component (entry point component), dalam hal ini adalah <app-root></app-root>
. Tentu kita tahu bahwa tag ini bukanlah tag HTML biasa, karena <app-root>
tidak ada dalam kamus HTML. Angular-lah yang bertanggung jawab memproses elemen ini. Di dalam root component inilah Angular akan me-render component-component yang sesuai dengan yang diminta. That's actually end of story. Sedikit membingungkan? Mari kita rewind sedikit.
Apabila fellowdevs bandingkan isi file index.html
kalian dengan snippet saya di atas, maka di file kalian tidak akan ada tag <script></script>
ke file JavaScript yang naming-nya aneh itu. Ya, file dan tag tersebut akan ditambahkan oleh Angular pada saat proses build. Pada saat Angular berjalan, file angular.json
akan digunakan sebagai acuan instruksi dalam menjalankan keseluruhan proses. That's why saya berikan penekanan pada penjelasan project structure bahwa ini adalah file yang penting. Berdasarkan instruksi dari angular.json
ini, Angular akan membangun keseluruhan aplikasi.
Under the hood, Angular menggunakan Webpack sebagai module bundler. Melalui Webpack inilah Angular akan mentransformasikan file-file yang kita buat pada project nanti menjadi JavaScript bundle. Dan kemudian bundle tersebut akan dikirimkan dan di-load melalui browser. Pada saat kita menjalankan perintah build seperti ng build
, Angular akan melakukan compile dan men-generate beberapa file JavaScript untuk kita.
1├── favicon.ico
2├── index.html
3├── main.1feaffbe857aaf7ee0db.js
4├── polyfills.a4021de53358bb0fec14.js
5├── runtime.e227d1a0e31cbccbf8ec.js
6└── styles.09e2c710755c8867a460.css
main.xxxx.ts
adalah segala code yang kita tulispolyfills.xxxx.ts
berisi code polyfills (biasanya konversi code yang lebih baru untuk dapat dijalankan pada browser lama)runtime.xxxx.ts
berisi utility code untuk Webpack
Ketiga script ini akan ditambahkan seperti halnya pada snippet index.html
saya di atas. Sejauh ini kita baru saja membahas mengenai file loading, tapi bagaimana eksekusinya?
Penamaan file yang di-generate ini menggunakan tambahan hash string di belakangnya. Hal ini berguna untuk memastikan bahwa browser perlu melakukan update apabila hash ini berubah. Ya, hash ini akan berubah apabila kita melakukan perubahan bahkan sekedar menambahkan spasi atau mengubah huruf kapital menjadi huruf kecil.
Nah, eksekusi aplikasi Angular juga dimulai dari file konfigurasinya. Dimanakah itu? Ya! File tersebut adalah angular.json
.
json
1// angular.json
2 ....
3 "architect": {
4 "build": {
5 "builder": "@angular-devkit/build-angular:browser",
6 "options": {
7 "outputPath": "dist/bcaadam-frontend",
8 "index": "src/index.html",
9 "main": "src/main.ts",
10 "polyfills": "src/polyfills.ts",
11 "tsConfig": "tsconfig.app.json",
12 "assets": [
13 "src/favicon.ico",
14 "src/assets"
15 ],
16 "styles": [
17 "src/styles.css"
18 ],
19 "scripts": []
20 },
21 ....
Perhatikan pada node architect
- build
, di sana terdapat instruksi pada property main
adalah menunjuk pada file src/main.ts
. Berdasarkan konfigurasi inilah, Angular akan memastikan bahwa module tersebut tereksekusi begitu bundle berhasil ter-load.
Serta property index
merujuk ke src/index.html
yang notabene adalah halaman HTML utama yang sudah kita bahas tadi. Itulah sebabnya browser akan memulai rendering HTML melalui file ini.
Nah setelah kita mengetahui pada file pertama yang sebenarnya disentuh Angular adalah main.ts
(setelah angular.json
), mari kita lihat ada apa di dalam file ini.
typescript
1import { enableProdMode } from '@angular/core';
2import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3
4import { AppModule } from './app/app.module';
5import { environment } from './environments/environment';
6
7if (environment.production) {
8 enableProdMode();
9}
10
11platformBrowserDynamic().bootstrapModule(AppModule)
12 .catch(err => console.error(err));
13
Beberapa import statement terletak di awal file, well ini adalah basic OOP jadi tidak ada yang spesial di sini. Baris selanjutnya adalah pengecekan apakah kondisi saat ini merupakan kondisi production atau bukan. Kondisi ini dicek berdasarkan file environment.ts
yang ada di folder /environment
. Pengecekan ini dilakukan untuk menentukan apakah Angular perlu melakukan performance tweak untuk production built.
Yang terutama adalah pada baris terakhir, yakni:
typescript
1platformBrowserDynamic().bootstrapModule(AppModule);
platformBrowserDynamic
seperti namanya, bertugas untuk membuat platform yang memungkinkan Angular dapat berjalan pada web browser context. Module ini me-load segala yang diperlukan dari komponen-komponen framework dan mengkonfigurasikannya sedemikian rupa. Mengingat bahwa Angular dapat berjalan pada context lain seperti mobile, server-side, etc perlu diketahui juga bahwa ada beberapa cara dalam me-load Angular.
Setelah Angular ter-load oleh platformBrowserDynamic
, perintah selanjutnya adalah melakukan boostrapModule(...)
yang menginstrusikan Angular untuk melakukan boostraping module yang diminta, pada case ini adalah AppModule
. AppModule
adalah salah satu file terpenting dalam aplikasi Angular karena di dalamnya akan kita definisikan segala component, directives, pipes, services dan apapun yang akan digunakan aplikasi. Melalui import statement, Angular dapat mengetahui path dari AppModule
ini, me-load file tersebut dan sesuai perintah tadi, Angular akan mencari bootstrap
option.
typescript
1// app.module.ts
2import { NgModule } from '@angular/core';
3import { BrowserModule } from '@angular/platform-browser';
4
5import { AppRoutingModule } from './app-routing.module';
6import { AppComponent } from './app.component';
7
8@NgModule({
9 declarations: [
10 AppComponent
11 ],
12 imports: [
13 BrowserModule,
14 AppRoutingModule
15 ],
16 providers: [],
17 bootstrap: [AppComponent]
18})
19export class AppModule { }
20
Berdasarkan value dari bootstrap
option ini, maka Angular akan me-load file selanjutnya yaitu AppComponent
dari app.component.ts
.
typescript
1// app.component.ts
2import { Component } from '@angular/core';
3
4@Component({
5 selector: 'app-root',
6 templateUrl: './app.component.html',
7 styleUrls: ['./app.component.css']
8})
9export class AppComponent {
10 title = 'bcaadam-frontend';
11}
Perhatikan value selector
dari definisi component ini, yaitu app-root
. Artinya component ini akan hidup dengan menggunakan tag <app-root></app-root>
. Ring a bell? Yes! Dugaan kalian benar. Dengan di-load nya AppModule
, Angular memiliki semua informasi yang diperlukan aplikasi dan akan me-load segala kebutuhan tersebut, seperti AppComponent
ini. Oleh karena itu, saat browser me-render <app-root>
yang sebenarnya bukan tag HTML yang valid, namun tag tersebut masih dapat dikenali karena Angular-lah yang akan memprosesnya untuk dapat dikonsumsi oleh browser.
Dengan demikian cerita dimulainya aplikasi Angular telah menjadi cerita yang utuh. Dengan memahami konsep dasar ini, saya yakin akan sangat membantu fellowdevs di dalam membangun aplikasi kita nanti.
Pada project kita ini, kita tidak menggunakan native CSS styling, seperti yang biasanya kita lakukan pada pemrograman web. Kita akan menggunakan CSS framework untuk membantu proses styling kita menjadi lebih cepat. Framework yang akan kita gunakan adalah Tailwind CSS. Sekali lagi, untuk mempersingkat konten materi saya juga tidak mengupas secara detil mengenai Tailwind CSS, fellowdevs dapat memulai mempelajarinya di sini.
Nah, untuk mengintegrasikan Tailwind CSS ke project Angular kita dibutuhkan sedikit konfigurasi. Tenang saja, ini bukanlah hal yang ribet. Dokumentasi yang disediakan Tailwind CSS sangat lengkap dan mudah diikuti. Yuk kita lakukan step by step nya.
Pertama, kita perlu install Tailwind CSS terlebih dahulu ke project kita. Cukup jalankan command berikut.
sh
1npm install -D tailwindcss postcss autoprefixer
2npx tailwindcss init
Perintah npx tailwindcss init akan men-generate file bernama tailwind.config.js
di dalam folder project kita. Langkah kedua, kita perlu mengubah path dari source folder Angular project kita yang berada di folder /src
. Hal ini memungkinkan Tailwind CSS untuk mengerti letak file project yang perlu di-transpile olehnya. Selain file .html
, karena Angular by default menggunakan TypeScript, maka kita perlu menambahkan juga file-file .ts
tersebut.
tailwind.config.js
1/** @type {import('tailwindcss').Config} */
2module.exports = {
3 content: [
4 "./src/**/*.{html,ts}",
5 ],
6 theme: {
7 extend: {},
8 },
9 plugins: [],
10}
Ketiga, kita perlu menambahkan directive dari Tailwind CSS pada base style file kita yaitu style.css
. File ini sudah diberikan oleh Angular pada saat proses project generation.
css
1@tailwind base;
2@tailwind components;
3@tailwind utilities;
And that's it! Mari kita coba apakah Tailwind CSS sudah dapat berjalan pada project kita. Buka file app.component.html
dan ganti semua isinya misalnya seperti ini.
html
1<h1 class="text-3xl font-bold underline text-red-500 text-center">
2 Hello world!
3</h1>
Styling yang kita terapkan pada teks Hello world!
sudah berhasil ter-render pada halaman aplikasi kita. Dengan demikian, kita sudah dapat melakukan development dengan menggunakan Tailwind CSS 👍
Bagi yang menggunakan VSCode sebagai IDE, kita dapat menggunakan extension Tailwind CSS Intellisense dari Tailwind Labs untuk memudahkan development.
Kita sudah selangkah lebih dekat ke proses development kita. Last thing yang penting adalah untuk kita mengerti beberapa core concepts dari Angular atau disebut juga Angular Essentials.
Component adalah bagian utama dari Angular. Definisi Angular sendiri adalah component based framework. Ya, framework JavaScript masa kini hampir semuanya mengusung konsep component.
Lalu apa itu component? Mengacu pada dokumentasi resminya, component adalah building block. Karena sedikit aneh kalau diterjemahkan ke Bahasa Indonesia (balok bangunan), ya saya sebut saja component ibarat batu bata dari sebuah rumah. Yang artinya, ini adalah barang wajib di sebuah aplikasi Angular. Hampir semua bagian dalam Angular adalah component. Tapi selayaknya batu bata, tentu dapat kita sesuaikan besar/bobot sebuah component tergantung bagaimana kita mendesainnya.
Component dalam Angular ditandai dengan decorator @Component
yang di dalamnya mengandung:
- Component selector, manifestasinya dalam bentuk custom HTML tag seperti
<app-root></app-root>
pada penjelasan sebelumnya. - HTML template, menjelaskan bagaimana sebuah component di-render dalam tag HTML
- CSS untuk styling (opsional)
Paling minimal, sebuah component Angular akan terlihat sebagai berikut.
typescript
1import { Component } from '@angular/core';
2
3@Component({
4 selector: 'hello-world',
5 template: `
6 <h2>Hello World</h2>
7 <p>This is my first component!</p>
8 `
9})
10export class HelloWorldComponent {
11 // The code in this class drives the component's behavior.
12}
Untuk dapat menggunakan component ini, kita akan menggunakan HTML tag <hello-world></hello-world>
sebagaimana ter-define pada value selector
. Cukup sederhana bukan?
Nah, setelah mengetahui bahwa component adalah bagian penting dalam Angular, maka begitu juga dengan Template. Setiap component pasti memiliki sebuah template. Why? Karena melalui template-lah Angular mengerti bagaimana me-render sebuah component menjadi halaman.
Kalau fellowdevs tidak asing dengan istilah ini, artinya kalian menyimak apa yang kita pelajari di Chapter 1 dimana saya menyebutkan mengenai DI pada framework Spring. Faktanya, DI sudah menjadi common practice di dunia pemrograman modern saat ini dan direkomendasikan menjadi cara yang baik dalam menulis code (best practice).
Definisi DI pada dokumentasi Angular sangatlah mudah dimengerti, yakni: cara mendefinisikan sebuah dependency terhadap class lain tanpa peduli bagaimana class tersebut diinisiasi. Hal ini dicapai melalui dependency injector dalam framework seperti Angular atau Spring sehingga framework yang akan melakukan inisiasi object/class tersebut untuk kita. Melalui DI, code kita menjadi lebih testable dan flexible. Di Angular sendiri, DI menjadi lem yang banyak digunakan dan kalian akan sering menemui konsep ini nantinya.
Sebagai penutup bagian ini, link ini adalah tutorial dasar untuk berkenalan dengan framework Angular sudah disediakan secara detil, lengkap dan komprehensif oleh dokumentasi resminya. Banyak sekali konsep Angular yang akan fellowdevs dapatkan dari mengerjakan tutorial ini seperti:
- Directives
- Components
- Data Binding & Two-way Data Binding
- Event Binding
- Pipes
- Services
- Routing
- Bekerja dengan simple forms
Saya sangat menyarankan untuk kalian bisa mencoba mengerjakannya juga untuk lebih mengerti lagi terlebih dari apa yang saya tidak jelaskan di materi ini. So, tunggu apa lagi? Segera pelajari tutorialnya!
Tampilan aplikasi yang akan kita buat akan terlihat seperti ini.
Aplikasi yang kita buat akan dapat melakukan inquiry data to-do yang sudah kita tambahkan, terdapat form yang dapat digunakan untuk menambahkan data to-do, serta toggle pada setiap data to-do untuk mengubah status dari suatu to-do item.
Adapun aplikasi frontend kita ini terdiri dari beberapa component berdasarkan pembagian berikut.
Kita akan membuat tiga component yaitu:
- Header component, yang merupakan shared component untuk menampilkan header di setiap page
- Todo List component, menampilkan data to-do list kita
- Todo Add component, adalah form yang digunakan untuk menambahkan data to-do.
Angular CLI telah menyediakan command untuk dapat digunakan dalam men-generate component, yakni ng generate component <nama-component>
. Karena component Header ini adalah shared component, maka demi kerapihan project, saya tempatkan component ini di dalam folder components/header
.
Sehingga command yang dijalankan adalah:
sh
1ng g c --skipTests=true components/header
Untuk simplifikasi project pembelajaran ini, kita tidak menerapkan testing pada aplikasi kita. Sehingga--skipTests=true
ditambahkan untuk mencegah pembuatan file.spec
yang ditujukan untuk keperluan tersebut.
Command ini akan membantu kita dalam men-generate file-file di dalam folder components/header
dengan file naming dan kode yang sudah siap untuk dapat kita gunakan langsung. Tentu saja kita dapat membuat sendiri file-file ini, hanya saja, kita tidak boleh lupa untuk menambahkan deklarasi component tersebut karena semua component di Angular project harus dideklarasikan di dalam app.module.ts
. Sedangkan dengan menggunakan CLI, Angular akan secara otomatis juga menambahkan deklarasi component tersebut.
File yang terbentuk ada tiga, yakni .css
file, .ts
file dan .html
file. .html
file digunakan sebagai template seperti yang sudah dijelaskan sebelumnya. .ts
file akan menjadi view logic component tersebut, .css
digunakan untuk styling, namun karena kita menggunakan Tailwind CSS, file ini tidak akan banyak kita gunakan.
Untuk component Header ini, kita tidak memiliki view logic apapun, oleh karena itu kita hanya perlu mengubah component template header.component.html
.
header.component.html
1<div
2 class="flex bg-white border-b border-gray-200 fixed top-0 inset-x-0 z-100 h-16 items-center"
3>
4 <div class="w-full max-w-screen-xl relative mx-auto px-6">
5 <div class="flex items-center -mx-6">
6 <div class="lg:w-1/4 xl:w-1/5 pl-6 pr-6 lg:pr-8">
7 <div class="flex items-center">
8 <a class="block lg:mr-4" href="/"
9 ><img
10 class="w-14"
11 id="profile-img"
12 src="https://img.icons8.com/fluent/344/year-of-tiger.png"
13 alt="Logo"
14 /></a>
15 </div>
16 </div>
17 <div class="flex flex-grow min-w-0 lg:w-3/4 xl:w-4/5">
18 <div class="w-full min-w-0 lg:px-6 xl:w-3/4 xl:px-12">
19 <div class="relative">
20 <h1 class="font-semibold text-2xl text-indigo-500">
21 BCA Advisory Program 2022
22 </h1>
23 </div>
24 </div>
25 <div
26 class="hidden lg:flex lg:items-center lg:justify-between xl:w-1/4 px-6"
27 >
28 <div class="flex justify-start items-center text-gray-500">
29 <a
30 class="block flex items-center hover:text-gray-700 mr-5"
31 href="https://github.com/chandragie/bca-advisory-program-2022/"
32 target="_blank"
33 ><svg
34 class="fill-current w-5 h-5"
35 xmlns="http://www.w3.org/2000/svg"
36 viewBox="0 0 20 20"
37 >
38 <title>GitHub</title>
39 <path
40 d="M10 0a10 10 0 0 0-3.16 19.49c.5.1.68-.22.68-.48l-.01-1.7c-2.78.6-3.37-1.34-3.37-1.34-.46-1.16-1.11-1.47-1.11-1.47-.9-.62.07-.6.07-.6 1 .07 1.53 1.03 1.53 1.03.9 1.52 2.34 1.08 2.91.83.1-.65.35-1.09.63-1.34-2.22-.25-4.55-1.11-4.55-4.94 0-1.1.39-1.99 1.03-2.69a3.6 3.6 0 0 1 .1-2.64s.84-.27 2.75 1.02a9.58 9.58 0 0 1 5 0c1.91-1.3 2.75-1.02 2.75-1.02.55 1.37.2 2.4.1 2.64.64.7 1.03 1.6 1.03 2.69 0 3.84-2.34 4.68-4.57 4.93.36.31.68.92.68 1.85l-.01 2.75c0 .26.18.58.69.48A10 10 0 0 0 10 0"
41 ></path></svg></a
42 ><a
43 class="block flex items-center hover:text-gray-700 mr-5"
44 target="_blank"
45 href="https://twitter.com/chandragie"
46 ><svg
47 class="fill-current w-5 h-5"
48 xmlns="http://www.w3.org/2000/svg"
49 viewBox="0 0 20 20"
50 >
51 <title>Twitter</title>
52 <path
53 d="M6.29 18.25c7.55 0 11.67-6.25 11.67-11.67v-.53c.8-.59 1.49-1.3 2.04-2.13-.75.33-1.54.55-2.36.65a4.12 4.12 0 0 0 1.8-2.27c-.8.48-1.68.81-2.6 1a4.1 4.1 0 0 0-7 3.74 11.65 11.65 0 0 1-8.45-4.3 4.1 4.1 0 0 0 1.27 5.49C2.01 8.2 1.37 8.03.8 7.7v.05a4.1 4.1 0 0 0 3.3 4.03 4.1 4.1 0 0 1-1.86.07 4.1 4.1 0 0 0 3.83 2.85A8.23 8.23 0 0 1 0 16.4a11.62 11.62 0 0 0 6.29 1.84"
54 ></path></svg
55 ></a>
56 </div>
57 </div>
58 </div>
59 </div>
60 </div>
61</div>
62
Untuk dapat me-render component Header, kita perlu menempatkannya pada root component kita yaitu app.component.html
. Hapus semua baris kode di dalam file tersebut dan gantikan dengan memanggil selector component Header.
app.component.html
1<app-header></app-header>
Cek kembali aplikasi kita melalui browser dan Header component kita sudah ter-render.
Selanjutnya, kita akan membuat component untuk menampilkan daftar to-do yang kita miliki. Seperti sebelumnya, saya menjalankan command ng g c --skipTests=true todo/todo-list
. Berikut inilah perubahan kode yang perlu dilakukan.
todo-list.component.html
1<div class="flex justify-center pt-16">
2 <div class="w-1/2 mt-7">
3 <div class="flex flex-col justify-center items-center w-full">
4 <div class="flex justify-between w-full">
5 <button
6 type="button"
7 class="w-32 rounded-md bg-indigo-400 hover:bg-indigo-300 p-2 text-md focus:outline-none text-white font-semibold mb-3"
8 >
9 Add to do
10 </button>
11 </div>
12
13 <!-- Cards -->
14 <p *ngIf="!todos">No data</p>
15 <div *ngIf="todos" class="divide-y divide-gray-200 w-full">
16 <ul *ngFor="let todo of todos" role="list">
17 <li
18 class="pl-3 pr-4 py-3 flex items-center justify-between text-lg mb-1 border border-gray-300 rounded-md"
19 >
20 <div class="flex-1 flex items-center">
21 <p class="text-gray-600" aria-hidden="true">
22 {{ todo.title }}
23 </p>
24 </div>
25 <div class="ml-4 flex-shrink-0">
26 <button
27 type="button"
28 class="font-medium text-indigo-600 hover:text-indigo-400"
29 *ngIf="!todo.done"
30 >
31 Done
32 </button>
33 <button
34 type="button"
35 class="font-medium text-gray-600 hover:text-gray-500"
36 *ngIf="todo.done"
37 >
38 Undone
39 </button>
40 </div>
41 </li>
42 </ul>
43 </div>
44 </div>
45 </div>
46</div>
47
Kita menggunakan directive ngFor
untuk melakukan looping data to-do yang akan didapatkan dari backend API. Kita perlu mendeklarasikan properti ini pada file TypeScript kita.
todo-list.component.ts
1import { Component, OnInit } from '@angular/core';
2
3@Component({
4 selector: 'app-todo-list',
5 templateUrl: './todo-list.component.html',
6 styleUrls: ['./todo-list.component.css'],
7})
8export class TodoListComponent implements OnInit {
9 constructor() {}
10
11 todos: any;
12
13 ngOnInit(): void {
14
15 }
16
17}
Tidak seperti Header component yang ditampilkan pada semua halaman, Todo List component merupakan component yang diakses melalui URL atau biasa disebut page. Oleh karena itu, kita perlu meng-update router aplikasi kita untuk dapat mengakses component ini. Pada inisialisasi project, kita melakukan setting router menjadi enabled, sehingga kita dapat langsung menggunakan routing system Angular.
Pertama, kita perlu mendefinisikan route atau path ke component Todo List. Buka file app-routing.module.ts
dan tambahkan kode berikut.
app-routing.module.ts
1const routes: Routes = [
2 { path: '', pathMatch: 'full', redirectTo: 'todos' },
3 { path: 'todos', component: TodoListComponent}
4];
Path ''
dimaksudkan untuk me-redirect request ke halaman Todo List sebagai default page.
Kedua, tambahkan component Todo List ini ke dalam app.module.html seperti sebelumnya. Namun karena kali ini kita menggunakan router dari Angular untuk take over proses rendering berdasarkan URL yang dikirim, kita bukan menambahkan tag <app-todo-list></app-todo-list>
melainkan <router-outlet></router-outlet>
.
app.component.html
1<app-header></app-header>
2<router-outlet></router-outlet>
Nah, sekarang coba kita akses kembali aplikasi kita dan by default kita akan langsung diarahkan ke component Todo List. Perhatikan pada address bar bahwa request kita diarahkan ke /todos
.
Karena belum ada data apapun yang kita supply ke properti todos
, sesuai dengan conditional rendering logic yang kita terapkan, maka kita mendapatkan teks "No data". Kita akan tambahkan integrasi ke backend API kita pada bagian selanjutnya.
Next kita buat form untuk menambahkan to-do item. Sama seperti sebelumnya, mari kita generate component dan lakukan perubahan sebagai berikut.
todo-add.component.ts
1import { Component, OnInit } from '@angular/core';
2import { FormControl, FormGroup, Validators } from '@angular/forms';
3
4@Component({
5 selector: 'app-todo-add',
6 templateUrl: './todo-add.component.html',
7 styleUrls: ['./todo-add.component.css'],
8})
9export class TodoAddComponent implements OnInit {
10 addForm!: FormGroup;
11 form: any;
12 constructor(
13 ) {
14 this.form = {
15 title: '',
16 };
17 }
18
19 ngOnInit(): void {
20 this.addForm = new FormGroup({
21 title: new FormControl('', Validators.required),
22 });
23 }
24}
todo-add.component.html
1<div class="flex justify-center pt-16">
2 <div class="w-1/2 mt-7">
3 <div class="flex flex-col justify-center items-center w-full">
4 <form autocomplete="off" class="w-full" [formGroup]="addForm">
5 <div class="items-center">
6 <div class="w-full mb-2">
7 <label
8 class="block text-gray-500 font-bold text-left"
9 for="title"
10 >
11 What do you want to do?
12 </label>
13 </div>
14 <div class="w-full">
15 <input
16 class="bg-gray-100 appearance-none border-2 border-gray-200 rounded w-full py-2 px-4 text-gray-700 leading-tight focus:outline-none focus:bg-white focus:border-indigo-500"
17 id="title"
18 type="text"
19 placeholder="Do something..."
20 [formControlName]="'title'"
21 required
22 />
23 <span *ngIf="!addForm.get('title')?.valid && addForm.get('title')?.touched" class="text-red-600 text-sm">Really? Nothing to do?</span>
24 </div>
25 </div>
26 <div class="flex justify-between w-full mt-10">
27 <button
28 type="button"
29 class="w-32 rounded-md bg-indigo-400 hover:bg-indigo-300 p-2 text-md focus:outline-none text-white font-semibold mb-3"
30 [routerLink]="['/']"
31 >
32 Cancel
33 </button>
34
35 <button
36 type="submit"
37 class="w-32 rounded-md bg-indigo-400 hover:bg-indigo-300 p-2 text-md focus:outline-none text-white font-semibold mb-3"
38 >
39 Submit
40 </button>
41 </div>
42 </form>
43 </div>
44 </div>
45</div>
46
47
Untuk dapat menggunakan form pada Angular, kita perlu mengaktifkan module tersebut melalui app.module.ts
.
app.module.ts
1import { NgModule } from '@angular/core';
2import { BrowserModule } from '@angular/platform-browser';
3
4import { AppRoutingModule } from './app-routing.module';
5import { AppComponent } from './app.component';
6import { HeaderComponent } from './components/header/header.component';
7import { TodoListComponent } from './todo/todo-list/todo-list.component';
8import { TodoAddComponent } from './todo/todo-add/todo-add.component';
9import { ReactiveFormsModule } from '@angular/forms';
10
11@NgModule({
12 declarations: [
13 AppComponent,
14 HeaderComponent,
15 TodoListComponent,
16 TodoAddComponent
17 ],
18 imports: [
19 BrowserModule,
20 AppRoutingModule,
21 ReactiveFormsModule
22 ],
23 providers: [],
24 bootstrap: [AppComponent]
25})
26export class AppModule { }
27
Jangan lupa kita juga perlu menambahkan route ke component ini.
app-routing.module.ts
1const routes: Routes = [
2 { path: '', pathMatch: 'full', redirectTo: 'todos' },
3 { path: 'todos', component: TodoListComponent},
4 { path: 'add', component: TodoAddComponent},
5];
Tambahkan juga routerLink
sebagai event binding pada tombol "Add to do" kita.
todo-list.component.html
1 <div class="flex justify-between w-full">
2 <button
3 [routerLink]="['/add']"
4 type="button"
5 class="w-32 rounded-md bg-indigo-400 hover:bg-indigo-300 p-2 text-md focus:outline-none text-white font-semibold mb-3"
6 >
7 Add to do
8 </button>
9 </div>
Simpan semua file tersebut dan cek aplikasi. Tombol "Add to do" kita sudah dapat melakukan perpindahan halaman ke halaman dari component Todo Add. Perhatikan juga bahwa validasi form yang kita terapkan sudah dapat berjalan 👍
Meskipun dapat melakukan perpindahan halaman, aplikasi kita masih belum menggunakan backend API yang sudah kita buat. Mari kita integrasikan agar aplikasi kita dapat fully functional. Pertama, kita perlu melakukan generate service. Sama seperti component, kita dapat menggunakan command berikut.
sh
1ng g service services/todo
Kita akan mendapatkan file todo.service.ts
pada folder /services
. Lakukan perubahan berikut.
todo.service.ts
1import { HttpClient } from '@angular/common/http';
2import { Injectable } from '@angular/core';
3import { Observable } from 'rxjs';
4import { environment } from 'src/environments/environment';
5
6@Injectable({
7 providedIn: 'root',
8})
9export class TodoService {
10 constructor(private httpClient: HttpClient) {}
11
12 getAll = (): Observable<any> => {
13 return this.httpClient.get(`${environment.baseUrl}/todo`, {
14 responseType: 'json',
15 });
16 };
17
18 add = (body: any): Observable<any> => {
19 return this.httpClient.post(`${environment.baseUrl}/todo`, { ...body });
20 };
21
22 update = (id: string): Observable<any> => {
23 return this.httpClient.put(`${environment.baseUrl}/todo`, { id: id });
24 };
25}
26
Code beauty tips: gunakan environment properties untuk configurational value. Tambahkan baseUrl: 'http://localhost:8080/adam'
pada environment.ts. Sesuaikan port pada URL tersebut dengan mengarah ke port dimana backend API kita berjalan.
Untuk memanggil backend API, kita memerlukan HTTP Client. Angular sudah menyediakan module ini, kita hanya perlu mengaktifkannya seperti berikut.
app.module.ts
1import { NgModule } from '@angular/core';
2import { BrowserModule } from '@angular/platform-browser';
3import { HttpClientModule } from '@angular/common/http';
4import { AppRoutingModule } from './app-routing.module';
5import { AppComponent } from './app.component';
6import { HeaderComponent } from './components/header/header.component';
7import { TodoListComponent } from './todo/todo-list/todo-list.component';
8import { TodoAddComponent } from './todo/todo-add/todo-add.component';
9import { ReactiveFormsModule } from '@angular/forms';
10
11@NgModule({
12 declarations: [
13 AppComponent,
14 HeaderComponent,
15 TodoListComponent,
16 TodoAddComponent
17 ],
18 imports: [
19 BrowserModule,
20 AppRoutingModule,
21 ReactiveFormsModule,
22 HttpClientModule,
23 ],
24 providers: [],
25 bootstrap: [AppComponent]
26})
27export class AppModule { }
Beberapa hal yang perlu dipelajari yaitu bahwa kita menggunakan Observable untuk berkomunikasi dengan backend API kita. Observable sendiri merupakan topik advance namun sederhananya, ibarat sebuah keran air, kita dapat sewaktu-waktu membuka keran tersebut di saat kita membutuhkan air dan mematikannya apabila sudah selesai menggunakannya. Apabila fellowdevs familiar dengan konsep Promise, Observable tidaklah sama. Observable memungkinkan kita untuk melakukan reactive programming sedangkan Promise sebatas asynchronous.
Beberapa hal yang perlu dipelajari yaitu bahwa kita menggunakan Observable untuk berkomunikasi dengan backend API kita. Observable sendiri merupakan topik advance namun sederhananya, ibarat sebuah keran air, kita dapat sewaktu-waktu membuka keran tersebut di saat kita membutuhkan air dan mematikannya apabila sudah selesai menggunakannya. Apabila fellowdevs familiar dengan konsep Promise, Observable tidaklah sama. Observable memungkinkan kita untuk melakukan reactive programming sedangkan Promise sebatas asynchronous.
Wait, what?? You are not alone! Ya, as I said, this is actually an advance topic tapi saya akan mencoba menjelaskannya sesederhana mungkin. Observable berasal dari kata to observe, to watch, or notice. Melalui Observable, kita dapat melakukan data streaming melalui proses subscription pada event emitter. Sehingga apabila terjadi perubahan atau biasa disebut event kita akan mendapatkan informasi atau update terhadap kejadian tersebut apabila kita masih listen atau subscribe.
Another brilliant example yang menjelaskan perbedaan Promise dan Observable adalah: andaikan Anda memenangkan tiket untuk menghadiri Angular conference, ng-conf. Anda mengemas koper Anda, terbang ke lokasi konferensi dan mendapati bahwa bapak dari Angular, Miško Hevery sendirilah yang memberikan talk pertama. Apa yang Anda lakukan?
- Pop in for a second, catch only one word of his talk and leave?
- Atau Anda akan duduk dengan nyaman dan "observe" apapun yang dia katakan?
Tentu saja Anda akan melakukan yang kedua bukan? Dengan kata lain, Promise adalah ilustrasi yang pertama. Segera setelah Promise mendapatkan response, even only a word of the whole talk, it would just leave and complete. Sedangkan Observable adalah ilustrasi kedua dimana Anda mendengarkan dan melakukan observasi terhadap materi yang dijelaskan oleh Miško.
Saat Anda mendengarkan ceramah Angular tersebut, Anda mulai sedikit merasa bosan, Anda mengambil handphone Anda dan mulai browsing atau berselancar di sosial media selama 15 menit. Lalu Anda sadar bahwa Anda tidak lagi mendengarkan materi yang dibawakan. Kondisi ini disebut juga sebagai "unsubscribe". Dan kemudian Anda memutuskan untuk meletakkan handphone Anda dan menjadi selayaknya good observer.
Okay, cukup tentang Observable. Sekarang kita perlu memanggil / "subscribe" ke Observable ini dari component kita. Mari kita mulai dari proses inquiry to-do list.
todo-list.component.ts
1import { Component, OnInit } from '@angular/core';
2import { TodoService } from 'src/app/services/todo.service';
3import { ActivatedRoute } from '@angular/router';
4
5@Component({
6 selector: 'app-todo-list',
7 templateUrl: './todo-list.component.html',
8 styleUrls: ['./todo-list.component.css'],
9})
10export class TodoListComponent implements OnInit {
11 constructor(
12 private todoService: TodoService,
13 private activatedRoute: ActivatedRoute,
14 private toastr: ToastrService
15 ) {}
16 todos: any;
17 ngOnInit(): void {
18 this.getTodos();
19
20 this.activatedRoute.queryParams.subscribe((params) => {
21 if (params['save'] !== undefined && params['save'] === 'true') {
22 this.toastr.success('Todo saved succesfully!');
23 }
24 });
25 }
26 getTodos = () => {
27 this.todoService.getAll().subscribe({
28 next: (data) => {
29 this.todos = data;
30 },
31 error: (error) => {
32 this.toastr.error('Failed to get todo list');
33 throw error;
34 },
35 });
36 };
37}
38
Saya menambahkan dependency tambahan untuk notifikasi sederhana berupa toaster. Dependency ini perlu kita install terlebih dahulu.
sh
1npm i ngx-toastr
Kemudian untuk pemanis, kita juga tambahkan animasi.
sh
1npm install @angular/animations
Tertulis pada dokumentasi resminya, kita perlu meng-copy file toastr.css ini pada folder /src
project kita dan kemudian untuk Angular dapat memasukkan style tersebut, kita perlu sedikit mengubah file angular.json
dan menambahkan konfigurasi berikut.
angular.json
1 "architect": {
2 "build": {
3 "builder": "@angular-devkit/build-angular:browser",
4 "options": {
5 "outputPath": "dist/bcaadam-frontend",
6 "index": "src/index.html",
7 "main": "src/main.ts",
8 "polyfills": "src/polyfills.ts",
9 "tsConfig": "tsconfig.app.json",
10 "assets": [
11 "src/favicon.ico",
12 "src/assets"
13 ],
14 "styles": [
15 "src/styles.css",
16 "src/toastr.css"
17 ],
18 "scripts": []
19 },
20 "configurations": {}
Seperti halnya semua module perlu dideklarasikan, mari kita daftarkan module toaster ini.
app.module.ts
1import { NgModule } from '@angular/core';
2import { BrowserModule } from '@angular/platform-browser';
3import { HttpClientModule } from '@angular/common/http';
4import { AppRoutingModule } from './app-routing.module';
5import { AppComponent } from './app.component';
6import { TodoListComponent } from './todo/todo-list/todo-list.component';
7import { HeaderComponent } from './components/header/header.component';
8import { TodoAddComponent } from './todo/todo-add/todo-add.component';
9import { ReactiveFormsModule } from '@angular/forms';
10import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
11import { ToastrModule } from 'ngx-toastr';
12
13@NgModule({
14 declarations: [
15 AppComponent,
16 TodoListComponent,
17 HeaderComponent,
18 TodoAddComponent,
19 ],
20 imports: [
21 BrowserModule,
22 AppRoutingModule,
23 HttpClientModule,
24 ReactiveFormsModule,
25 BrowserAnimationsModule,
26 ToastrModule.forRoot({
27 positionClass: 'toast-bottom-right',
28 }),
29 ],
30 providers: [],
31 bootstrap: [AppComponent],
32})
33export class AppModule {}
Simpan semua file tersebut dan kita sudah dapat melihat bahwa aplikasi frontend kita sudah berhasil melakukan call ke backend API dan mendapatkan data to-do yang tersimpan.
Coba matikan service backend API kita dan refresh halaman aplikasi. Maka kita akan mendapatkan notifikasi dalam bentuk toaster. Notifikasi semacam ini berguna untuk memberi user info apabila terjadi masalah pada aplikasi kita.
Selanjutnya, kita akan mengubah beberapa file untuk membuat fungsi add dan update bekerja.
todo-add.component.html
1 <form
2 autocomplete="off"
3 class="w-full"
4 [formGroup]="addForm"
5 (ngSubmit)="addTodo()"
6 >
todo-add.component.ts
1import { Component, OnInit } from '@angular/core';
2import { FormControl, FormGroup, Validators } from '@angular/forms';
3import { Router } from '@angular/router';
4import { ToastrService } from 'ngx-toastr';
5import { TodoService } from 'src/app/services/todo.service';
6
7@Component({
8 selector: 'app-todo-add',
9 templateUrl: './todo-add.component.html',
10 styleUrls: ['./todo-add.component.css'],
11})
12export class TodoAddComponent implements OnInit {
13 addForm!: FormGroup;
14 form: any;
15 constructor(
16 private todoService: TodoService,
17 private router: Router,
18 private toastr: ToastrService
19 ) {
20 this.form = {
21 title: '',
22 };
23 }
24
25 ngOnInit(): void {
26 this.addForm = new FormGroup({
27 title: new FormControl('', Validators.required),
28 });
29 }
30
31 addTodo() {
32 if (this.addForm.invalid) {
33 this.toastr.error('Name what you want to do dude!');
34 return;
35 }
36
37 this.form.title = this.addForm.get('title')?.value;
38 this.todoService.add(this.form).subscribe({
39 next: () =>
40 this.router.navigate(['/'], { queryParams: { save: 'true' } }),
41 error: () => this.toastr.error('Failed to save todo! Please try again'),
42 });
43 }
44}
45
todo-list.component.html
1 <div class="ml-4 flex-shrink-0">
2 <button
3 (click)="updateTodo(todo.id)"
4 type="button"
5 class="font-medium text-indigo-600 hover:text-indigo-400"
6 *ngIf="!todo.done"
7 >
8 Done
9 </button>
10 <button
11 (click)="updateTodo(todo.id)"
12 type="button"
13 class="font-medium text-gray-600 hover:text-gray-500"
14 *ngIf="todo.done"
15 >
16 Undone
17 </button>
18 </div>
todo-list.component.ts
1 getTodos = () => {
2 // snipped
3 }
4
5 updateTodo = (id: string) => {
6 this.todoService.update(id).subscribe({
7 next: () => {
8 this.toastr.success('Todo updated!');
9 this.getTodos();
10 },
11 error: (error) => {
12 this.toastr.error('Failed to update todo ☹');
13 throw error;
14 },
15 });
16 };
And that should be it guys! Cek aplikasi kita melalui browser dan semua operasi sudah dapat dilakukan.
Apabila fellowdevs perhatikan pada component todo-list.component.html
saya memberikan segment <!-- Cards -->
. Untuk saat ini saya masih menuliskan to-do list dalam tag <ul>
. Nah untuk latihan, coba kalian kembangkan cara ini dengan memisahkan list menjadi card component.
Kita telah belajar mengenai bagaimana melakukan frontend development dengan menggunakan framework Angular, serta mengintegrasikannya ke backend API kita yang dibangun dengan menggunakan Spring Boot. Selanjutnya, kita akan kembangkan aplikasi kita ini dengan menambahkan unsur security yaitu authentication dan authorization pada Chapter 3.
How Angular applications start (dsebastien.net)
How Angular Application Starts - Behind The $cene story!
Angular and Observable. We listen so many times that developers… | by Bhatt Ami