# Seri Belajar Pemrograman

Step by step belajar pemrograman web, database, api dan pemrograman mobile. Bahasa pemrograman yang digunakan adalah javascript, dengan database MySQL.

Materi ini disusun untuk membantu siswa mempelajari pemrograman. Untuk mempermudah pembelajaran, bahasa pemrograman yang diajarkan hanya satu bahasa pemrograman, yaitu javascript. Bahasa pemrograman javascript dipilih karena javascript merupakan bahasa pemrograman yang sangat umum, mudah dipelajari, dan bisa digunakan untuk membuat berbagai macam aplikasi, baik aplikasi berbasis web, desktop maupun mobile.&#x20;

Materi pertama adalah materi pengenalan web design, yaitu HTML dan CSS, serta pengenalan javascript. Setelah mengikuti materi ini, diharapkan siswa mampu membuat tampilan halaman web secara fungsional dan artistik (web design). Siswa juga diharapkan menguasai logika pemrograman.

Materi kedua adalah database. Setelah mengikuti materi ini, siswa diharapkan mampu merancang dan membuat database MySQL. Siswa juga diharapkan mampu melakukan query untuk select, join, insert, update, dan delete.

Materi ketiga adalah NodeJS, yaitu penggunaan javascript sebagai bahasa di sisi server. Setelah mengikuti materi ini, siswa diharapkan mampu membuat rest api yang berinteraksi dengan database.

Materi keempat adalah Svelte, sebagai framework javascript yang handal. Setelah mengikuti materi ini, siswa diharapkan dapat membuat tampilan frontend dan melakukan interaksi dengan api yang telah dibuat pada materi sebelumnya.

Materi terakhir adalah penggunaan javascript dalam pembuatan aplikasi mobile (android maupun ios). Framework yang digunakan adalah Svelte Native. Diharapkan siswa bisa cepat memahami karena pada materi sebelumnya sudah mengenal Svelte framework. Setelah mengikuti materi ini, siswa diharapkan dapat membuat aplikasi mobile, baik android maupun ios.&#x20;

Berikut adalah silabus materi seri belajar pemrograman :

* [HTML dan CSS](/html-dan-css/pengenalan-html-dan-css)
* [Javascript](/javascript/pengenalan-javascript)
* [Database](/database/pengenalan-database)
* [Node JS](/node-js/pengenalan-node-js)
* [Svelte](/svelte/pengenalan-svelte)
* [Svelte Native for Mobile](/svelte-native-for-mobile/pengenalan-svelte-native)


# Pengenalan HTML dan CSS

## HTML

HTML adalah bahasa markup standar untuk membuat halaman Web yang menggambarkan struktur halaman Web. Berikut struktur dasar HTML :

```markup
<!DOCTYPE html>
<html>
    <head>
        <title>Judul Halaman</title>
    </head>
    <body>
        Selamat Pagi
    </body>
</html>
```

* Deklarasi \<!DOCTYPE html> mendefinisikan bahwa dokumen ini adalah dokumen HTML5
* Elemen  \<html> adalah elemen root dari halaman HTML
* Elemen  \<head> berisi informasi meta tentang halaman HTML
* Elemen  \<title> menentukan judul untuk halaman HTML (yang ditampilkan di judul browser atau tab halaman)&#x20;
* Elemen  \<body> mendefinisikan tubuh dokumen, dan merupakan wadah untuk semua konten yang terlihat, seperti teks, judul, paragraf, gambar, hyperlink, tabel dll.

### Text Editor

Untuk membuat/mengedit file html bisa dilakukan dengan text editor sederhana seperti notepad, maupun text editor yang dibangun khusus untuk developer. Saya pribadi biasa menggunakan Visual Studio Code. Download Visual Studio code melalui halaman <https://code.visualstudio.com/download> dan install di komputer/laptop.

File html disimpan dengan ekstensi .html. Buka Visual Studio Code dan buat file index.html yang berisi dengan kode html seperti di atas. File ini ketika dibuka dengan browser (seperti chrome/firefox/opera) akan menampilkan tulisan "Selamat Pagi". Silahkan coba klik file index.html yang telah dibuat, tampilan di browser akan tampak seperti gambar di bawah ini.

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MfcJ-mWGwfB27EGC2hA%2F-MfhB2QdJIFXMZGkjBS7%2FScreen%20Shot%202021-07-28%20at%2019.55.11.png?alt=media\&token=87efc1f8-1097-40fc-81f1-e50a3b270ec3)

### Tag

Sebagai sebuah bahasa markup, **HTML** membutuhkan cara untuk memberitahu web browser untuk apa fungsi sebuah text. Apakah text itu ditulis sebagai sebuah paragraf, list, atau sebagai link. Dalam **HTML**, tanda ini dikenal dengan istilah **tag**.

Tag dimulai dengan simbol lebih kecil (<) dan ditutup dengan simbol lebih besar (>). Perhatikan beberapa contoh berikut :

* \<p> adalah tag untuk paragraf
* \<h1> adalah tag untuk judul utama

Tag dibagi dua jenis, yaitu tag buka dan tag tutup. Yang membedakan suatu tag buka dengan tag tutup adalah simbol slash (/). Jika ada simbol slash (/) berarti merupakan tag tutup. Untuk tag paragraf, \<p> adalah tag buka. Sementara tag tutupnya adalah \</p>.

### Element

Element HTML adalah semua yang dimulai dari TAG buka sampai TAG tutup. Jadi di antara tag buka dengan tag tutup ada suatu *content* berupa text. keseluruhan tag beserta isinya itulah yang disebut element.

Berikut adalah contoh suatu elemen berupa paragraf :

```markup
<p>Selamat pagi Indonesia, semoga semua sehat...</p>
```

Tidak semua tag memiliki isi, tag br yang berfungsi sebagai ganti baris (line break) tidak membutuhkan isi. Tag input juga tidak memerlukan isi. Untuk semua tag yang tidak memerlukan isi, tag tersebut setelah dibuka bisa langsung ditutup. Berikut contoh tag yang langsung ditutup karena tidak memerlukan isi.

* \<br/> &#x20;
* \<input />
* \<button/>

### Attributes

*Attribute* adalah informasi tambahan dari sebuah *element*. Atribut ini tidak wajib, hanya opsional, dan diletakkan di tag awal. Cara penulisan atribut adalah dengan menuliskan nama atribut dan nilai dari atribut. Contoh penulisan atribut sebagai berikut :

```markup
<p style="color:green">Selamat Pagi</p>
<img src="kucing.jpg" width="400" height="400" alt="kucing hitam"/>
```

Kode di atas terdiri dari dua elemen, yaitu elemen paragraf dan elemen gambar. Pada elemen paragraf, terdapat satu atribut, yaitu atribut style dengan nilai color:green. Sementara pada elemen gambar terdapat 4 atribut, meliputi src, width, height, dan alt. Lebih jauh tentang elemen paragraf dan elemen gambar, akan dibahas pada bab selanjutnya.

## CSS

CSS digunakan untuk menata tampilan halaman web, kertas atau media lain. Dengan CSS tampilan HTML menjadi lebih cantik, artistik dan mudah terbaca. Beberapa poin penting pengertian CSS meliputi :

* CSS adalah bahasa yang digunakan untuk menata halaman Web
* CSS adalah singkatan dari *Cascading Style Sheets*
* CSS menjelaskan bagaimana elemen HTML ditampilkan di layar, kertas, atau di media lain

Pembahasan CSS akan dilakukan bertahap dengan menyisipkan pada materi html yang berkaitan (*related*).


# Tipografi Dasar

Tipografi adalah suatu teknik dalam memilih dan menata huruf dengan indah dalam suatu ruang yang tersedia. Ini melibatkan pilihan jenis huruf, ukuran huruf, warna, format teks yang disusun sedemikian rupa sehingga tampilan menjadi mudah dibaca.

Pada bab ini siswa akan mempelajari elemen elemen terkait tipografi, dan styling untuk mempercantik tampilan.

## Judul

Untuk membuat judul atau sub judul, kita menggunakan tag h (heading). Disediakan 6 jenis heading, dari judul utama sampai ke sub judul yang paling kecil.&#x20;

Judul ini sangat penting dalam sebuah halaman web. Search engine seperti google, bing, yahoo, yandex dll, memanfaatkan judul untuk algoritma pencarian mereka. Gunakan judul sesuai dengan fungsinya secara alami. Dalam suatu artikel hanya boleh ada satu judul utama. Di dalam artikel bisa terdiri dari beberapa sub judul.&#x20;

Jangan menggunakan judul untuk alasan artistik agar suatu teks kelihatan besar dan atau tebal. Karena untuk artistik kita bisa memanfaatkan styling (CSS) untuk mengatur besaran dan tampilan huruf. Letakkan judul pada porsinya secara alamiah.

Berikut cara penulisan judul/sub judul, mulai dari judul utama (h1) sampai sub judul yang paling kecil (h6).

```markup
<h1>Judul Utama - H1</h1>
<h2>Sub Judul - H2</h2>
<h3>Sub Judul - H3</h3>
<h4>Sub Judul - H4</h4>
<h5>Sub Judul - H5</h5>
<h6>Sub Judul - H6</h6>
```

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MfmpbccFnjvNhjdgw0j%2F-MfmyG69_3rNIv0qE-Rr%2FScreen%20Shot%202021-07-29%20at%2022.53.04.png?alt=media\&token=adc60138-462e-4bee-b16a-e36c024bb23e)

Saya pribadi biasanya hanya menggunakan tiga jenis judul/sub judul, yaitu H1, H2 dan H3. Satu artikel hanya mempunyai H1 sebagai judul utama. Di dalam body artikel bisa mempunyai 2 sampai 4 sub judul H2. Dan di masing-masing sub judul H2, bisa mempunyai beberapa sub judul lagi berupa H3.

## Paragraf

Paragraf digunakan untuk membuat suatu alinea/paragraf dalam suatu tulisan. Tag \<p> digunakan untuk membuat suatu paragraf. Paragraf  selalu dimulai pada baris baru, dan biasanya berupa blok teks. Browser secara otomatis menambahkan beberapa spasi (margin) sebelum dan sesudah paragraf.

```markup
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut fermentum, nunc nec sagittis porta, urna nunc pulvinar augue, ac efficitur felis urna nec odio. Phasellus sed rutrum tellus. Donec id lobortis tortor, et mattis nulla. Phasellus mollis tempus orci mattis ornare. Fusce pharetra congue dictum. Sed accumsan tempor aliquam. Aenean dictum, odio tristique consectetur suscipit, ante enim auctor velit, at vehicula sem nunc at purus. Cras vel mollis urna. Sed sed massa non tellus pulvinar bibendum ut et erat. Donec fringilla lobortis pellentesque. Morbi posuere libero malesuada magna viverra congue. Cras fermentum diam sit amet est lobortis rutrum. Vestibulum in ipsum pellentesque, auctor metus eget, dapibus leo. Sed commodo efficitur dui nec malesuada. Nunc at faucibus ante. Pellentesque porta nec nisi non suscipit.</p>
<p>Integer sed sodales ex. Ut consectetur eros quis ex fermentum placerat. Duis faucibus felis vel diam laoreet, vel varius tellus consequat. Ut dignissim lobortis dolor, in egestas mauris varius vulputate. Phasellus et ultrices est. Nulla viverra lectus felis, sit amet rhoncus felis congue a. Vestibulum eu tortor quis lectus tempus vehicula. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae.</p>
<p>Suspendisse non erat ultrices, imperdiet sem eget, egestas dolor. Aliquam at lectus convallis, bibendum enim quis, fringilla tellus. Aenean sodales nisl et ornare vestibulum. Nullam ut sagittis felis, ultricies ornare augue. Cras tempus nisi sed risus interdum scelerisque. Mauris faucibus risus id luctus auctor. Ut congue non orci eget egestas. Nunc pharetra vehicula enim. Integer vel venenatis metus. Nam imperdiet, velit sit amet facilisis suscipit, felis sem viverra quam, in elementum velit ante non neque. Sed enim dui, ornare in libero id, gravida sollicitudin libero. Mauris gravida, libero eget tincidunt luctus, elit arcu mollis orci, sollicitudin volutpat ipsum sem nec purus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae.</p>
```

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MfmyOpq2i60ZEvllsKi%2F-Mfn-gsBLf3-GXHONtZ9%2FScreen%20Shot%202021-07-29%20at%2023.04.06.png?alt=media\&token=312bb6a6-e5c7-40aa-80b1-62698805d053)

## Format

Format diperlukan ketika ingin mendefinisikan teks dengan arti khusus, misalnya cetak tebal, cetak miring dan lain-lain.

Elemen pemformatan dirancang untuk menampilkan jenis teks khusus:

* `<b>` - Bold text - cetak tebal
* `<strong>` - Important text - kata penting
* `<i>` - Italic text - cetak miring
* `<em>` - Emphasized text - teks ditekankan
* `<mark>` - Marked text - teks disorot
* `<small>` - Smaller text - teks dicetak dengan ukuran kecil
* `<del>` - Deleted text - teks dicoret
* `<ins>` - Inserted text - teks digarisbawahi
* `<sub>` - Subscript text - teks dicetak menjorok ke bawah
* `<sup>` - Superscript text - teks dicetak menjorok ke atas

```markup
<b>Teks dicetak tebal</b> <br/>
<strong>Ditandai sebagai teks penting</strong> <br/>
<i>Teks dicetak miring</i> <br/>
<em>Teks yang perlu ditekankan</em> <br/>
<mark>Teks yang perlu disorot</mark> <br/>
<small>Teks dicetak kecil</small> <br/>
<del>Teks dicoret</del> <br/>
<ins>Teks digaris-bawahi</ins> <br/>
Kita menghirup O<sub>2</sub> <br/>
A<sup>2</sup> = A x A 
```

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-Mfn0P98SB_7HUl4WAPr%2F-MfouJisjltHsbulfQpr%2FScreen%20Shot%202021-07-30%20at%2007.55.06.png?alt=media\&token=ca2b763f-6e1d-4a6e-81e4-031e7d1754f9)

Yang perlu diperhatikan adalah perbedaan antara \<b> dan \<strong>, serta \<i> dengan \<em>. Secara tampilan, \<b> dan \<strong> tampak sama-sama dicetak tebal, tapi sebenarnya fungsi-nya berbeda. \<b> adalah bold yang hanya mencetak tulisan secara tebal. Tapi \<strong> artinya adalah kata yang penting. Search engine tidak akan mengindeks kata yang dicetak tebal, tapi akan mengindeks kata yang penting. Kita bisa saja boros menggunakan \<b> untuk mencetak kata menjadi tebal. Namun kalau kita menandai sembarang kata (banyak kata) sebagai kata penting, search engine akan malas mengindeks halaman web kita. Kalau kita menandai banyak sekali kata sebagai kata penting, artinya semua kata itu menjadi tidak penting khan? Jadi bijaklah menggunakan \<strong> hanya untuk menandai teks yang benar-benar penting.

Begitu juga dengan \<i> dan \<em> yang secara tampilan sama-sama dicetak miring, tapi mempunyai fungsi yang berbeda. \<i> artinya italic hanya untuk mencetak teks secara miring. tag \<i> bisa digunakan berkali-kali tanpa ada pengaruh terhadap search engine. Namun berbeda dengan \<em> yang artinya emphasized atau penekanan. Jadi teks yang ditandai dengan tag \<em> hanyalah teks yang memang perlu ditekankan. Search engine akan meng-*crawler* teks yang ditandai dengan \<em>. Jadi bijaklah menggunakan tag \<em>, gunakan hanya jika kita memandang teks tersebut perlu untuk ditekankan.

## Style

Seperti yang telah disinggung di pengenalan CSS, style digunakan untuk mempercantik tampilan. Ada 3 cara bagaimana kita memberi style pada tag html, yaitu : Inline CSS, Internal CSS, dan eksternal CSS.

### Inline CSS

Inline CSS artinya kita memberi style secara inline pada tag html. Keunggulan-nya adalah ketika elemen tersebut di-load otomatis juga sudah terbawa styling-nya. Inline CSS juga berguna jika kita ingin memberi style hanya khusus pada satu tag yang dinginkan. Styling yang disematkan secara inline di tag tersebut, tidak akan berdampak pada tag di tempat lain, walaupun kedua tag tersebut sama (misalnya \<p> pertama diberi inline style, dan \<p> yang berikutnya tidak, maka style hanya bekerja pada \<p> pertama saja).

Perhatikan contoh berikut :

```markup
<h1>Contoh Inline Style</h1>
<p style="background-color:pink">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut fermentum, nunc nec sagittis porta, urna nunc pulvinar augue, ac efficitur felis urna nec odio. Phasellus sed rutrum tellus. Donec id lobortis tortor, et mattis nulla. Phasellus mollis tempus orci mattis ornare. Fusce pharetra congue dictum. Sed accumsan tempor aliquam. Aenean dictum, odio tristique consectetur suscipit, ante enim auctor velit, at vehicula sem nunc at purus. Cras vel mollis urna. Sed sed massa non tellus pulvinar bibendum ut et erat. Donec fringilla lobortis pellentesque. Morbi posuere libero malesuada magna viverra congue. Cras fermentum diam sit amet est lobortis rutrum. Vestibulum in ipsum pellentesque, auctor metus eget, dapibus leo. Sed commodo efficitur dui nec malesuada. Nunc at faucibus ante. Pellentesque porta nec nisi non suscipit.</p>
<p>Integer sed sodales ex. Ut consectetur eros quis ex fermentum placerat. Duis faucibus felis vel diam laoreet, vel varius tellus consequat. Ut dignissim lobortis dolor, in egestas mauris varius vulputate. Phasellus et ultrices est. Nulla viverra lectus felis, sit amet rhoncus felis congue a. Vestibulum eu tortor quis lectus tempus vehicula. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae.</p>
<p>Suspendisse non erat ultrices, imperdiet sem eget, egestas dolor. Aliquam at lectus convallis, bibendum enim quis, fringilla tellus. Aenean sodales nisl et ornare vestibulum. Nullam ut sagittis felis, ultricies ornare augue. Cras tempus nisi sed risus interdum scelerisque. Mauris faucibus risus id luctus auctor. Ut congue non orci eget egestas. Nunc pharetra vehicula enim. Integer vel venenatis metus. Nam imperdiet, velit sit amet facilisis suscipit, felis sem viverra quam, in elementum velit ante non neque. Sed enim dui, ornare in libero id, gravida sollicitudin libero. Mauris gravida, libero eget tincidunt luctus, elit arcu mollis orci, sollicitudin volutpat ipsum sem nec purus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae.</p>
```

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MfovUlkFk2k9h1OMBae%2F-MfoyYvjsqH_1l94Wcyb%2FScreen%20Shot%202021-07-30%20at%2008.13.06.png?alt=media\&token=12b09523-7354-4738-8eb6-cdf929d1d502)

Perhatikan bahwa paragraf pertama diberi atribut style untuk memberi tampilan dengan bakground warna pink.

Kekurangan inline style adalah jika kita menginginkan untuk memberi style pada seluruh tag atau kumpulan suatu tag, maka kita harus menyematkan atributnya di seluruh tag yang ada. Melelahkan dan membuat kode menjadi jorok atau tidak rapi.&#x20;

### Internal CSS

Internal CSS menjawab kekurangan inline style, untuk memberi style pada suatu group tag. Internal CSS dibuat dengan membuat tag \<style> dan mengisi-nya dengan aturan-aturan styling yang diinginkan. Perhatikan contoh berikut :

```markup
<style>
    body {
      background-color: grey;
    }
    h1 {
        color: gold;
    }
    
    p {
        background-color:aqua;
    }
</style>
<h1>Contoh Inline Style</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut fermentum, nunc nec sagittis porta, urna nunc pulvinar augue, ac efficitur felis urna nec odio. Phasellus sed rutrum tellus. Donec id lobortis tortor, et mattis nulla. Phasellus mollis tempus orci mattis ornare. Fusce pharetra congue dictum. Sed accumsan tempor aliquam. Aenean dictum, odio tristique consectetur suscipit, ante enim auctor velit, at vehicula sem nunc at purus. Cras vel mollis urna. Sed sed massa non tellus pulvinar bibendum ut et erat. Donec fringilla lobortis pellentesque. Morbi posuere libero malesuada magna viverra congue. Cras fermentum diam sit amet est lobortis rutrum. Vestibulum in ipsum pellentesque, auctor metus eget, dapibus leo. Sed commodo efficitur dui nec malesuada. Nunc at faucibus ante. Pellentesque porta nec nisi non suscipit.</p>
<p>Integer sed sodales ex. Ut consectetur eros quis ex fermentum placerat. Duis faucibus felis vel diam laoreet, vel varius tellus consequat. Ut dignissim lobortis dolor, in egestas mauris varius vulputate. Phasellus et ultrices est. Nulla viverra lectus felis, sit amet rhoncus felis congue a. Vestibulum eu tortor quis lectus tempus vehicula. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae.</p>
<p>Suspendisse non erat ultrices, imperdiet sem eget, egestas dolor. Aliquam at lectus convallis, bibendum enim quis, fringilla tellus. Aenean sodales nisl et ornare vestibulum. Nullam ut sagittis felis, ultricies ornare augue. Cras tempus nisi sed risus interdum scelerisque. Mauris faucibus risus id luctus auctor. Ut congue non orci eget egestas. Nunc pharetra vehicula enim. Integer vel venenatis metus. Nam imperdiet, velit sit amet facilisis suscipit, felis sem viverra quam, in elementum velit ante non neque. Sed enim dui, ornare in libero id, gravida sollicitudin libero. Mauris gravida, libero eget tincidunt luctus, elit arcu mollis orci, sollicitudin volutpat ipsum sem nec purus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae.</p>
```

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MfozC50FMKwt3DYuDQl%2F-MfpA89cfNlAuMyPm44W%2FScreen%20Shot%202021-07-30%20at%2009.08.48.png?alt=media\&token=93e7456a-7b4b-4d27-9169-bdb66717572c)

### Eksternal CSS

Dalam inline CSS, kode styling bercampur dengan kode html, yang kadang dengan alasan kerapian, kita ingin memisahkan kode styling tersebut. Jawaban-nya adalah dengan teknik eksternal CSS.

Buat file style.css dan pisahkan blok kode dalam tag \<style>, kemudian panggil file style.css tersebut dalam file index.html melalui tag link.

{% tabs %}
{% tab title="HTML" %}
{% code title="seri-belajar-pemrograman/html-css/index.html" %}

```markup
<!DOCTYPE html>
<html>
<head>
  <title>Judul Halaman</title>
  <link rel="stylesheet"  href="style.css"/>
</head>
<body>
  <h1>Contoh Inline Style</h1>
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut fermentum, nunc nec sagittis porta, urna nunc pulvinar augue, ac efficitur felis urna nec odio. Phasellus sed rutrum tellus. Donec id lobortis tortor, et mattis nulla. Phasellus mollis tempus orci mattis ornare. Fusce pharetra congue dictum. Sed accumsan tempor aliquam. Aenean dictum, odio tristique consectetur suscipit, ante enim auctor velit, at vehicula sem nunc at purus. Cras vel mollis urna. Sed sed massa non tellus pulvinar bibendum ut et erat. Donec fringilla lobortis pellentesque. Morbi posuere libero malesuada magna viverra congue. Cras fermentum diam sit amet est lobortis rutrum. Vestibulum in ipsum pellentesque, auctor metus eget, dapibus leo. Sed commodo efficitur dui nec malesuada. Nunc at faucibus ante. Pellentesque porta nec nisi non suscipit.</p>
  <p>Integer sed sodales ex. Ut consectetur eros quis ex fermentum placerat. Duis faucibus felis vel diam laoreet, vel varius tellus consequat. Ut dignissim lobortis dolor, in egestas mauris varius vulputate. Phasellus et ultrices est. Nulla viverra lectus felis, sit amet rhoncus felis congue a. Vestibulum eu tortor quis lectus tempus vehicula. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae.</p>
  <p>Suspendisse non erat ultrices, imperdiet sem eget, egestas dolor. Aliquam at lectus convallis, bibendum enim quis, fringilla tellus. Aenean sodales nisl et ornare vestibulum. Nullam ut sagittis felis, ultricies ornare augue. Cras tempus nisi sed risus interdum scelerisque. Mauris faucibus risus id luctus auctor. Ut congue non orci eget egestas. Nunc pharetra vehicula enim. Integer vel venenatis metus. Nam imperdiet, velit sit amet facilisis suscipit, felis sem viverra quam, in elementum velit ante non neque. Sed enim dui, ornare in libero id, gravida sollicitudin libero. Mauris gravida, libero eget tincidunt luctus, elit arcu mollis orci, sollicitudin volutpat ipsum sem nec purus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae.</p>
</body>
</html>
```

{% endcode %}
{% endtab %}

{% tab title="CSS" %}
{% code title="seri-belajar-pemrograman/html-css/style.css" %}

```css
body {
  background-color: grey;
}
h1 {
    color: gold;
}

p {
    background-color:aqua;
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

### Warna

Warna bisa ditentukan dengan menggunakan nama warna (predefined color name), atau nilai RGB, HEX, HSL, RGBA, HSLA.  Ada 140 nama warna standard yang telah ditentukan, yaitu:&#x20;

| Nama Warna (dikelompok-kan menurut abjad)                                                                                                                                                                                                                                                        |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| AliceBlue, AntiqueWhite, Aqua, Aquamarine, Azure                                                                                                                                                                                                                                                 |
| Beige, Bisque, Black, BlanchedAlmond, Blue, BlueViolet, Brown, BurlyWood                                                                                                                                                                                                                         |
| CadetBlue, Chartreuse, Chocolate, Coral, CornflowerBlue, Cornsilk, Crimson, Cyan                                                                                                                                                                                                                 |
| DarkBlue, DarkCyan, DarkGoldenRod, DarkGray, DarkGrey, DarkGreen, DarkKhaki, DarkMagenta, DarkOliveGreen, DarkOrange, DarkOrchid, DarkRed, DarkSalmon, DarkSeaGreen, DarkSlateBlue, DarkSlateGray, DarkSlateGrey, DarkTurquoise, DarkViolet, DeepPink, DeepSkyBlue, DimGray, DimGrey, DodgerBlue |
| FireBrick, FloralWhite, ForestGreen, Fuchsia                                                                                                                                                                                                                                                     |
| Gainsboro, GhostWhite, Gold, GoldenRod, Gray, Grey, Green, GreenYellow                                                                                                                                                                                                                           |
| HoneyDew, HotPink                                                                                                                                                                                                                                                                                |
| IndianRed, Indigo, Ivory                                                                                                                                                                                                                                                                         |
| Khaki                                                                                                                                                                                                                                                                                            |
| Lavender, LavenderBlush, LawnGreen, LemonChiffon, LightBlue, LightCoral, LightCyan, LightGoldenRodYellow, LightGray, LightGrey, LightGreen, LightPink, LightSalmon, LightSeaGreen, LightSkyBlue, LightSlateGray, LightSlateGrey, LightSteelBlue, LightYellow, Lime, LimeGreen, Linen             |
| Magenta, Maroon, MediumAquaMarine, MediumBlue, MediumOrchid, MediumPurple, MediumSeaGreen, MediumSlateBlue, MediumSpringGreen, MediumTurquoise, MediumVioletRed, MidnightBlue, MintCream, MistyRose, Moccasin                                                                                    |
| NavajoWhite, Navy                                                                                                                                                                                                                                                                                |
| OldLace, Olive, OliveDrab, Orange, OrangeRed, Orchid                                                                                                                                                                                                                                             |
| PaleGoldenRod, PaleGreen, PaleTurquoise, PaleVioletRed, PapayaWhip, PeachPuff, Peru, Pink, Plum, PowderBlue, Purple                                                                                                                                                                              |
| RebeccaPurple, Red, RosyBrown, RoyalBlue                                                                                                                                                                                                                                                         |
| SaddleBrown, Salmon, SandyBrown, SeaGreen, SeaShell, Sienna, Silver, SkyBlue, SlateBlue, SlateGray, SlateGrey, Snow, SpringGreen, SteelBlue                                                                                                                                                      |
| Tan, Teal, Thistle, Tomato, Turquoise                                                                                                                                                                                                                                                            |
| Violet                                                                                                                                                                                                                                                                                           |
| Wheat, White, WhiteSmoke                                                                                                                                                                                                                                                                         |
| Yellow, YellowGreen                                                                                                                                                                                                                                                                              |

Contoh penggunaan warna :

```markup
<h1 style="color:tomato;">Warna dengan nama tomato</h1>
<h1 style="color:#ff6347;">Warna dengan Hex - #ff6347</h1>
<h1 style="color: rgb(255, 99, 71);">Warna dengan RGB - rgb(255, 99, 71)</h1>
<h1 style="color: hsl(9, 100%, 64%);">Warna dengan HSL - hsl(9, 100%, 64%)</h1>
<h1 style="color: rgba(255, 99, 71, 0.5);">Warna dengan RGBA - rgba(255, 99, 71, 0.5)</h1>
<h1 style="color: hsla(9, 100%, 64%, 0.5);">Warna dengan HSLA - hsla(9, 100%, 64%, 0.5);</h1>
```

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MfpDzRb089bV5qxZSBF%2F-Mfs0CgG7-DpprAiCNX3%2FScreen%20Shot%202021-07-30%20at%2022.23.20.png?alt=media\&token=45cf882a-b4ba-4c10-83c1-1e578a9f014f)

Aturan styling terkait warna antara lain: \
\- color, misal **color:tomato**\
\- background-color, misal **background-color:tomato**\
\- border-color, misal **border-color:tomato**

### Font

Dalam pemilihan font, hal utama yang diperhatikan adalah keterbacaan. Pilihlah font yang memudahkan pembaca. Selain itu, karakter font juga akan  memberi pengalaman bagi pembaca. Di CSS ada lima keluarga font generik, yang memberi pengalaman berbeda bagi pembaca.

1. Font **serif** memiliki goresan kecil di tepi setiap huruf. Mereka menciptakan rasa formalitas dan keanggunan.&#x20;
2. Font **sans-serif** memiliki garis yang bersih (tidak ada goresan kecil yang terpasang). Mereka menciptakan tampilan modern dan minimalis.&#x20;
3. Font **monospace** - di sini semua huruf memiliki lebar tetap yang sama. Mereka menciptakan tampilan mekanis.&#x20;
4. Font **kursif** meniru tulisan tangan manusia.&#x20;
5. Font **fantasi** adalah font dekoratif/menyenangkan.&#x20;

Semua nama font pasti merupakan turunan dari salah satu 5 keluarga font di atas. "Times New Roman" masuk dalam keluarga serif. Arial, Verdana, Helvetica masuk dalam keluarga sans-serif.&#x20;

Dalam penerapan di styling font, sebaiknya setelah menyebut spesifik nama font-nya, kita juga memberi alternatif font lain (yang masih dalam keluarga sama), kemudian diakhiri dengan menyebutkan nama font generic-nya. Ini bertujuan jika nama font tersebut tidak ditemukan, maka akan disajikan font alternatifnya, dan jika masih tidak ditemukan maka akan menggunakan font generic. Perhatikan contoh berikut:&#x20;

```css
h1 {
  font-family: "Times New Roman", Times, serif;
}

h2 {
  font-family: Arial, Helvetica, sans-serif;
}

h3 {
  font-family: "Lucida Console", "Courier New", monospace;
}
```

### Ukuran Font

#### Ukuran Absolut

Untuk mengatur ukuran teks, css menyediakan properti font-size. Dengan properti ini kita bisa mengelola ukuran teks dalam desain web. Nilai ukuran font dapat berupa ukuran absolut, atau relatif. Untuk ukuran absolut bisa menggunakan px (pixel). Dengan pixel, ukuran akan tetap sehingga mudah untuk dikontrol. Bagi pemula, ukuran pixel jauh lebih mudah untuk dimaintenance.&#x20;

```markup
<style>
  h1 {
      font-size: 40px;
  }
  
  h2 {
    font-size: 30px;
  }
  
  p {
      font-size: 14px;
  }
</style>
<h1>Judul Utama</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut fermentum, nunc nec sagittis porta, urna nunc pulvinar augue, ac efficitur felis urna nec odio. Phasellus sed rutrum tellus. Donec id lobortis tortor, et mattis nulla. Phasellus mollis tempus orci mattis ornare. Fusce pharetra congue dictum. Sed accumsan tempor aliquam. Aenean dictum, odio tristique consectetur suscipit, ante enim auctor velit, at vehicula sem nunc at purus. Cras vel mollis urna. Sed sed massa non tellus pulvinar bibendum ut et erat. Donec fringilla lobortis pellentesque. Morbi posuere libero malesuada magna viverra congue. Cras fermentum diam sit amet est lobortis rutrum. Vestibulum in ipsum pellentesque, auctor metus eget, dapibus leo. Sed commodo efficitur dui nec malesuada. Nunc at faucibus ante. Pellentesque porta nec nisi non suscipit.</p>
<p>Integer sed sodales ex. Ut consectetur eros quis ex fermentum placerat. Duis faucibus felis vel diam laoreet, vel varius tellus consequat. Ut dignissim lobortis dolor, in egestas mauris varius vulputate. Phasellus et ultrices est. Nulla viverra lectus felis, sit amet rhoncus felis congue a. Vestibulum eu tortor quis lectus tempus vehicula. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae.</p>
<h2>Sub Judul</h2>
<p>Suspendisse non erat ultrices, imperdiet sem eget, egestas dolor. Aliquam at lectus convallis, bibendum enim quis, fringilla tellus. Aenean sodales nisl et ornare vestibulum. Nullam ut sagittis felis, ultricies ornare augue. Cras tempus nisi sed risus interdum scelerisque. Mauris faucibus risus id luctus auctor. Ut congue non orci eget egestas. Nunc pharetra vehicula enim. Integer vel venenatis metus. Nam imperdiet, velit sit amet facilisis suscipit, felis sem viverra quam, in elementum velit ante non neque. Sed enim dui, ornare in libero id, gravida sollicitudin libero. Mauris gravida, libero eget tincidunt luctus, elit arcu mollis orci, sollicitudin volutpat ipsum sem nec purus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae.</p>
```

#### Ukuran Relatif

Ukuran relatif memberikan keleluasaan bagi user untuk mendapatkan ukuran font sesuai dengan acuan ukuran font secara default, kemudian ukuran-ukuran lain akan diatur berdasarkan ukuran font induknya. Ukuran yang digunakan yaitu em, dan % (persen).

Secara default, ukuran em adalah 16px. Artinya 1 em = 16px. Kita bisa mengkonversi px menjadi em dengan rumus di atas. Misalkan ukuran font H1 = 40px, dan kita ingin mengubahnya dalam format em, maka kita bisa menggunakan rumus : 40/16 = 2.5 em.

Jika kita ubah kode pixel sebelumnya menjadi em, maka akan menjadi seperti berikut:

```markup
<style>
  h1 {
      font-size: 2.5em; /* 40px/16=2.5em */
  }
  
  h2 {
    font-size: 1.875em;
  }
  
  p {
      font-size: 0.875em;
  }
</style>
<h1>Judul Utama</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut fermentum, nunc nec sagittis porta, urna nunc pulvinar augue, ac efficitur felis urna nec odio. Phasellus sed rutrum tellus. Donec id lobortis tortor, et mattis nulla. Phasellus mollis tempus orci mattis ornare. Fusce pharetra congue dictum. Sed accumsan tempor aliquam. Aenean dictum, odio tristique consectetur suscipit, ante enim auctor velit, at vehicula sem nunc at purus. Cras vel mollis urna. Sed sed massa non tellus pulvinar bibendum ut et erat. Donec fringilla lobortis pellentesque. Morbi posuere libero malesuada magna viverra congue. Cras fermentum diam sit amet est lobortis rutrum. Vestibulum in ipsum pellentesque, auctor metus eget, dapibus leo. Sed commodo efficitur dui nec malesuada. Nunc at faucibus ante. Pellentesque porta nec nisi non suscipit.</p>
<p>Integer sed sodales ex. Ut consectetur eros quis ex fermentum placerat. Duis faucibus felis vel diam laoreet, vel varius tellus consequat. Ut dignissim lobortis dolor, in egestas mauris varius vulputate. Phasellus et ultrices est. Nulla viverra lectus felis, sit amet rhoncus felis congue a. Vestibulum eu tortor quis lectus tempus vehicula. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae.</p>
<h2>Sub Judul</h2>
<p>Suspendisse non erat ultrices, imperdiet sem eget, egestas dolor. Aliquam at lectus convallis, bibendum enim quis, fringilla tellus. Aenean sodales nisl et ornare vestibulum. Nullam ut sagittis felis, ultricies ornare augue. Cras tempus nisi sed risus interdum scelerisque. Mauris faucibus risus id luctus auctor. Ut congue non orci eget egestas. Nunc pharetra vehicula enim. Integer vel venenatis metus. Nam imperdiet, velit sit amet facilisis suscipit, felis sem viverra quam, in elementum velit ante non neque. Sed enim dui, ornare in libero id, gravida sollicitudin libero. Mauris gravida, libero eget tincidunt luctus, elit arcu mollis orci, sollicitudin volutpat ipsum sem nec purus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae.</p>
```

Namun karena ukuran em adalah ukuran relatif,  pada prakteknya ukuran em akan mengacu pada ukuran font induknya. Jika tidak diatur secara spesifik ukuran font induk memang akan 16px, tapi jika diatur maka 1 em tidak lagi persis = 16px, melainkan sebesar ukuran font induk. Untuk lebih memahami relatifitas ukuran em, perhatikan dua kasus berikut.

Kasus 1 : \
\- Ukuran font body = 14px\
\- Ukuran H1 = 1.6 em. \
maka ukuran sebenarnya H1 adalah 14 px \* 1.6 = 22.4px\
\
Kasus 2 :\
\- Ukuran font body = 16px\
\- Ukuran H1 = 1.6 em.\
maka ukuran sebenarnya H1 adalah 16px \* 1.6 = 25.6 px

Begitu pula dengan ukuran % (persen), besaran font bergantung pada ukuran font dari induknya. Jika ukuran font body = 14 px dan ukuran H1 = 1.5% maka ukuran sebenarnya adalah  21px.  &#x20;

#### Mengkombinasikan persen dan em untuk menghasilkan ukuran yang benar-benar relatif

Biasanya ukuran em dikombinasikan dengan ukuran persen untuk memastikan kode berfungsi dengan baik, dan kompatible di semua browser.

```markup
<style>
  body {
    font-size:100%;
  }
    
  h1 {
      font-size: 2.5em;
  }
  
  h2 {
    font-size: 1.875em;
  }
  
  p {
      font-size: 0.875em;
  }
</style>
<h1>Judul Utama</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut fermentum, nunc nec sagittis porta, urna nunc pulvinar augue, ac efficitur felis urna nec odio. Phasellus sed rutrum tellus. Donec id lobortis tortor, et mattis nulla. Phasellus mollis tempus orci mattis ornare. Fusce pharetra congue dictum. Sed accumsan tempor aliquam. Aenean dictum, odio tristique consectetur suscipit, ante enim auctor velit, at vehicula sem nunc at purus. Cras vel mollis urna. Sed sed massa non tellus pulvinar bibendum ut et erat. Donec fringilla lobortis pellentesque. Morbi posuere libero malesuada magna viverra congue. Cras fermentum diam sit amet est lobortis rutrum. Vestibulum in ipsum pellentesque, auctor metus eget, dapibus leo. Sed commodo efficitur dui nec malesuada. Nunc at faucibus ante. Pellentesque porta nec nisi non suscipit.</p>
<p>Integer sed sodales ex. Ut consectetur eros quis ex fermentum placerat. Duis faucibus felis vel diam laoreet, vel varius tellus consequat. Ut dignissim lobortis dolor, in egestas mauris varius vulputate. Phasellus et ultrices est. Nulla viverra lectus felis, sit amet rhoncus felis congue a. Vestibulum eu tortor quis lectus tempus vehicula. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae.</p>
<h2>Sub Judul</h2>
<p>Suspendisse non erat ultrices, imperdiet sem eget, egestas dolor. Aliquam at lectus convallis, bibendum enim quis, fringilla tellus. Aenean sodales nisl et ornare vestibulum. Nullam ut sagittis felis, ultricies ornare augue. Cras tempus nisi sed risus interdum scelerisque. Mauris faucibus risus id luctus auctor. Ut congue non orci eget egestas. Nunc pharetra vehicula enim. Integer vel venenatis metus. Nam imperdiet, velit sit amet facilisis suscipit, felis sem viverra quam, in elementum velit ante non neque. Sed enim dui, ornare in libero id, gravida sollicitudin libero. Mauris gravida, libero eget tincidunt luctus, elit arcu mollis orci, sollicitudin volutpat ipsum sem nec purus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae.</p>
```

#### Ukuran Responsif

Ukuran responsif membuat ukuran font menjadi responsif terhadap perubahan lebar screen atau device. Keterbacaan menjadi lebih tinggi karena ukuran bisa menyesuaikan dengan device yang digunakan. Untuk ukuran relatif digunakan satuan vw (viewport width). Dengan vw, ukuran teks akan mengikuti ukuran jendela browser.

```markup
<style>
  h1 {
    font-size: 8vw;
  }
  
  h2 {
    font-size: 5vw;
  }
  
  p {
    font-size: 3vw;
  }
</style>
<h1>Judul Utama</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut fermentum, nunc nec sagittis porta, urna nunc pulvinar augue, ac efficitur felis urna nec odio. Phasellus sed rutrum tellus. Donec id lobortis tortor, et mattis nulla. Phasellus mollis tempus orci mattis ornare. Fusce pharetra congue dictum. Sed accumsan tempor aliquam. Aenean dictum, odio tristique consectetur suscipit, ante enim auctor velit, at vehicula sem nunc at purus. Cras vel mollis urna. Sed sed massa non tellus pulvinar bibendum ut et erat. Donec fringilla lobortis pellentesque. Morbi posuere libero malesuada magna viverra congue. Cras fermentum diam sit amet est lobortis rutrum. Vestibulum in ipsum pellentesque, auctor metus eget, dapibus leo. Sed commodo efficitur dui nec malesuada. Nunc at faucibus ante. Pellentesque porta nec nisi non suscipit.</p>
<p>Integer sed sodales ex. Ut consectetur eros quis ex fermentum placerat. Duis faucibus felis vel diam laoreet, vel varius tellus consequat. Ut dignissim lobortis dolor, in egestas mauris varius vulputate. Phasellus et ultrices est. Nulla viverra lectus felis, sit amet rhoncus felis congue a. Vestibulum eu tortor quis lectus tempus vehicula. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae.</p>
<h2>Sub Judul</h2>
<p>Suspendisse non erat ultrices, imperdiet sem eget, egestas dolor. Aliquam at lectus convallis, bibendum enim quis, fringilla tellus. Aenean sodales nisl et ornare vestibulum. Nullam ut sagittis felis, ultricies ornare augue. Cras tempus nisi sed risus interdum scelerisque. Mauris faucibus risus id luctus auctor. Ut congue non orci eget egestas. Nunc pharetra vehicula enim. Integer vel venenatis metus. Nam imperdiet, velit sit amet facilisis suscipit, felis sem viverra quam, in elementum velit ante non neque. Sed enim dui, ornare in libero id, gravida sollicitudin libero. Mauris gravida, libero eget tincidunt luctus, elit arcu mollis orci, sollicitudin volutpat ipsum sem nec purus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae.</p>
```

### Class dan Id

Id merupakan *unique identity* dari sebuah *element*. Dalam satu halaman tidak boleh ada *element* yang mempunyai id yang sama. Sementara *class* adalah *grouping identity* dari beberapa *element*. Beberapa elemen yg dikelompokkan dalam *class* yang sama bisa diatur sehingga mempunyai styling yang sama. Untuk penulisan di css, id ditandai dengan # sementara class menggunakan titik atau dot.

```css
<style>
  #main {
    color: gold;
  }
  .hGroup {
    color: pink;
  }
</style>
<h1 id="main">Judul Utama</h1>
<h1>Judul Biasa</h1>
<h1 class="hGroup">Judul Class</h1>
<h1 class="hGroup">Judul Class</h1>
<h1 class="hGroup">Judul Class</h1>
```

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-Mfs5XnhmSPCaVXmguh8%2F-Mfs8Txt-cTF2rlixbDd%2FScreen%20Shot%202021-07-30%20at%2023.00.21.png?alt=media\&token=872b8520-d7eb-4878-af7f-809ebbc620da)


# List

Elemen list digunakan untuk membuat suatu list atau daftar. HTML menyediakan dua jenis list, yaitu *ordered list* (list berurutan) dan *unordered list* (list tidak berurutan). Setelah elemen list dibuat, kita bisa mengisinya dengan *list item* sebanyak yang diinginkan. Tag \<li> digunakan untuk membuat *list item*.

### List Berurutan

Tag \<ol> atau *ordered list* digunakan untuk membuat list yang berurutan.

```markup
<ol>
    <li>Jakarta</li>
    <li>Surabaya</li>
    <li>Denpasar</li>
</ol>
```

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MfwQFbEQk0xjvEWcPV3%2F-MfwRnNPzbW2apMbU201%2FScreen%20Shot%202021-07-31%20at%2019.03.20.png?alt=media\&token=a26e2155-accb-4ac9-82d9-28c2e5bff061)

Secara default urutan list ditentukan dengan angka. Jika ingin mengubah jenis urutan, kita bisa memanfaatkan aturan-aturan pada css, yaitu : **list-style-type**.

```markup
<style>
    ol {
        list-style-type: lower-latin;
    } 
</style>
<ol>
    <li>Jakarta</li>
    <li>Surabaya</li>
    <li>Denpasar</li>
</ol>
```

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MfwQFbEQk0xjvEWcPV3%2F-MfwTaLQjwQTlkYpnAmo%2FScreen%20Shot%202021-07-31%20at%2019.11.10.png?alt=media\&token=a74cf26a-4e72-410a-be93-0c9edf66ef28)

Ada banyak tipe list-style, saya akan menuliskan beberapa yang sering digunakan, yaitu : decimal-leading-zero, lower-latin, lower-roman, upper-latin, dan upper-roman.

### List Tidak Berurutan

Tag \<ul> atau *unordered list* digunakan untuk membuat list yang tidak berurutan.

```markup
<ul>
    <li>Jakarta</li>
    <li>Surabaya</li>
    <li>Denpasar</li>
</ul>
```

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MfwQFbEQk0xjvEWcPV3%2F-MfwUWR-Qu4BlDVezwhy%2FScreen%20Shot%202021-07-31%20at%2019.15.21.png?alt=media\&token=80c03cac-8e40-4f81-8200-afdbb7411e5e)

Secara default urutan list ditentukan dengan ***disc***. Jika ingin mengubah tipe list, kita bisa memanfaatkan aturan-aturan pada css, yaitu : **list-style-type**.

```markup
<style>
    ul {
        list-style-type: circle;
    }
</style>

<ul>
    <li>Jakarta</li>
    <li>Surabaya</li>
    <li>Denpasar</li>
</ul>
```

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MfwWowqDbtRfrYTRk7u%2F-MfwZ78tqx67kP-RVbZX%2FScreen%20Shot%202021-07-31%20at%2019.35.09.png?alt=media\&token=66c052e8-175f-45cb-9ac2-98ab1dc664d2)

Tipe list-style untuk *unordered list* yang sering digunakan adalah: circle, square, dan none.


# Tabel

## Table, Baris dan Kolom

* Element \<table> untuk membuat tabel
* Elemen \<tr> atau *table row* untuk membuat baris
* Elemen \<th> atau *table header* untuk membuat kolom header
* Elemen \<td> atau *table data* untuk membuat kolom

```markup
<table>
    <tr>
        <th>Nama</th>
        <th>Kota</th>
    </tr>
    <tr>
        <td>Rijal</td>
        <td>Jakarta</td>
    </tr>
    <tr>
        <td>Jacky</td>
        <td>Denpasar</td>
    </tr>
    <tr>
        <td>Ayoen</td>
        <td>Purbalingga</td>
    </tr>
</table>
```

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-Mfwcpt-KrcR52diUkZ-%2F-Mfwgrn28P9OoM7ya4_B%2FScreen%20Shot%202021-07-31%20at%2020.01.54.png?alt=media\&token=814c215d-d9d7-4d8b-a2dd-c33924a3c650)

Kita bisa menggunakan css untuk mempercantik tampilan tabel.

```markup
<style>
    table {
      width:100%;
    }

    table td, table th {
      border: 1px solid grey;
      padding: 10px;
    }

    table th {
      background-color: darkorange;
      text-align: left;
      color: white;
    }

    table tr:nth-child(even){
      background-color: lightgray;
    }

    table tr:hover {
      background-color:gray;
    }
</style>
<table>
    <tr>
        <th>Nama</th>
        <th>Kota</th>
    </tr>
    <tr>
        <td>Rijal</td>
        <td>Jakarta</td>
    </tr>
    <tr>
        <td>Jacky</td>
        <td>Denpasar</td>
    </tr>
    <tr>
        <td>Ayoen</td>
        <td>Purbalingga</td>
    </tr>
</table>
```

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-Mfwcpt-KrcR52diUkZ-%2F-MfwhG5i0u4nzag9Ul4v%2FScreen%20Shot%202021-07-31%20at%2020.15.22.png?alt=media\&token=1b5a7128-dd3d-44ab-9cb0-a91e527f613e)

## Merge Baris dan Merge Kolom

Untuk menggabungkan 2 baris menjadi 1, gunakan atribut ***rowspan***. Sementara untuk menggabungkan 2 kolom menjadi satu, gunakan atribut ***colspan***.

```markup
<style>
  table {
    width:100%;
  }

  table td, table th {
    border: 1px solid grey;
    padding: 10px;
  }

  table th {
    background-color: darkorange;
    text-align: left;
    color: white;
  }

  table th.alignCenter {
    text-align: center;
  }

  table tr:nth-child(even){
    background-color: lightgray;
  }

  table tr:hover {
    background-color:gray;
  }
</style>
<table>
  <tr>
    <th rowspan="2">Nama</th>
    <th rowspan="2">Kota</th>
    <th colspan="3" class="alignCenter">Iuran</th>
  </tr>
  <tr>
    <th class="alignCenter">Jan</th>
    <th class="alignCenter">Feb</th>
    <th class="alignCenter">Mart</th>
  </tr>
  <tr>
    <td>Rijal</td>
    <td>Jakarta</td>
    <td>&#9745;</td>
    <td>&#9745;</td>
    <td>&#9745;</td>
  </tr>
  <tr>
    <td>Jacky</td>
    <td>Denpasar</td>
    <td>&#9745;</td>
    <td>&#9745;</td>
    <td>&#9744;</td>
  </tr>
  <tr>
    <td>Ayoen</td>
    <td>Purbalingga</td>
    <td>&#9744;</td>
    <td>&#9744;</td>
    <td>&#9744;</td>
  </tr>
</table>
```

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MfwqsY_uLQnz7ndNmta%2F-MfwtFE5RL2aQK0FqkzT%2FScreen%20Shot%202021-07-31%20at%2021.06.31.png?alt=media\&token=7bed3af5-3fd6-425e-9f1f-e1fcf26730db)


# Link, Gambar dan Multimedia

## Link

Untuk membuat link dari satu halaman ke halaman lain, gunakan hyperlink dengan tag \<a>

```markup
<ul>
    <li><a href="judul.html">Judul</a></li>
    <li><a href="paragraf.html">Paragraf</a></li>
    <li><a href="font-size.html">Font Size</a></li>
    <li><a href="color.html">Warna</a></li>
</ul>

<p>Dalam HTML, <a href="list.html">list</a> sering kali digunakan untuk menampilkan daftar suatu benda. <a href="list.html">List</a> juga sering digunakan dalam membuat menu dalam layout HTML</p>
```

## Gambar

Gunakan tag \<img/> untuk menampilkan file gambar. Atribut utama \<img/> adalah src dan alt. src diisi dengan source file gambar (bisa berupa url maupun path direktori file), sementara alt adalah alternatif teks yang ditampilkan jika source gambar tidak berhasil dimuat. Sebenarnya ada atribut lain width dan height juga, tapi saya pribadi lebih suka memasang width dan height di dalam style, untuk mencegah atribut width dan height gambar sudah dipasang sebagai atribut gambar namun ternyata tidak berlaku karena di-override oleh css.

```markup
<style>
  div {
    width:100%;
  }

  img {
    height:30vw;
    width: calc(50% - 2px);
    float:left;
    border: 1px solid white;
  }
</style>
<div>
  <img src="./erp.png" alt="ERP Software"/>
  <img src="https://cdn.pixabay.com/photo/2015/04/19/08/32/marguerite-729510__340.jpg" alt="bunga yang cantik"/>
</div>
```

* Div digunakan untuk mengelompokkan semua gambar dalam 1 group element.
* Tinggi gambar dibuat responsif dengan ukuran vw
* Float digunakan untuk membuat gambar menjadi floating (defaultnya adalah block) sehingga bisa ditampilkan secara berdampingan.
* Border digunakan agar ada jarak antara 2 gambar.
* Lebar sebenarnya dibuat 50%, namun karena ada border 1px di masing-masing gambar maka pengaturan lebar menjadi 50% - (2gambar x 1 pixel). CSS menyediakan penghitungan seperti ini melalui calc. sehingga width : calc(50% - 2px). &#x20;

File html di atas jika dibuka di browser akan tampil seperti gambar di bawah ini. Jika browser diubah-ubah lebar dan tinggi-nya, tampilan gambar akan responsif mengikuti perubahan lebar dan tinggi browser.

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-Mfx6Wu3o9Boi736opBN%2F-MfzpubxW9bd2buH6O3N%2FScreen%20Shot%202021-08-01%20at%2010.51.56.png?alt=media\&token=321d9a4e-60a6-483d-8ba1-48251f818a97)

File format gambar yang didukung oleh html meliputi :

| Abbreviation | File Format                           | File Extension                   |
| ------------ | ------------------------------------- | -------------------------------- |
| APNG         | Animated Portable Network Graphics    | .apng                            |
| GIF          | Graphics Interchange Format           | .gif                             |
| ICO          | Microsoft Icon                        | .ico, .cur                       |
| JPEG         | Joint Photographic Expert Group image | .jpg, .jpeg, .jfif, .pjpeg, .pjp |
| PNG          | Portable Network Graphics             | .png                             |
| SVG          | Scalable Vector Graphics              | .svg                             |

## Multimedia

Multimedia di web adalah suara, musik, video, film, dan animasi. Multimedia hadir dalam berbagai format. Namun tidak semua didukung oleh HTML, hanya sebagian kecil format multimedia yang didukung oleh broser.

### Audio

HTML hanya mendukung 3 format audio, yaitu: MP3, WAV dan Ogg. Selain itu, HTML juga mendukung file MP4, yang sebenarnya adalah format untuk video, namun bisa juga digunakan untuk audio.

| Format | File | Description                                                                                                                                                       |
| ------ | ---- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| WAV    | .wav | WAV. Developed by IBM and Microsoft. Plays well on Windows, Macintosh, and Linux operating systems.                                                               |
| Ogg    | .ogg | Ogg. Developed by the Xiph.Org Foundation.                                                                                                                        |
| MP3    | .mp3 | MP3 files are actually the sound part of MPEG files. MP3 is the most popular format for music players. Combines good compression (small files) with high quality. |
| MP4    | .mp4 | MP4 is a video format, but can also be used for audio.                                                                                                            |

Untuk menampilkan audio, gunakan element \<audio>

```markup
<audio controls>
  <source src="sample-3s.mp3" type="audio/mpeg">
  Your browser does not support the audio element.
</audio>
```

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MfzqpdC1zBgnHXCsSJM%2F-Mg-9OxNLA5v5hR3Bmo3%2FScreen%20Shot%202021-08-01%20at%2012.21.41.png?alt=media\&token=7098c253-136c-4a21-a0c4-c367e0d5dd6f)

### Video

HTML mendukung tiga format file multimedia, meliputi .ogg, .webm dan .mp4

| Format        | File  | Description                                                                                         |
| ------------- | ----- | --------------------------------------------------------------------------------------------------- |
| Ogg           | .ogg  | Theora Ogg. Developed by the Xiph.Org Foundation.                                                   |
| WebM          | .webm | WebM. Developed by Mozilla, Opera, Adobe, and Google.                                               |
| MPEG-4 or MP4 | .mp4  | MP4. Developed by the Moving Pictures Expert Group. Commonly used in video cameras and TV hardware. |

Untuk menampilkan video, gunakan element \<video>

```markup
<video width="100%" height="500vw">
  <source src="sample-mp4-file.mp4" type="video/mp4">
  Your browser does not support the video tag.
</video>
```

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MfzqpdC1zBgnHXCsSJM%2F-Mg-6hJv9z5T6zFjOuVu%2FScreen%20Shot%202021-08-01%20at%2012.09.42.png?alt=media\&token=331440b2-1ca8-4e18-b570-394c98f10e77)

Tampilan di browser tampak seperti gambar saja, ini dikarenakan di kode di atas tidak mengaktifkan controls. Tambahkan atribut controls seperti kode berikut :

```markup
<video width="100%" height="500vw" controls>
  <source src="sample-mp4-file.mp4" type="video/mp4">
  Your browser does not support the video tag.
</video>
```

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MfzqpdC1zBgnHXCsSJM%2F-Mg-7Hltk2mtzGx2-qSV%2FScreen%20Shot%202021-08-01%20at%2012.12.18.png?alt=media\&token=11c49208-1eae-4912-95ee-d51a33e0ba62)

Sekarang video bisa diputar, di-pause, diatur volumenya, fullscreen dan sebagianya. Kita bisa menambahkan autoplay agar ketika halaman dibuka, video langsung play. Namun browser keluarga chromimum (chromium, chrome, safari, microsoft edge) tidak mendukung autoplay. Browser keluarga chromium hanya mendukung autoplay jika dikombinasikan dengan atribut muted.

```markup
<video width="100%" height="500vw" controls autoplay muted>
  <source src="sample-mp4-file.mp4" type="video/mp4">
  Your browser does not support the video tag.
</video>
```


# Layout

Layout adalah desain tata letak, suatu bentuk penataan desain dalam elemen tertentu yang telah ditata secara artistik, sehingga akan menarik & indah untuk dilihat dan digunakan.

Untuk layout, ada 4 teknik yang bisa digunakan, yaitu :

1. Table
2. Position (table-less)
3. Flexbox
4. Grid

Table digunakan untuk layout pada awal-awal teknologi web berkembang. Namun rendering table yang cukup lambat dan munculnya teknik position di css, menjadikan layout dengan table segera ditinggalkan.

Teknik position digunakan dalam layout karena dipandang lebih cepat performance-nya daripada tabel. Sementara tabel tetap digunakan secara alami ketika hendak menampilkan data-data dalam bentuk tabel. Aturan-aturan yang diterapkan terkait styling position yaitu :

* position : relative | absolute
* float : left | right
* clear: left | right | both
* top : x px
* bottom: x px
* left: x px
* right: x px

Karena tidak menggunakan table, teknik position juga dikenal dengan istilah table-less. Namun layouting dengan teknik position dianggap sangat rumit dan tidak memudahkan developer.

Dua teknik terbaru yang muncul dalam layout adalah flexbox dan grid. Kedua teknik ini sangat powerfull jika dibandingkan dengan teknik position.

## Layout HTML

Dalam pembahaasan kali ini, kita akan membahas dua teknik layout, yaitu position dan flexbox. Baik position maupun flexbox akan menggunakan satu file html yang sama. File html ini disusun dengan menggunakan tag-tag layouting yang ramah terhadap search engine, seperti header, footer, nav, aside, dan section.

Kita bisa saja menggunakan div (dengan nama class header), namun hal ini tidak mendatangkan benefit bagi search engine. Dengan tag layout, search engine akan mengenal mana informasi yang penting berdasarkan tag yang digunakan (misal informasi yang ada di header, nav atau section).

### Header

Bagian ujung depan yang digunakan di bagian atas halaman. Tag \<header> digunakan untuk menambahkan bagian header di halaman web. Informasi judul (\<h1> atau \<h2>) yang diletakkan di header dianggap penting oleh search engine.

### Footer

Bagian footer berisi informasi kontak dan hal lain yang terkait dengan halaman web. Bagian footer selalu diletakkan di bagian bawah halaman web. Tag \<footer> digunakan untuk mengatur footer di halaman web.

### Section

Bagian konten adalah bagian utama tempat konten ditampilkan. Semua informasi dalam bentuk judul atau subjudul (h1/h2/h3), \<strong>, \<em>, dan hyperlink yang ada dalam bagian section akan dicrawl oleh search engine. Untuk membuat section gunakan tag \<section>.

### Aside

Aside merupan bagian tambahan yang menyimpan informasi atau iklan tambahan dan tidak selalu perlu ditambahkan ke halaman. Search engine tidak menganggap tag ini penting, sehingga jika ingin menampilkan informasi tambahan yang kurang penting (tidak berkaitan dengan artikel dan keyword), bisa ditampilkan dalam element aside. Gunakan tag \<aside> untuk membuat elemen aside.

### Nav

Nav merupakan bilah navigasi yang sama dengan daftar menu. Ini digunakan untuk menampilkan informasi konten menggunakan hyperlink. Search engine akan mengcrawler tag navigasi ini. Untuk membuat navigasi, gunakan tag \<nav>.

Tampilan layout yang hendak dibuat dalam bab ini adalah seperti berikut :

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MgulPHNS8c-a-46F3oW%2F-MgyMRSsTtIOMDwlU7uc%2Flayout.png?alt=media\&token=32cf6657-7a62-4321-9a09-2bb721071495)

Baiklah kita mulai, untuk mempraktekkan layout di html, buat file layout.html yang diisi dengan kode berikut:

{% code title="layout.html" %}

```markup
<!DOCTYPE html>
<html>
  <head>
    <title>Layout</title>
  </head>
  <body>
    <header>
      <h1>Learning Management System</h1>
      <h2>SMP/SMA Merdeka</h2>
    </header>
    <nav>
      <ul>
        <li><a href="">Kelas Online</a></li>
        <li><a href="">Materi Belajar Mandiri</a></li>
        <li><a href="">Tugas</a></li>
        <li><a href="">Latihan Soal Mandiri</a></li>
        <li><a href="">Ujian Online</a></li>
        <li><a href="">Kalender</a></li>
      </ul>
    </nav>
    <div id="main-content">
      <aside>
        <img src="erp.png"/>
        <h3>Ikuti Kelas Terbaru : ERP (Enterprise Resource Planning)</h3>
      </aside>
      <section>
        <h2>Selamat Datang di Learning Management System</h2>
        <article>
          <h3>Anak Merdeka</h3>
          <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ullamcorper eleifend ipsum vitae congue. Donec vel justo porttitor nisi lobortis imperdiet. Etiam eget nunc a nunc imperdiet luctus eu nec orci. Mauris et nibh imperdiet, semper eros et, auctor dolor. Phasellus bibendum fermentum ipsum ut lacinia. Aliquam gravida, velit efficitur sollicitudin faucibus, sapien leo rhoncus urna, eget pharetra risus felis eu lorem. Proin pretium suscipit pulvinar. In eget massa sed tellus luctus congue a viverra tellus. Praesent sit amet posuere arcu, vitae convallis augue. Maecenas non gravida est. Aenean bibendum ex nec luctus volutpat. Fusce sit amet mauris pulvinar, finibus odio accumsan, cursus tellus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla convallis, sapien vel mattis scelerisque, augue sem vulputate mauris, a suscipit purus velit ut lectus. Donec bibendum elit vel posuere tincidunt. Fusce nec turpis dolor.</p>
        </article>
        <article>
          <h3>Anak Merdeka</h3>
          <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ullamcorper eleifend ipsum vitae congue. Donec vel justo porttitor nisi lobortis imperdiet. Etiam eget nunc a nunc imperdiet luctus eu nec orci. Mauris et nibh imperdiet, semper eros et, auctor dolor. Phasellus bibendum fermentum ipsum ut lacinia. Aliquam gravida, velit efficitur sollicitudin faucibus, sapien leo rhoncus urna, eget pharetra risus felis eu lorem. Proin pretium suscipit pulvinar. In eget massa sed tellus luctus congue a viverra tellus. Praesent sit amet posuere arcu, vitae convallis augue. Maecenas non gravida est. Aenean bibendum ex nec luctus volutpat. Fusce sit amet mauris pulvinar, finibus odio accumsan, cursus tellus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla convallis, sapien vel mattis scelerisque, augue sem vulputate mauris, a suscipit purus velit ut lectus. Donec bibendum elit vel posuere tincidunt. Fusce nec turpis dolor.</p>
        </article>
        <article>
          <h3>Anak Merdeka</h3>
          <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ullamcorper eleifend ipsum vitae congue. Donec vel justo porttitor nisi lobortis imperdiet. Etiam eget nunc a nunc imperdiet luctus eu nec orci. Mauris et nibh imperdiet, semper eros et, auctor dolor. Phasellus bibendum fermentum ipsum ut lacinia. Aliquam gravida, velit efficitur sollicitudin faucibus, sapien leo rhoncus urna, eget pharetra risus felis eu lorem. Proin pretium suscipit pulvinar. In eget massa sed tellus luctus congue a viverra tellus. Praesent sit amet posuere arcu, vitae convallis augue. Maecenas non gravida est. Aenean bibendum ex nec luctus volutpat. Fusce sit amet mauris pulvinar, finibus odio accumsan, cursus tellus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla convallis, sapien vel mattis scelerisque, augue sem vulputate mauris, a suscipit purus velit ut lectus. Donec bibendum elit vel posuere tincidunt. Fusce nec turpis dolor.</p>
        </article>
      </section>
    </div>
    <footer>
      Copyright &copy; 2021
    </footer>
  </body>
</html>
```

{% endcode %}

## Layout CSS

Pertama kita akan membuat styling untuk tag-tag yang digunakan agar tampil lebih menarik secara visual. Buat file style.css dan tambahkan link css tersebut dalam head htrml.

{% tabs %}
{% tab title="CSS" %}
{% code title="style.css" %}

```css
* {
  padding:0;
  margin:0;
}

body {
  font-family: Arial;
}

header{
  padding: 5px;
  text-align: center;
  background: orange;
  color: white;
}

nav {
  overflow: hidden;
  background-color: #333;
  padding:8px 0;
}

nav ul {
  list-style: none;
}

nav ul li {
  display: inline;
  padding: 14px 10px;
}

nav ul li a {
  color: white;
  padding: 14px 20px;
  text-decoration: none;
  text-align: center;
}

nav ul li a:hover {
  background-color: gold;
  color: black;
}

aside {
  background-color: #f1f1f1;
  padding: 20px;
}

aside img {
  width:100%;
}

section {
  background-color: white;
  padding: 20px;
}

article {
  border-bottom: 1px solid silver;
}

footer {
  padding: 20px;
  text-align: center;
  background: darkorange;
}

h1, h2, h3, p {
  padding: 1%;
}
```

{% endcode %}
{% endtab %}

{% tab title="HTML" %}
{% code title="layout.html" %}

```markup
<head>
    <title>Layout</title>
    <link rel="stylesheet" href="style.css"/>
</head>
```

{% endcode %}
{% endtab %}
{% endtabs %}

### Position

Untuk kemudahan pembelajaran, styling layout saya pisahkan file-nya dengan nama table-less.css

{% tabs %}
{% tab title="CSS" %}
{% code title="table-less.css" %}

```css
aside {
  float: left;
  width: calc(30% - 40px);
}

section {
  float: right;
  width: calc(70% - 40px);
}

footer {
  clear: both;
}
```

{% endcode %}
{% endtab %}

{% tab title="HTML" %}
{% code title="layout.html" %}

```markup
<head>
    <title>Layout</title>
    <link rel="stylesheet" href="style.css"/>
    <link rel="stylesheet" href="tableless.css"/>
  </head>
```

{% endcode %}
{% endtab %}
{% endtabs %}

Halaman akan tampak seperti berikut :

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MguTv0Dd_wyb-rITsCD%2F-MgubcRqMvGNLc6HgEl0%2FScreen%20Shot%202021-08-12%20at%2020.45.16.png?alt=media\&token=8df1c3b3-dd66-40f2-8cb5-530f44bad417)

Jika diperhatikan, tinggi aside dan tinggi section tidaklah sama. Ini salah satu kelemahan layout dengan menggunakan teknik position, untuk mengakali hal ini, biasanya dilakukan dengan smengatur tinggi aside secara dinamis mengikuti tinggi section menggunakan jacascript.

### Flex

Namun permasalahan di atas sangat mudah dipecahkan jika menggunakan teknik flex. Flex terdiri dari 2 komponen, flex container dan flex item. flex container merupakan induk, sementara flex item merupakan anak.

Mengacu pada html yang sudah dibuat di atas, \<div id="main-content"> adalah flex container (induk), sementara \<aside> dan \<section> adalah flex item atau anak.

Role atau aturan css yang bisa disematkan di flex container/induk meliputi :

* display: flex | inline-flex
* flex-direction: row | row-reverse | column | column-reverse
* flex-wrap: nowrap | wrap | wrap-reverse&#x20;
* flex-flow: column wrap; shorthand untuk  `flex-direction` dan `flex-wrap`. Secara default, valuenya `row nowrap`.
* justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly | start | end | left | right ... + safe | unsafe
* align-items: stretch | flex-start | flex-end | center | baseline | first baseline | last baseline | start | end | self-start | self-end + ... safe | unsafe
* align-content: flex-start | flex-end | center | space-between | space-around | space-evenly | stretch | start | end | baseline | first baseline | last baseline + ... safe | unsafe

Sedangkan role atau aturan css yang bisa disematkan di flex item / anak meliputi :

* order: 5;  (*default 0 )*
* flex-grow: 4; (*default 0 )*
* flex-shrink: 3; (*default 1, harus diisi angka positif )*
* flex-basis: auto;
* flex: none | \[ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ] } shorthand untuk kombinasi `flex-grow,` `flex-shrink` dan `flex-basis`. Paremeter kedua dan ketiga (`flex-shrink` dan `flex-basis`) adalah opsional. Secara default, valuenya `0 1 auto.`
* align-self: auto | flex-start | flex-end | center | baseline | stretch;

{% tabs %}
{% tab title="CSS" %}
{% code title="flex.css" %}

```css
#main-content {
  display: flex;
  flex-wrap: wrap;
}

aside {
  flex: calc(30% - 40px);
}

section {
  flex: calc(70% - 40px);
}
```

{% endcode %}
{% endtab %}

{% tab title="HTML" %}
{% code title="layout.html" %}

```
<head>
    <title>Layout</title>
    <link rel="stylesheet" href="style.css"/>
    <link rel="stylesheet" href="flex.css"/>
</head>
```

{% endcode %}
{% endtab %}
{% endtabs %}

Dengan teknik flex, akan menghasilkan tinggi yang selaras antara aside dan section.

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MguTv0Dd_wyb-rITsCD%2F-MgueW4ahYDdjh4_LoyX%2FScreen%20Shot%202021-08-12%20at%2020.58.13.png?alt=media\&token=155d490e-6c39-4973-a116-1371746e50ba)

Untuk belajar lebih jauh tentang flex, saya rekomendasikan untuk membaca [a Complete Guide to Flexbox ](https://css-tricks.com/snippets/css/a-guide-to-flexbox/).

### Responsive Layout

Seiring munculnya berbagai device, developer dituntut untuk menghasilkan layout yang baik ketika dijalankan di semua device. Teknik media query adalah salah satu teknik yang mesti diterapkan jika ingin mengimplementasikan responsive web design.

Kali ini kita akan membuat design layout flex di atas menjadi responsive. Ada 2 hal penting untuk menjadi responsif :

1. ketika ukuran hp (<= 600px), maka #main-content akan berubah menjadi kolom.&#x20;
2. ketika ukuran hp (<= 600px), maka menu akan berubah menjadi dropdown dengan togle show/hide.&#x20;

Untuk deteksi ukuran screen, kita memanfaatkan media query. Sementara untuk poin pertama, kita bisa memanfaatkan flex-direction : column | column-reverse.

{% code title="flex.css" %}

```css
@media screen and (max-width: 600px) {
  #main-content {
    flex-direction: column;
  }
}
```

{% endcode %}

Untuk poin kedua, langkah yang dilakukan relatif lebih panjang :

1. Tambahkan hyperlink burger menu yang secara default tersembunyi.
2. Jika ukuran <= 600, sembunyikan menu, dan tampilkan burger menu.
3. Jika burger menu diklik, akan menambahkan togle class responsive pada navigasi menu. Ini dilakukan dengan membuat fungsi javascript onClick.
4. Jika ukuran layar <= 600, navigasi menu akan dibuat menjadi list tersusun ke bawah.
5. jika ukuran layar <= 600, navigasi dibuatkan 2 style, yang tanpa class responsif akan tersembunyi. Dan satu style lagi dengan class responsif dimana menu akan ditampilkan.

Pada file layout.html dan flex.css yang sudah ada, tambahkan/sisipikan kode berikut :

{% tabs %}
{% tab title="HTML" %}
{% code title="layout.html" %}

```css
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">

<nav class="navigation">
  <a href="javascript:void(0);" class="icon" onclick="myFunction()"><i class="fa fa-bars"></i></a>
  <ul>
    <li><a href="">Kelas Online</a></li>
    <li><a href="">Materi Belajar Mandiri</a></li>
    <li><a href="">Tugas</a></li>
    <li><a href="">Latihan Soal Mandiri</a></li>
    <li><a href="">Ujian Online</a></li>
    <li><a href="">Kalender</a></li>
  </ul>
</nav>

<script>
  function myFunction() {
    var x = document.getElementsByTagName("nav")[0];
    if (x.className === "navigation") {
      x.className += " responsive";
    } else {
      x.className = "navigation";
    }
  }
</script>
```

{% endcode %}
{% endtab %}

{% tab title="CSS" %}
{% code title="flex.css" %}

```css
.navigation .icon {
  display: none;
}

@media screen and (max-width: 600px) {
  #main-content {
    flex-direction: column;
  }

  .navigation {
    position:relative;
    min-height: 20px;
  }

  .navigation .icon {
    display:block;
    position: absolute;
    top:10px;
    right:10px;
    color:white;
  }

  .navigation ul {
    display:none;
  }

  .navigation ul li {
    display: block;
  }

  .navigation ul li:hover {
    background: gold;
  }

  .navigation.responsive ul {
    display: block;
  }

}
```

{% endcode %}
{% endtab %}
{% endtabs %}

Begini tampilan halaman ketika dibuka di device dengan layar <= 600 px.

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-Mh-9QUqcBoMJyzLKrlW%2F-Mh-EHXNBz2w3_DkVDTP%2FScreen%20Shot%202021-08-13%20at%2022.58.13.png?alt=media\&token=e5aa29ea-09b8-4243-bd38-fc4275681f93)

Materi layout halaman HTML sudah selese. Jika Anda ingin mempelajari teknik layout yang lain seperti grid, saya sarankan untuk membaca [A Complete Guide to Grid](https://css-tricks.com/snippets/css/complete-guide-grid/). Namun anda juga bisa mengabaikan-nya untuk saat ini (bisa belajar grid di lain waktu) dan beralih ke materi selanjutnya.


# Form

Form merupakan alat utama untuk interaksi antara user dengan aplikasi web. Form memungkinkan user untuk memasukkan data, yang kemudian diteruskan untuk diproses/disimpan di server.

HTML form terdiri dari input, textarea, dan select. Namun pada prakteknya tak pernah lepas dari label dan button.  Untuk membuat form biasanya dengan membuat tag form yang diisi dengan dengan elemen-elemen HTML form yang diperlukan.

### Form&#x20;

Form merupakan tag untuk mengawali pembuatan form. \
\<form>Content\</form>

### Label&#x20;

Label merupakan tag untuk membuat label. \
\<label for="username">Content\</label>

### Input

Input merupakan tag generic untuk memasukkan data ke dalam form. Ada berbagai macam tipe yang didukung oleh input.&#x20;

```markup
<style>
  label {
    width:120px;
    display: inline-block;
  }

  div {
    padding: 2px;
  }

  form {
    width: 100%;
  }

  input {
    width: 235px;
  }

  .radio-input, .radio-label, .checkbox-input, .checkbox-label {
    width:auto;
  }
</style>

<form>
  <div>
    <label for="text-input">Text</label>
    <input id="text-input" type="text" placeholder="nama"/>
  </div>

  <div>
    <label for="email-input">Email</label>
    <input id="email-input" type="email" placeholder="email"/>
  </div>

  <div>
    <label for="url-input">Url</label>
    <input id="url-input" type="url" value="https://www.rijalasepnugroho.com"/>
  </div>

  <div>
    <label for="tel-input">Tel</label>
    <input id="tel-input" type="tel"/>
  </div>

  <div>
    <label for="number-input">Angka</label>
    <input id="number-input" type="number"/>
  </div>

  <div>
    <label for="password-input">Password</label>
    <input id="password-input" type="password"/>
  </div>

  <div>
    <label for="search-input">Search</label>
    <input id="search-input" type="search"/>
  </div>

  <div>
    <label for="date-input">Tanggal</label>
    <input id="date-input" type="date"/>
  </div>

  <div>
    <label for="datetime-local-input">Datetime Local</label>
    <input id="datetime-local-input" type="datetime-local"/>
  </div>

  <div>
    <label for="month-input">Bulan</label>
    <input id="month-input" type="month"/>
  </div>

  <div>
    <label for="time-input">Jam</label>
    <input id="time-input" type="time"/>
  </div>

  <div>
    <label for="week-input">Week</label>
    <input id="week-input" type="week"/>
  </div>

  <div>
    <label for="color-input">Warna</label>
    <input id="color-input" type="color"/>
  </div>

  <div>
    <label for="file-input">File</label>
    <input id="file-input" type="file"/>
  </div>

  <input id="hidden-input" type="hidden"/>

  <div>
    <label for="range-input">Range</label>
    <input id="range-input" type="range"/>
  </div>

  <div>
    <label>Radio</label>
    <input class="radio-input" id="l-radio-input" name="jenis-kelamin" value="L" type="radio"/>
    <label class="radio-label" for="l-radio-input">Laki-Laki</label>
    <input class="radio-input" id="p-radio-input" name="jenis-kelamin" value="P" type="radio"/>
    <label class="radio-label" for="p-radio-input">Perempuan</label>  
  </div>

  <div>
    <label>Checkbox</label>
    <input class="checkbox-input" id="m-checkbox-input" name="pelajaran[]" value="matematika" type="checkbox"/>
    <label class="checkbox-label" for="m-checkbox-input">Matematika</label>
    <input class="checkbox-input" id="k-checkbox-input" name="pelajaran[]" value="komputer" type="checkbox"/>
    <label class="checkbox-label" for="k-checkbox-input">Komputer</label>
    <input class="checkbox-input" id="b-checkbox-input" name="pelajaran[]" value="bahasa" type="checkbox"/>
    <label class="checkbox-label" for="b-checkbox-input">Bahasa</label> 
  </div>
</form>
```

### Textarea

Textarea  merupakan tag untuk membuat suatu teks dengan panjang tak terbatas.&#x20;

```markup
<textarea style="width:50%; height:30vw;">
Form merupakan alat utama untuk interaksi antara user dengan aplikasi web. Form memungkinkan user untuk memasukkan data, yang kemudian diteruskan untuk diproses/disimpan di server.
  
HTML form terdiri dari input, textarea, select, radio dan checkbox. Namun pada prakteknya tak pernah lepas dari label dan button.  Untuk membuat form biasanya dengan membuat tag form yang diisi dengan dengan element-element HTML Form yang diperlukan.
</textarea>
```

### Select

Untuk input yang mempunyai beberapa opsi untuk dipilih, HTML form menyediakan tag select. Select hanya memilih satu dari sekian banyak opsi. Jika ingin memilih lebih dari satu opsi, tambahkan atribut multiple.&#x20;

```markup
<style>
  select {
    width: 235px;
  }
</style>
<select multiple>
  <option disabled selected>Pilih Mata Pelajaran yang disukai</option>
  <optgroup label="IPA">
    <option>Matematika</option>
    <option>Fisika</option>
    <option>Biologi</option>
    <option>Kimia</option>
  </optgroup>

  <optgroup label="IPS">
    <option>Sosiologi</option>
    <option>Geografi</option>
    <option>Sejarah</option>
    <option>Akuntansi</option>
  </optgroup>

  <optgroup label="Umum">
    <option>Bahasa Indonesia</option>
    <option>Bahasa Inggris</option>
    <option>Komputer</option>
  </optgroup>
</select>
```

### Button

Button adalah input untuk membuat tombol. Ada tiga tipe button: button, reset dan submit. Tipe button hanya menampilkan tampilan tombol tanpa ada fungsi apapun. Reset menampilkan tombol yang jika diklik akan me-reset *value* dari form. Tipe submit menampilkan tombol yang jika diklik akan mengirimkan hasil dari pengisian form.

```markup
<form>
<div>
    <label>Radio</label>
    <input class="radio-input" id="l-radio-input" name="jenis-kelamin" value="L" type="radio"/>
    <label class="radio-label" for="l-radio-input">Laki-Laki</label>
    <input class="radio-input" id="p-radio-input" name="jenis-kelamin" value="P" type="radio"/>
    <label class="radio-label" for="p-radio-input">Perempuan</label>  
  </div>

  <div>
    <label>Checkbox</label>
    <input class="checkbox-input" id="m-checkbox-input" name="pelajaran[]" value="matematika" type="checkbox"/>
    <label class="checkbox-label" for="m-checkbox-input">Matematika</label>
    <input class="checkbox-input" id="k-checkbox-input" name="pelajaran[]" value="komputer" type="checkbox"/>
    <label class="checkbox-label" for="k-checkbox-input">Komputer</label>
    <input class="checkbox-input" id="b-checkbox-input" name="pelajaran[]" value="bahasa" type="checkbox"/>
    <label class="checkbox-label" for="b-checkbox-input">Bahasa</label> 
  </div>

  <button type="button">Klik Button</button>
  <button type="reset">Klik Reset</button>
  <button type="submit">Klik Submit</button>
</form>
```

Dengan berakhirnya materi tentang form, berakhir pula materi tentang HTML dan CSS. Sampai di sini, siswa diharapkan sudah mampu melakukan design web, baik melayout halaman web secara umum maupun membuat form.  Untuk memastikan hal tersebut, bab berikutnya adalah praktikum.


# Praktikum I : Membuat Halaman Login dan CRUD

Kerjakan tugas praktikum sebagai berikut :

1. Buat halaman login.
2. Buat halaman list user yang diserta tombol "create new user" di bagian atas. Di setiap row juga disertakan link untuk view, edit dan delete. Jika link delete di-klik tampilkan dialog konfirmasi, "Yakin hendak menghapus data user?".
3. &#x20;Buat halaman form input user baru.
4. Buat halaman form update user.

Design bebas sesuai dengan kreativitas masing-masing, sebagai contoh, berikut saya lampirkan tampilan login dan Halaman CRUD.

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MfwaGF_pkTnRiq5SmUY%2F-MfwcV-fvsOHjD4edkOk%2FScreen%20Shot%202021-07-31%20at%2019.52.51.png?alt=media\&token=9e589e34-a7ad-4caf-a295-cdb0e72ef7ee)

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MfwaGF_pkTnRiq5SmUY%2F-MfwcaNBuZ20VvZicQ1H%2FScreen%20Shot%202021-07-31%20at%2019.54.01.png?alt=media\&token=5def6867-7395-4a45-bbbf-fabc6a8a6aa6)


# Pengenalan Javascript

Javascript merupakan bahasa pemrograman yang awalnya hanya bisa berjalan di browser. Namun belakangan, javascript juga bisa jalan di server, sehingga popularitas javascript meningkat dengan drastis. Javascript bisa digunakan untuk membangun frontend web, API backend, frontend mobile, desktop, dan iot.

Untuk tahap awal, kita akan belajar javascript yang berjalan di browser. Ada tiga cara untuk menulis kode javascript di HTML, yaitu : Inline, Embed dan external.&#x20;

## Inline&#x20;

Kode javascript ditempel langsung pada properti HTML.

```markup
<button onclick="alert('Hi')">Say Hi</button>
```

## Embed

Kode javascript ditulis langsung sebagai tag element \<script>\</script> di HTML.

```markup
<!DOCTYPE html>
<html>
  <head>
    <title>Javascript</title>
  </head>
  <body>
    Internal Javascript
    <script>
      console.log("embed javascript");
    </script>
  </body>
</html>
```

Kode di atas akan menampilkan tulisan "Internal Javascript" di browser. Sementara kode javascript akan menampilkan log "embed javascript" di console browser. Untuk melihat console browser, tampilkan developer tools dan klik tab console.

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MiEqR1iD-lIPOtJMp-M%2F-MiEvJE8UOtl6ZJ0HfeL%2FScreen%20Shot%202021-08-29%20at%2010.19.22.png?alt=media\&token=d1f39bbf-5bb1-41e1-bd60-21486445d690)

## External

Kode javascript ditulis di file terpisah dan dipanggil melalui link.&#x20;

{% tabs %}
{% tab title="HTML" %}
{% code title="index.html" %}

```markup
<!DOCTYPE html>
<html>
  <head>
    <title>Javascript</title>
    <script src="index.js"></script>
  </head>
  <body>
    External Javascript
  </body>
</html>
```

{% endcode %}
{% endtab %}

{% tab title="Javascript" %}
{% code title="index.js" %}

```javascript
console.log("external javascript")
```

{% endcode %}
{% endtab %}
{% endtabs %}


# Dasar Pemrograman Javascript

Dasar pemrograman javascript meliputi pengaksesan DOM HTML,  variable, konstanta dan tipe data.

### DOM HTML

Dokumen HTML bisa diakses melalui DOM (*Document Object Model).* Ketika sebuah halaman HTML diload oleh browser, maka browser akan menciptakan sebuah dokumen. Dokumen ini dimodelkan dalam bentuk objek yang berisi kumpulan data/atribut dan fungsi, yang bisa dimanfaatkan (dipanggil) saat kita membuat kode-kode javascript.

Contoh fungsi dalam document adalah document.write() yang berguna untuk menulis di dalam document. Contoh properti/atribut document adalah document.body (untuk mengakses body HTML) dan document.title  (untuk mengakses title HTML).&#x20;

{% tabs %}
{% tab title="JavaScript" %}
{% code title="index.js" %}

```javascript
document.write("Halo Selamat Pagi ");
document.body.style.backgroundColor = "pink";
```

{% endcode %}
{% endtab %}

{% tab title="HTML" %}
{% code title="index.html" %}

```markup
<!DOCTYPE html>
<html>
  <head>
    <title>Indonesia Pagi</title>
    <script src="index.js"></script>
  </head>
  <body>
    Indonesia
  </body>
</html>
```

{% endcode %}
{% endtab %}
{% endtabs %}

Ketika script di atas dijalankan maka akan menulis isi dari body HTMl dengan tulisan "Halo Selamat Pagi ", kemudian mengakses properti style backgroundColor dari body dan menggantinya dengan nilai "pink" sehingga tampilan browser akan meanmpilkan tulisan "Halo Selamat Pagi Indonesia" dengan background browser berwarna pink.&#x20;

Fungsi-fungsi lain yang sering digunakan untuk mengakses sebuah element dalam HTML adalah:

* document.getElementById()
* document.getElementsByName()
* document.getElementsByTagName()
* document.getElementsByClassName()
* document.querySelector()
* document.querySelectorAll()

```markup
<p id="main-p">Selamat Pagi</p>
<p>Selamat Siang</p>
<p>Selamat Sore</p>
<p class="malam">Selamat Malam</p>
<p class="malam">Selamat Tidur</p>
<input name="kota" type="text" value="Jakarta"/>
<script>
    document.getElementById("main-p").style.color = "gold";
    document.getElementsByTagName("p")[2].innerText = "Selamat Senja";
    document.getElementsByName("kota")[0].value = "Surabaya";
    document.querySelector("p.malam").innerText = "good night";
    console.log("queryALL", document.querySelectorAll("p.malam, p#main-p"));
</script>
```

Dari kode di atas kita juga mengenal beberapa properti/atribut dari sebuah objek, meliputi: element.style untuk mengakses style dari objek, element.InnerText atau element.innerHTML untuk mengakses text/html dari sebuah object. Document juga mempunyai atribut seperti document.body, document.style dll.

### Variabel dan Konstanta

Variabel adalah kontainer untuk menyimpan data, dimana isi dari data tersebut bisa diubah-ubah. Semua nama variable harus bersifat unik dan menjadi identitas dari variable tersebut (identifier). Penamaan variabel (dan konstanta) harus mengikuti kaidah :&#x20;

* Nama dapat berisi huruf, angka, garis bawah, dan tanda dolar.&#x20;
* Nama harus diawali dengan huruf&#x20;
* Nama peka huruf besar/kecil (y dan Y adalah variabel yang berbeda)&#x20;
* Kata-kata yang dicadangkan (seperti kata kunci JavaScript) tidak dapat digunakan sebagai nama

Ada dua cara untuk membuat variabel, yaitu dengan var dan let. var adalah cara penggunaan untuk deklarasi variabel global, dimana ruang liangkup hidup-nya di seluruh kode. Sementara let adalah cara deklarasi variable lokal dimana ruang lingkup-nya aganya ada di dalam blok kode dimana variabel tersebut dideklarasikan.

Sementara kontanta adalah suatu kontainer untuk menyimpan data yang tidak dapat diubah. Untuk membuat konstanta digunakan kata kunci const.

{% code title="variable.html" %}

```markup
<h1>variabel dan Konstanta</h1>

<script>
  var salam = "Selamat Pagi";
  console.log("salam di luar blok: ", salam);

  const ekspresi = "senyum";
  console.log("ekspresi di luar blok: ", ekspresi);
    
  {
    // cek apakah salam hidup dalam blok ini
    console.log("salam di dalam blok: ", salam);

    // cek apakah ekspresi hidup di blok ini
    console.log("ekspresi di dalam blok: ", ekspresi);
    
    ekspresi = "tertawa";
    console.log("ekspresi di dalam blok: ", ekspresi);

    salam = "Selamat siang";
    console.log("salam di dalam blok: ", salam);
    
    let sapa = "Halo....";
    console.log("sapa di dalam blok: ", sapa);

    sapa = "Apa Kabar";
    console.log("sapa di dalam blok: ", sapa);

    const jawab = "baik";
    console.log("jawab di dalam blok: ", jawab);
    
  }

  console.log("salam di akhir dan luar blok: ", salam);
  console.log("sapa di akhir dan luar blok: ", sapa);
  console.log("ekspresi di akhir dan luar blok: ", ekspresi);
  console.log("jawab di akhir dan luar blok: ", jawab);
    
</script>
```

{% endcode %}

&#x20;ketika kode di atas dijalankan maka akan error `variabel.html:17 Uncaught TypeError: Assignment to constant variable. at variabel.html:17` Ini disebabkan ada upaya untuk mengganti nilai dari sebuah konstanta. \
\
Jika kita komen kode pada baris 17 agar tidak dieksekusi, kemudian kita jalankan kembali kode di atas, maka error akan berpindah pada baris 35  `variabel.html:35 Uncaught ReferenceError: sapa is not defined at variabel.html:35`Ini disebabkan baris 35 menggunakan variabel '*sapa'* yang tidak dikenal, karena variabel '*sapa'* hanya hidup di dalam blok saja.\
\
Perhatikan juga baris 37 dimana ada upaya menggunakan konstanta '*jawab'*, kode ini akan menyebabkan error karena konstanta '*jawab'* hanya dikenal di dalam blok saja.  &#x20;

### Tipe Data

Ada beberapa tipe data dalam pemrograman javascript

* undefined\
  suatu tipe data yang belum didefinisikan isinya. Jika membuat suatu variable tanpa pernah mengisi data di dalamnya, maka tipe data varibel tersebut adalah undefined.&#x20;
* null \
  sebenarnya null merupakan object, namun sengaja saya pisahkan tersendiri agar mendapat perhatian yang lebih. null adalah suatu keadaan dimana suatu varibel dideklarasikan kemudian diberi nilai null. Jika menjalankan typeof , maka tipe data-nya adalah object.&#x20;
* String (teks)
* Integer atau Number (bilangan bulat)
* Float (bilangan Pecahan) : sebenarnya juga merupakan tipe data number.
* Boolean : hanya berisi dua kemungkinan nilai, yaitu : true atau false.
* Object : bisa berupa null, json object, maupun array object. Object merupakan satu-satunya tipe data yang bukan primitif, melainkan tipe data turunan.

```markup
<h1>Tipe Data</h1>

<script>
  let variabelUndefined;
  let variableNull = null;
  let variabelBoolean = true;
  let variabelString = "Apa Kabar?";
  let variabelNumber = 12345;
  let variabelFloat = 3.14;
  let variabelObjectArray = [1, 2, 3, 4, 5];
  let variabelObjectJson = {
    nama: "Naruto",
    umur: 12,
    alamat: "Desa Konoha"
  }
  
  console.log("variabelUndefined", typeof(variabelUndefined));
  console.log("variableNull", typeof(variableNull));
  console.log("variabelBoolean", typeof(variabelBoolean));
  console.log("variabelString", typeof(variabelString));
  console.log("variabelNumber", typeof(variabelNumber));
  console.log("variabelFloat", typeof(variabelFloat));
  console.log("variabelObjectArray", typeof(variabelObjectArray));
  console.log("variabelObjectJson", typeof(variabelObjectJson));
  
</script>
```

Di dalam javascript, perubahan tipe data berlangusng secara dinamis ketika sebuah nilai diassign ke variabel. Bisa jadi dalam state tertentu tipe data variable adalah string, di state berikutnya bisa berubah menjadi number. Perhatikan contoh berikut :

```markup
<h1>Tipe Data Dinamis</h1>

<script>
  let a = 100;
  console.log("a: ", a, " | ", typeof(a));

  a = a + 50;
  console.log("a: ", a, " | ", typeof(a));

  a = a + "50";
  console.log("a: ", a, " | ", typeof(a));

  a = a + " hari";
  console.log("a: ", a, " | ", typeof(a));
</script>
```


# Operator

## Operator Aritmatika

Aritmatika adalah salah satu hal penting dalam bahasa pemrograman. Di javascript ada 7 operator aritmatika meliputi :

* Penambahan  (+)&#x20;
* Pengurangan (-)&#x20;
* Perkalian (\*)
* Pembagian (/)&#x20;
* Sisa bagi (%)&#x20;
* Increment (++)&#x20;
* Decrement (- -)

```markup
<h1>Operator Aritmatika</h1>

<script>
  let a = 10;
  let b = 5;
  console.log("a + b = ", a + b);
  console.log("a - b = ", a - b);
  console.log("a * b = ", a * b);
  console.log("a / b = ", a / b);
  console.log("a % b = ", a % b);
  console.log("++10 = b = ", ++a + b, " | ", a);
  
  a = 10;
  console.log("--a + b = ", --a + b, " | ", a);
  
  a = 10;
  console.log("a++ + b = ", a++ + b, " | ", a);
  
  a = 10;
  console.log("a-- + b = ", a-- + b, " | ", a);
</script>
```

### &#x20;Derajat Operator

Seperti konsep matematika, operator aritmatika juga mempunyai derajat sebagia berikut:

1. Prefix Increment, ++x
2. Prefix Decrement, — x
3. Perkalian, \*
4. Pembagian, /
5. Modulus, %
6. Penjumlahan, +
7. Pengurangan, -
8. Postfix Increment, x++
9. Postfix Decrement, x —

## Operator Perbandingan

Ada delapan operator perbandingan di JavaScript, yaitu:

* Equal value, ==
* Equal value and type, ===
* Not equal, !=
* Not equal value and type, !==
* Greater than, >
* Less than, <
* Greater than or equal, >=
* Less than or equal, <=

```markup
<h1>Operator Perbandingan</h1>

<script>
  let a = 10;
  let b = 5;
  console.log("a >= b = ", a >= b);
  console.log("a <= b = ", a <= b);
  console.log("a != b = ", a != b);
  console.log("a == b = ", a == b);
  console.log("a == '10' = ", a == "10");
  console.log("a === '10' = ", a === "10");
  console.log("a === 10 = ", a === 10);
  console.log("a != '5' = ", a != "5");
  console.log("a !== '5' = ", a !== "5");
  console.log("a != '10' = ", a != "10");
  console.log("a !== '10' = ", a !== "10");
</script>
```

## Operator Logika <a href="#id-60b6" id="id-60b6"></a>

Terdapat tiga operator yang termasuk operator logika, yaitu:

* AND, &&
* OR, ||
* NOT, !

### Operator AND

| Ekspresi 1 | Eskpresi 2 | Hasil |
| ---------- | ---------- | ----- |
| true       | true       | true  |
| true       | false      | false |
| false      | true       | false |
| false      | false      | false |

Hasil operator AND akan TRUE jika kedua ekspresi bernilai TRUE

### Operator OR

| Ekspresi 1 | Eskpresi 2 | Hasil |
| ---------- | ---------- | ----- |
| true       | true       | true  |
| true       | false      | true  |
| false      | true       | true  |
| false      | false      | false |

Hasil operartor OR akan TRUE jika salah satu ekspresi bernilai TRUE

### Operator NOT

| Ekspresi 1 | Hasil |
| ---------- | ----- |
| true       | false |
| false      | true  |

Hasil operator NOT merupakan kebalikan dari ekspresi.

operator logika dibaca dari sebelah kiri, sehingga jika ekspresi pertama dari operator AND  bernilai false, maka ekspresi kedua tidak perlu lagi dievaluasi. Begitu juga jika ekspresi pertama pada operator OR bernilai true, maka ekspresi kedua sudah tidak perlu dievaluasi.

* false && (any expression)
* true || (any expression)

```markup
<h1>Operator Logika</h1>

<script>
  console.log("true && true = ", true && true );
  console.log("true && false = ", true && false );
  console.log("false && true = ", false && true );
  console.log("false && false = ", false && false );
  
  
  console.log("true || true = ", true || true );
  console.log("true || false = ", true || false );
  console.log("false || true = ", false || true );
  console.log("false || false = ", false || false );
  
  console.log("!true = ", !true);
  console.log("!false = ", !false);
  
  console.log("(10 >= 5)  && (10 == '10') = ", (10 >= 5)  && (10 == '10'));
  var a;
  console.log("false && a = ", false && a);
  console.log("true || a = ", true || a);
</script>
```


# Seleksi Kondisi

Seleksi kondisi digunakan untuk melakukan tindakan yang berbeda berdasarkan kondisi yang berbeda. Kode akan dieksekusi jika syarat yang diminta terpenuhi.

### if

```markup
<h1>If</h1>

<script>
  let cuaca = prompt("apa cuaca hari ini ?", "cerah");

  if (cuaca === "cerah") {
    console.log("cuaca", cuaca, ", saya pergi bermain di luar rumah");
  }
</script>
```

### if else

```markup
<h1>If Else</h1>

<script>
  let cuaca = prompt("apa cuaca hari ini ?", "cerah");

  if (cuaca === "cerah") {
    console.log("cuaca", cuaca, ", saya pergi bermain di luar rumah");
  } else {
    console.log("cuaca", cuaca, ", saya baca buku di ruang tamu");
  }
</script>
```

### nested if else&#x20;

```markup
<h1>Nested If Else</h1>

<script>
  let cuaca = prompt("apa cuaca hari ini ?", "cerah");

  if (cuaca === "cerah") {
    console.log("cuaca", cuaca, ", saya pergi bermain di luar rumah");
  } else if (cuaca === "berawan") {
    console.log("cuaca", cuaca, ", saya baca buku di teras");
  } else {
    console.log("cuaca", cuaca, ", saya baca buku di ruang tamu");
  }
</script>
```

### switch

Jika nested if else terkalu banyak, itu tandanya anda membutuhkan switch.

```markup
<h1>Switch</h1>

<script>
  let cuaca = prompt("apa cuaca hari ini ?", "cerah");

  switch (cuaca) {
    case "cerah":
      console.log("cuaca", cuaca, ", saya pergi bermain di luar rumah");
      break
    case "berawan":
      console.log("cuaca", cuaca, ", saya baca buku di teras");
      break
    default:
      console.log("cuaca", cuaca, ", saya baca buku di ruang tamu");
  }
</script>
```


# Perulangan

Perulangan dapat mengeksekusi blok kode beberapa kali. Ini berguna jika Anda ingin menjalankan kode yang sama berulang-ulang, setiap kali dengan nilai yang berbeda.

### for

```markup
<h1>Perulangan</h1>

<script>
  for (let index = 1; index <= 10; index++) {
    console.log("Aku baca buku halaman ", index);
  }
</script>
```

### for in

```markup
<h1>Perulangan</h1>

<script>
  var pages = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
  for (const index in pages) {
    console.log("Aku baca buku halaman ", pages[index]);
  }
</script>
```

### for of

```markup
<h1>Perulangan</h1>

<script>
  var pages = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
  for (const element of pages) {
    console.log("Aku baca buku halaman ", element);
  }
</script>
```

### foreach

```markup
<h1>Perulangan</h1>

<script>
  var pages = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
  pages.forEach((element, index) => {
    console.log("Aku baca buku halaman ", element);
  });
</script>
```

### while

```markup
<h1>Perulangan</h1>

<script>
  var page = 1;
  while (page >= 1 && page <= 10) {
    console.log("Aku baca buku halaman ", page);
    page++;
  }
</script>
```


# Fungsi

Fungsi diperlukan agar suatu kode tidak ditulis berulang-ulang, cukup dibuat sekali dalam satu fungsi, dan bisa dipanggil berkali-kali kapan pun dibutuhkan.

### Deklarasi Fungsi&#x20;

Dekalrasi fungsi terdiri dari kata kunci function, nama fungsi beserta argumen yang diperlukan

```
function namaFungsi(argumen1, argumen2) {
    // blok kode
}
```

Contoh penggunaan fungsi

```javascript
function cetakSalam() {
    console.log("Selamat Pagi");
}

function cetak(salam) {
    console.log(salam);
}

function sapa(salam, nama) {
    console.log(salam, nama);
}

cetakSalam();
cetak("Selamat Pagi");
sapa("Selamat Pagi", "Beruang");
```

### Fungsi dengan return

Fungsi bisa menghasilkan kembalian berupa data hasil dari eksekusi fungsi tersebut.

```javascript
function isPrimeNumber(n) {
    if (n < 2) {
      return false;
    }
    for (let i = 2; i < n; i++) {
      if (n%i == 0) {
        return false;
      }
    }

    return true;
  }
  
  // Mencetak bilangan prima antara 1 - 100
  for (let i = 1; i<=100; i++) {
    if (isPrimeNumber(i)) {
      console.log(i);
    }
  }
  
  // mencetak N bilangan prima pertama 
  const bilangan = prompt("masukkan bilangan");
  let iterator = 1;
  let jumlah = 1;
  while (jumlah <= bilangan) {
    if (isPrimeNumber(iterator)) {
      console.log(`${jumlah} --> ${iterator}`);
      jumlah++;
    }

    iterator++;
  }
  
  
  function GetStudent(id){
    if (id === 1) {
      return {
        name: "Amalia",
        age: 14 
      } 
    }
    
    return {}
  }
  
  let amalia = GetStudent(1);
  let kosong = GertStudent(2);
  
  console.log("amalia : ", amalia);
  console.log("kosong : ", kosong);
  
```

### Fungsi Anonim

Fungsi anonim adalah suatu fungsi yang dideklarasikan tanpa nama

```javascript
let weekDays = ["Senin", "Selasa", "Rabu", "Kamis", "Jumat"];

weekDays.forEach(function (value, index) { 
    console.log(index, value); 
});
```

Fungsi anonim juga bisa disimpan dalam sebuah variabel

```javascript
const salam = function(str) {
    console.log("fungsi anonim di variabel", str);
};

salam("Halo");
```

### Arrow Function

```javascript
const salam = str => console.log("arrow function", str);
const sapa = (salam, nama) => console.log("arrow function", salam, nama);
const multiLine = () => {
    console.log("line 1");
    console.log("line 2");
}
const withReturn = () => "halo";
const withReturnMultiLine = () => {
    let str = "halo";
    return str;
}

salam("selamat pagi");
sapa("selamat pagi", "beruang");
multiLine();
const halo = withReturn();
console.log(halo);

const haloAgain = withReturnMultiLine();
console.log(haloAgain);
```

### Callback Function

Ketika sebuah fungsi dijadikan paramter fungsi lain, itulah yang disebut dengan callback.  Kita akan mengubah anonim function pada contoh foreach weekdays menjadi callback.

```javascript
function cetak(value, index) { 
    console.log(index, value); 
}

let weekDays = ["Senin", "Selasa", "Rabu", "Kamis", "Jumat"];

weekDays.forEach(cetak);
```

Contoh lain

```javascript
function cetak(data) {
    console.log(data);
}

function hitung(angka1, angka2, myCallback){
    let jumlah = angka1 + angka2;
    myCallback(jumlah);
}

hitung(4, 5, cetak);

function ask(question, no, yes) {
    if (confirm(question)) {
        yes();
    } else {
        no();
    }
}

function agree() {
    console.log("Ya, Saya setuju!");
}

function disagree() {
    console.log("Tidak, saya tidak setuju!");
}

ask("Apakah Anda Setuju?", disagree, agree);
```


# String

Untuk menulis string digunakan tanda petik dua (") atau tanda petik satu (').

```javascript
console.log('Selamat pagi dunia!');
console.log("Selamat pagi dunia!"); 
```

Meski kita bebas menggunakan tanda petik dua maupun tanda petik satu, pastikan Anda hanya mengunakan salah satunya saja. Ini demi konsistensi dan kemudahan maintenance kode.&#x20;

Untuk menulis string yang mengandung quote/tenda petik, bisa menggunakan tanda petik yang berbeda dengan yang hendak dicetak atau menggunakan prefix backslash.

```javascript
console.log('Matahari tersenyum menyapa, "Selamat pagi dunia!"');
console.log("Matahari tersenyum menyapa, \"Selamat pagi dunia!\"");
```

## Properti&#x20;

### length

Untuk mendapatkan panjang suatu string, gunakan properti length

```javascript
let salam = "Apa Kabar";
console.log("Selamat pagi dunia!".length);
console.log(salam.length);
```

## Method

Ada banyak method yang dimiliki oleh string, kita ahnaya akan membahas sebagian yang menurut saya pribadi sering digunakan.

### Mengambil potongan string : slice dan substring/substr

Ada dua cara untuk mengambil potongan string, bisa melalui slice(), dan substring().

```javascript
Syntax: string.slice(start, stop);
Syntax: string.substring(start, stop);
```

#### Slice

Digunakan untuk mengambil bagian dari string yang diberikan. Caranya dengan melempar index awal dan index akhir dari slice/potongan string yang diinginkan.  Indek yang diberikan bisa bernilai positif maupun negatif. Jika positif, indek dihitung dari kiri string. JIka negatif, indek dihitung dari kanan string.

```javascript
let salam = "Selamat pagi dunia!";
console.log(salam.slice(0, 7));
console.log(salam.slice(8, 12));
console.log(salam.slice(13, -1));
console.log(salam.slice(-6, -1));
console.log(salam.slice(0, salam.length));

console.log(salam.slice(0));
console.log(salam.slice(0, 1000));
```

#### substring/substr

substring dan substr adalah dua method yang sama persis, kita bosa meilih salah satunya saja. Method ini juga digunakan untuk mengambil suatu potongan string berdasarkan indek string. Berbeda dengan slice, substring tidak bisa mempunyai indek negatif.

```javascript
let salam = "Selamat pagi dunia!";
console.log(salam.substring(0));
console.log(salam.substring(0, 1000));

console.log(salam.substring(0, salam.length));
console.log(salam.substring(12, 8));
console.log(salam.substring(12, "asal"));
```

**Kesamaan apa yang mereka miliki:**

1. Jika `start` sama dengan `stop`: mengembalikan string kosong
2. Jika `stop` dihilangkan: ekstrak karakter ke akhir string
3. Jika salah satu argumen lebih besar dari panjang string, panjang string akan digunakan sebagai gantinya.

**Perbedaan**[`substring()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substring)**:**

1. Jika `start > stop`, maka `substring` akan menukar 2 argumen tersebut.
2. Jika salah satu argumen negatif atau `NaN`, itu diperlakukan seolah-olah `0`.

**Perbedaan**[`slice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice)**:**

1. Jika `start > stop`, `slice()` akan mengembalikan string kosong. (`""`)
2. Jika `start` negatif: set char dari akhir string, persis seperti `substr()` di Firefox. Perilaku ini diamati di Firefox dan IE.
3. Jika `stop` negatif: set berhenti ke: `string.length – Math.abs(stop)` (nilai asli), kecuali dibatasi pada 0 (dengan demikian, `Math.max(0, string.length + stop)`) sebagaimana dicakup dalam [spesifikasi ECMA](https://www.ecma-international.org/ecma-262/9.0/index.html#sec-string.prototype.slice) .

### Mengambil karakter berdasarkan indek: charAt

charAt digunakan untuk mengambil suatu karakter sebuah string berdasarkan indek yang dilempar. Karena yang dilempar adalah indek dan dimulai dari index ke nol, maka indek terakhir adalah panjang suatu string dikurangi 1.&#x20;

charAt memiliki sifat :

* Jika indek tidak ditemukan, akan dikembalikan string kosong.&#x20;
* Jika diberi indek negatif makan akan dikembalikan string kosong.
* Jika diberi indeks Nan maka akan dikembalikan character pada indek ke nol. &#x20;

```javascript
let salam = "Selamat pagi dunia!";
console.log(salam.charAt(0));
console.log(salam.charAt(5));
console.log(salam.charAt(salam.length));
console.log(salam.charAt(salam.length - 1));
console.log(salam.charAt(-1));
console.log(salam.charAt("asal"));
```

### Mengubah huruf besar/kecil : toUpperCase dan toLowerCase

Untuk mengubah suatu string menjadi huruf besar maupun huruf kecil, digunakan method toUppercase dan toLowerCase.

```javascript
let salam = "Selamat pagi dunia!";
console.log(salam.toUpperCase());
console.log(salam.toLowerCase());
console.log(salam.charAt(0).toUpperCase()+salam.slice(1).toLowerCase());
```

### Menggabungkan dua string : concat

Untuk menggabungkan dua buah string atau lebih, kita bisa memilih menggunakan operator plus (+) maupun method concat.

```javascript
let sapa = "Halo";
let name = "Jacky";
console.log(sapa + " " + name);
console.log(sapa.concat(" ").concat(name));
```

### Menghilangkan spasi berlebih : trim

```javascript
let salam = "    Selamat      pagi dunia!        ";
console.log(salam.trim());
console.log(salam.trimStart());
console.log(salam.trimEnd());
```

### Mengubah string menjadi array : split

```javascript
let salam = "Selamat pagi dunia!";
console.log(salam.split(" "));
```

## Template using backtick

Kadang kita memerlukan template string, misalnya saat hendak memasukkan variabel ke dalam format string. Javascript menyediakan template string dengan backtick (\`).

```javascript
let name = "Jacky";
console.log(`Selamat pagi ${name}. Bagaimana keadaanmu di sana? Semoga ${name} dalam keadaan sehat dan bahagia.`);
```


# Array

Array adalah koleksi atau kumpulan dari banyak nilai.

```javascript
const arStr = ["senin", "selasa", "rabu", "kamis", "jumat"];
console.log(arStr);

const arInt = [1, 2, 3, 4, 5];
console.log(arInt);

const arMix = ["senin", 100, "rabu", 200, "jumat"];
console.log(arMix);

const arMixWithObj = ["senin", 100, "rabu", 200, "jumat", ["Rambutan", "Durian", "Salak"], {name: "jacky", age: 12}];
console.log(arMixWithObj);
```

cara deklarasi array bisa seperti di atas. Namun bisa juga dengan menggunakan objek Array dan memanggilnya dengan kata kunci new, atau dengan mengakses indek array tersebut.

```javascript
const ar = ["senin", "selasa", "rabu", "kamis", "jumat"];
console.log(ar);

const arIndex = [];
arIndex[0] = "senin";
arIndex[1] = "selasa";
arIndex[2] = "rabu";
arIndex[3] = "kamis";
arIndex[4] = "jumat";
console.log(arIndex);

const arObj = new Array("senin", "selasa", "rabu", "kamis", "jumat");
console.log(arObj);
```

Object Array juga punya method penting untuk mengecek apakah suatu variabel array atau bukan.

```javascript
const ar = ["senin", "selasa", "rabu", "kamis", "jumat"];
console.log(Array.isArray(ar));
console.log(Array.isArray(["Rambutan", "Durian", "Salak"]));
console.log(Array.isArray({name: "jacky", age: 12}));
console.log(Array.isArray("Apa kabar"));
console.log(Array.isArray(2021));
```

Untuk mengakses array bisa langsung menunjuk indek-nya

```javascript
const ar = ["senin", "selasa", "rabu", "kamis", "jumat"];
console.log(ar[3]);
```

Array juga mempunya properti dan method

## Properti

### length

Untuk mendapatkan panjang suatu array, gunakan properti length

```javascript
const ar = ["senin", "selasa", "rabu", "kamis", "jumat"];
console.log(ar.length);
```

## Method

Array mempunyai banyak method, kita akan membahas sebagian yang sering digunakan.

### Menambah dan mengurangi anggota sebuah array

#### push

Untuk menambahkan elemen baru ke dalam array. Anggota terbaru akan diletakkan di indek paling terakhir.

```javascript
const ar = ["senin", "selasa", "rabu", "kamis", "jumat"];
ar.push("sabtu");
ar.push("minggu");
console.log(ar);
```

#### Pop

Pop adalah suatu method untuk mendapatkan anggota terahir dari sebuah array sekaligus mengeluarkan (menghapus) anggota tersebut dari array. Pop merupakan method standard dari struktur data stack (tumpukan). Dimana pop digunakan untuk mengambil dari tumpukan paling atas.

```javascript
const ar = ["senin", "selasa", "rabu", "kamis", "jumat"];
ar.push("sabtu");
ar.push("minggu");
console.log(ar);

console.log(ar.pop())
console.log(ar.pop())

console.log(ar);
```

#### shift

shift mirip dengan pop, digunakan untuk mengambil tumpukan paling bawah. shift akan menampilkan nilai dari indek pertama sebauh array sekaligus mengeluarkan (menghapus) value tersebut dari array.

```javascript
const ar = ["senin", "selasa", "rabu", "kamis", "jumat"];
console.log(ar.shift());
console.log(ar);
```

#### unshift

unshift mirip dengan push, digunakan untuk menambahkan anggota baru ke dalam sebuah array, namun anggota baru ini akan ditambahkan di indek paling awal.

```javascript
const ar = ["senin", "selasa", "rabu", "kamis", "jumat"];
ar.unshift("minggu");
ar.unshift("sabtu");
console.log(ar);
```

### Memanipulasi isi/nilai sebuah array

#### delete

delete digunakan untuk menghapus value dari sebuah indek. delete tidak menhilangkan keanggotaan, melainkan hanya menghapus nilai saya.

```javascript
const ar = ["senin", "selasa", "rabu", "kamis", "jumat"];
delete ar[3];
console.log(ar);
ar[3] = "kamis";
console.log(ar);
  
```

### Membuat potongan sebuah array

slice digunakan untuk memotong sebuah array. slice mempunyai sifat:

* Membuat array baru tanpa menghapus array sumber.
* Mempunyai 2 argumen, argumen pertama adalah indek awal, argumen kedua adalah indek akhir.
* Slice memotong mulai dari indek awal sampai sebelum indek akhir. Artinya potongan array tidak termasuk indek terakhir.&#x20;
* Jika hanya ada 1 argumen maka dianggap argumen kedua adalah panjang array.
* Jika argumen negatif, maka itu sama dengan panjang array dikurangi argumen (atau dihitung dari array terakhir).

```javascript
const days = ["senin", "selasa", "rabu", "kamis", "jumat", "sabtu", "minggu"];
const weekdays = days.slice(0, 5);
const weekend = days.slice(5, 7);
const weekendsOneArg = days.slice(5);
const weekendUsingLengthMinus = days.slice(days.length-2);
const weekendUsingMinus = days.slice(-2);
console.log("days", days);
console.log("weekdays", weekdays);
console.log("weekend", weekend);
console.log("weekendsOneArg", weekendsOneArg);
console.log("weekendUsingLengthMinus", weekendUsingLengthMinus);
console.log("weekendUsingMinus", weekendUsingMinus);
```

### Menggabungkan dua buah array : concat()

Berlawanan dengan slice, concat adalah untuk menambah anggota baru.

```javascript
const weekdays = ["senin", "selasa", "rabu", "kamis", "jumat"];
const weekend = ["sabtu", "minggu"];
const days = weekdays.concat(weekend);
console.log(days);

let myFruits = ["Rambutan", "Durian", "Salak"];
myFruits = myFruits.concat(
    ["Kesemek", "Apel", "Jeruk"], 
    ["Jambu", "Pepaya", "Mangga"], 
    "Nanas", 
    ["Kelengkeng"]
);
myFruits = myFruits.concat("Nangka");
console.log(myFruits);
```

### Mengurutkan array : sort

Untuk mengurutkan array dari terkecil ke terbesar.

```javascript
const myFruits = ["Rambutan", "Durian", "Salak"];
myFruits.sort();
console.log(myFruits);

const myNumber = [400, 314, 256, 512];
myNumber.sort();
console.log(myNumber);

const myMix = ["Rambutan", 374, "Duku", 845, "Kedondong", 543];
myMix.sort();
console.log(myMix);

const myMixObj = [null, "Rambutan", ["senin", "selasa"], 374, ["sabtu", "minggu"], "Duku", 845, {name: "jeruk"}, "Kedondong", 543, {name: "anggur"}];
myMixObj.sort();
console.log(myMixObj);
```

### Membalik susunan array : reverse

```javascript
const days = ["senin", "selasa", "rabu", "kamis", "jumat", "sabtu", "minggu"];
days.reverse();
console.log(days);
```

### Mengubah array menjadi string

Untuk mengubah array ke string, kita bisa menggunakan fungsi toString() maupun join(). Jika menggunakan toString() maka array akan menjadi string dengan separator koma (,). Jika menginginkan separator lain, gunakan fungsi join() dengan melempar separator yang diinginkan.

```javascript
const days = ["senin", "selasa", "rabu", "kamis", "jumat", "sabtu", "minggu"];
console.log(days.toString());
console.log(days.join(" "));
```

### Perulangan pada array

Method-method array yang melakukan iterasi antara lain foreach(), map() dan filter()&#x20;

#### forEach&#x20;

forEach melakukan iterasi dengan setiap iterasi-nya memanggil fungsi (callback).

```javascript
const myNums = [1, 2, 3, 4, 5];
const square = (value, index, arr) => console.log(value * value);
myNums.forEach(square);
```

#### map

Mirip seperti forEach,  map juga melakukan iterasi pada sebuah array.  Bedanya forEach murni melakukan iterasi. Sementara map selain melakukan iterasi, dia juga  menciptakan array baru. Map tidak merubah array aslinya.&#x20;

```javascript
const myNums = [1, 2, 3, 4, 5];
const square = num => num * num;
console.log(myNums.map(square));
```

#### filter

filter digunakan jika kita ingin memfilter array lama, dengan memilih beberapa anggota array yang memenuhi kriteria yang diinginkan. Hasil filter akan disimpan dalam sebuah array baru dan tidak merubah array yang asli.

```javascript
const myNums = [1, 2, 3, 4, 5];
const even = num => num%2 === 0
const odd = num => num%2 !== 0
const bigSquare = num => num * num > 10;
console.log("filter genap", myNums.filter(even));
console.log("filter ganji", myNums.filter(odd));
console.log("filter big square", myNums.filter(bigSquare));
```

## Struktur data terkait array

Struktur data adalah cara penyimpanan, penyusunan dan pengaturan data di dalam media penyimpanan komputer sehingga data tersebut dapat digunakan secara efisien

Ada beberapa struktur data terkait array, pada kesempatan ini saya akan mengenalkan tiga struktur data yang sering digunakan :

1. **Stack**\
   Stack adalah struktur data tumpukan, dimana menggunakan prinsip LIFO (Last In First Out)&#x20;
2. **Queue**\
   Queue adalah struktur data antrian, dimana menggunakan prinsip FIFI (First In First Out)
3. **Set**\
   Set adalah data struktur dimana setiap nilai anggotanya adalah unique (tidak ada anggota yang kembar)


# JSON

### JSON object

JSON merupakan singkatan dari **J**ava**S**cript **O**bject **N**otation. Untuk membuat JSON On=bject harus memenhi kriteria:

* Data dalam pasangan nama dan nilai.
* Data dipisahkan dengan koma.
* Object dibuat dengan kururung kurawal {}
* Array dibuat dengan kurung persegi \[]&#x20;

JSON object bisa dideklarasikan dengan berbagai cara :

```javascript
const ninja1 = {
    nama: "Naruto",
    umur: 12,
    alamat: "Desa Konoha",
    jurus: ["kage bunshin", "rasengan"]
}
console.log(ninja1);

const ninja2 = {}
ninja2.nama = "Naruto";
ninja2.umur = 12;
ninja2.alamat = "Desa Konoha";
ninja2.jurus = ["kage bunshin", "rasengan"];
console.log(ninja2);

const ninja3 = new Object();
ninja3.nama = "Naruto";
ninja3.umur = 12;
ninja3.alamat = "Desa Konoha";
ninja3.jurus = ["kage bunshin", "rasengan"];
console.log(ninja3);

// kita bisa mengakses langsung properti object
console.log(ninja3.nama);
console.log(ninja3["nama"]);
```

### JSON stringify

Digunakan untuk mengubah json object menjadi string

```javascript
const ninja1 = {
  nama: "Naruto",
  umur: 12,
  alamat: "Desa Konoha",
  jurus: ["kage bunshin", "rasengan"]
}
console.log(ninja1);
console.log(JSON.stringify(ninja1));
```

### JSON parse

Digunakan untuk mengubah string menjadi JSON Object

```javascript
ninjaStr = '{"nama":"Naruto","umur":12,"alamat":"Desa Konoha","jurus":["kage bunshin","rasengan"]}';
console.log(JSON.parse(ninjaStr));
```

### delete&#x20;

Digunakan untuk menghapus properti dari sebuah object. Sementara untuk menambah properti jauh lebih simple, sama seperti waktu deklarasi object, langsung menambah properti yang diinginkan.

```javascript
const ninja1 = {
  nama: "Naruto",
  umur: 12,
  alamat: "Desa Konoha",
  jurus: ["kage bunshin", "rasengan"]
};
console.log(ninja1);
delete ninja1.umur;
delete ninja1["alamat"];
console.log(ninja1);
```


# Error Handling

Dalam membuat aplikasi, error pasti akan terjadi dan harus kita handle. Error bisa disebabkan oleh banyak hal, sintaks kode yang salah, input user yang salah, dan lain-lain.

### try - catch

Penangan error dilakukan dengan sintaks try - catch, artinya kita akan mencoba untuk mengeksekusi suatu kode, namun jika ada error kita akan menagkapnya.

```javascript
try {
  alart("selamat pagi");
} catch (err) {
  console.error("terjadi error : ", err);
}
```

### throw error

error bisa dibuat secara kustom melalui perintah throw.

```javascript
try {
  const angka = prompt("masukkan angka untuk dibagi");
  switch (true) {
    case angka == 0:
      throw "tidak bisa membagi dengan nol";
      break;
    case angka < 0 :
      console.log("membagi dengan angka negatif");
      break;
    case angka > 0 :
      console.log("membagi dengan angka positif");  
      break;
  }
} catch (err) {
  console.error("terjadi error : ", err);
}
```

### finally

finally adalah suatu blok yang selalu dieksekusi dalam sebuah rangkaian try-catch-finally

```javascript
try {
  const angka = prompt("masukkan angka untuk dibagi");
  switch (true) {
    case angka == 0:
      throw "tidak bisa membagi dengan nol";
      break;
    case angka < 0 :
      console.log("membagi dengan angka negatif");
      break;
    case angka > 0 :
      console.log("membagi dengan angka positif");  
      break;
    default:
      console.log("anda tidak memasukkan angka");
      break;
  }
} catch (err) {
  console.error("terjadi error : ", err);
} finally {
  console.log("selesai");
}
```


# AJAX

AJAX = **A**synchronous **J**avaScript **A**nd **X**ML. Merupakan kombinasi dari `XMLHttpRequest` dan JavaScript DOM. XMLHttpRequest digunakan untuk memanggil API, semanatar javascript DOM digunakan untuk mengolah dan menampilkan data hasil dari pemanggilan API.

Ajax dibagi menjadi tiga tahapan :

1. Membuat objek XMLHttpRequest\
   `const xhttp = new XMLHttpRequest();`&#x20;
2. Membuat callback. \
   `xhttp.onload = function() {` \
   &#x20;   `// lakukan manipulasi DOM ketika sudah mendapat response` \
   `}`
3. Mengirim request.\
   `xhttp.open("http method: GET|POST|PUT|DELETE", "url");` \
   `xhttp.send();`

Untuk persiapan dan bahan pembelajaran, saya sudah sediakan CRUD Rest API untuk digunakan, yaitu :\
\- GET /users\
\- POST /users\
\- GET /users/:id\
\- PUT /users/:id\
\- DELETE /users/:id\
Url bisa diakses melalui :  <https://node-rest.rijalasepnugroho.com>

### List

Buat file list-user.html

```markup
<h1>AJAX - List User</h1>
<main></main>
<script>

  function list() {
    const xhttp = new XMLHttpRequest();
    xhttp.onload = function() {
      const tables = [];
      tables.push(`
        <tr>
          <th>No</th>
          <th>Nama</th>
          <th>Umur</th>
        </tr>
      `); 
      users = JSON.parse(this.responseText);
      let no = 1;
      for (user of users) {
        tables.push(`
          <tr>
            <td>${no}</td>
            <td>${user.name}</td>
            <td>${user.age}</td>
          </tr>
        `);
        no++;
      }

      const html = `
        <table>
          ${tables.join("")}
        </table>
      ` 
      const parent = document.getElementsByTagName("main")[0];
      parent.innerHTML = "";
      parent.insertAdjacentHTML("beforeend", html);
    };  
    xhttp.open("GET", "https://node-rest.rijalasepnugroho.com/users");
    xhttp.send();
  }

  list();
  </script>
```

### Insert

Saat insert, method yang gunakan adalah "POST" dan saat send() kita mengirim data berupa string json.\
\
`xhttp.open("POST", "http://localhost:3000/users", true);`\
`xhttp.send(JSON.stringify(user));`

Kita akan membuat perubahan pada halaman Ajax dengan logik seperti berikut

1. Pada file list-user.html tambahkan button "Tambah User" yang jika diklik akan redirect ke halaman add-user.html
2. Buat halaman add-user.html yang berisi form.
3. Form dicegah untuk submit karena akan dihandle lewat ajax.\
   `document.getElementById("form").addEventListener("submit", function(event){       event.preventDefault();`\
   &#x20;`})`
4. Buat fungsi add() untuk memangil ajax POST /users
5. Pada callback AJAX, dibuat pengecekan, jika response berhasil dan menghasilkan id, maka akan redirect kembali ke halaman list.

Ubah file list-user.html untuk menambahkan tombol "Tambah User".&#x20;

```markup
<h1>AJAX - List User</h1>
<button onclick="location.href='./add-user.html'">Tambah User</button>
<main></main>
<script>

  function list() {
    const xhttp = new XMLHttpRequest();
    xhttp.onload = function() {
      const tables = [];
      tables.push(`
        <tr>
          <th>No</th>
          <th>Nama</th>
          <th>Umur</th>
        </tr>
      `); 
      users = JSON.parse(this.responseText);
      let no = 1;
      for (user of users) {
        tables.push(`
          <tr>
            <td>${no}</td>
            <td>${user.name}</td>
            <td>${user.age}</td>
          </tr>
        `);
        no++;
      }

      const html = `
        <table>
          ${tables.join("")}
        </table>
      ` 
      const parent = document.getElementsByTagName("main")[0];
      parent.innerHTML = "";
      parent.insertAdjacentHTML("beforeend", html);
    };  
    xhttp.open("GET", "https://node-rest.rijalasepnugroho.com/users");
    xhttp.send();
  }

  list();
  </script>

```

Buat file add-user.html

```markup
<h1>AJAX - Add user</h1>
<form id="form">
  <div>
    <label for="email">Email</label>
    <input type="email" onchange="changeUser('email', this.value)" name="email" placeholder="email" required/>
  </div>

  <div>
    <label for="password">Password</label>
    <input type="password" onchange="changeUser('password', this.value)" name="password" placeholder="password" required/>
  </div>

  <div>
    <label for="name">Nama</label>
    <input type="name" onchange="changeUser('name', this.value)" name="text" placeholder="nama" required/>
  </div>

  <div>
    <label for="age">Umur</label>
    <input type="number" onchange="changeUser('age', this.value)" name="age" placeholder="umur" required/>
  </div>

  <button onclick="add()">Tambah User</button>
</form>

<script>
  document.getElementById("form").addEventListener("submit", function(event){
    event.preventDefault();
  });

  const curUser = {};

  function changeUser(field, value) {
    curUser[field] = value;
  }

  function add() {
    var xhttp = new XMLHttpRequest();
    xhttp.open("POST", "https://node-rest.rijalasepnugroho.com/users", true);
    xhttp.onload = function() {
      const newUser = JSON.parse(this.responseText);
      if (newUser.id > 0) {
        location.href = "./list-user.html";
      } 
    }
    xhttp.setRequestHeader("Content-type", "application/json");
    xhttp.send(JSON.stringify(curUser));
  }
  </script>
```

### Single page using modal

kadang kita ingin menjadikan halaman list dan add dalam satu halaman saja. Solusinya adalah membuat form tambah user dalam bentuk modal. Logic pembuatan single page adalah sebagia berikut :

1. Tambahkan modal form add-user dalam file list-user.html dalam keadaan hide.
2. Jika ada klik "Tambah User" maka tampilkan modal form add-user.
3. Setelah submit form tambah user maka modal kembali dihide dan load ulang fungsi list() untuk melakukan pembaruan data.

Berikut file list-user.html

```markup
<style>
  #modal{
    display: none;
    background-color: #808080aa;
    position: fixed;
    height: 100%;
    width: 100%;
    top: 0;
    left: 0;
    z-index:99;
  }

  #form-container {
    width:100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
  }

  form {
    width: 38%;
    background-color: white;
    border: 1px solid black;
    padding: 1%;
  }

  form div {
    padding: 2%;
  }

  form label {
    display: inline-block;
    width: 20%; 
  }

  form input {
    width: 77%;
  }

  #closeBtn {
    position: relative;
    left: calc(100% - 30px); 
    top:0;
  }
</style>

<h1>AJAX - List User</h1>
<div id="modal">
  <div id="form-container">
    <form id="form">
      <button id="closeBtn" onclick="closeModal()">X</button>
      <div>
        <label for="email">Email</label>
        <input type="email" onchange="changeUser('email', this.value)" name="email" placeholder="email" required/>
      </div>
    
      <div>
        <label for="password">Password</label>
        <input type="password" onchange="changeUser('password', this.value)" name="password" placeholder="password" required/>
      </div>
    
      <div>
        <label for="name">Nama</label>
        <input type="name" onchange="changeUser('name', this.value)" name="text" placeholder="nama" required/>
      </div>
    
      <div>
        <label for="age">Umur</label>
        <input type="number" onchange="changeUser('age', this.value)" name="age" placeholder="umur" required/>
      </div>
    
      <button onclick="add()">Tambah User</button>
    </form>
  </div>
</div>
<button onclick="openModal()">Tambah User</button>
<main></main>
<script>
  document.getElementById("form").addEventListener("submit", function(event){
    event.preventDefault();
  });

  const curUser = {};

  function changeUser(field, value) {
    curUser[field] = value;
  }

  function add() {
    var xhttp = new XMLHttpRequest();
    xhttp.open("POST", "https://node-rest.rijalasepnugroho.com/users", true);
    xhttp.onload = function() {
      const newUser = JSON.parse(this.responseText);
      if (newUser.id > 0) {
        closeModal();
        list();
      } 
    }
    xhttp.setRequestHeader("Content-type", "application/json");
    xhttp.send(JSON.stringify(curUser));
  }

  function list() {
    const xhttp = new XMLHttpRequest();
    xhttp.onload = function() {
      const tables = [];
      tables.push(`
        <tr>
          <th>No</th>
          <th>Nama</th>
          <th>Umur</th>
        </tr>
      `); 
      users = JSON.parse(this.responseText);
      let no = 1;
      for (user of users) {
        tables.push(`
          <tr>
            <td>${no}</td>
            <td>${user.name}</td>
            <td>${user.age}</td>
          </tr>
        `);
        no++;
      }

      const html = `
        <table>
          ${tables.join("")}
        </table>
      ` 
      const parent = document.getElementsByTagName("main")[0];
      parent.innerHTML = "";
      parent.insertAdjacentHTML("beforeend", html);
    };  
    xhttp.open("GET", "https://node-rest.rijalasepnugroho.com/users");
    xhttp.send();
  }

  function openModal(){
    document.getElementById("modal").style.display = 'block';
  }

  function closeModal(){
    document.getElementById("modal").style.display = 'none';
  }

  list();
  </script>
```


# Local Storage

Ada banyak cara untuk menyimpan data ke dalam storage di browser. Kita bisa mengeceknya melalui developer tool dan klik tab Application. Di sebelah kiri terdapat menu, lihat menu Storage, ada banyak pilihan di sana meliputi : Local Storage, Session Storage, IndexedDB, Web SQL, Cookies dan Trust Tokens.

Kali ini kita akan memanfaatkan local storage untuk menyimpan data token yang didapatkan setelah berhasil login.&#x20;

Untuk menyimpan data menggunakan perintah `localStorage.setItem("nama-key", "value-yang-hendak-disimpan")`. Sementara untuk membaca data menggunakan perintah `localStorage.getItem("nama-key")`. Untuk menghapus local storage berdasarkan key, gunakan perintah `localStorage.removeItem("nama-key")`.

```javascript
// Store
localStorage.setItem("token", "akxakcnacnadkasaksnaksasaksnasnaks");
// Retrieve
console.log(localStorage.getItem("token"));
// Remove
localStorage.removeItem("token");
```

Praktek-kan ke dalam kode login yang pernah dibuat. Buat file login.html

```markup
<main>
  <h1>Login</h1>
  <form id="form">
    <div>
      <label for="email">Email</label>
      <input type="email" onchange="changeUser('email', this.value)" name="email" placeholder="email" required/>
    </div>
  
    <div>
      <label for="password">Password</label>
      <input type="password" onchange="changeUser('password', this.value)" name="password" placeholder="password" required/>
    </div>
  
    <button onclick="login()">Login</button>
  </form>
</main>

<script>
  document.getElementById("form").addEventListener("submit", function(event){
    event.preventDefault();
  });

  const curUser = {};

  function changeUser(field, value) {
    curUser[field] = value;
  }

  function login() {
    var xhttp = new XMLHttpRequest();
    xhttp.open("POST", "https://node-rest.rijalasepnugroho.com/login", true);
    xhttp.onload = function() {
      const loginResponse = JSON.parse(this.responseText);
      if (loginResponse.token) {
        localStorage.setItem("token", loginResponse.token);
        location.href = "./list-user.html";
      } 
    }
    xhttp.setRequestHeader("Content-type", "application/json");
    xhttp.send(JSON.stringify(curUser));
  }
  </script>
```

Jika login berhasil maka di dalam local storage akan tersimpan Key = token dan Value = alabama-token.

Agar lebih riil, maka di dalam halaman yang harus login terlebih dahulu, dilakukan pengecekan apakah sudah login atau belum, jika belum diredirct ke halaman login.

```javascript
  if (!localStorage.getItem("token")) {
    location.href = "./login.html";
  }
```

Penganganan logout juga diperlukan. Tambahkan button logout yang jika diklik akan mengahapus local storage dan redirect ke halamn login.

```markup
<button onclick="localStorage.removeItem('token'); location.href='./login.html'">Logout</button>
```


# Param Url

Seringkali kita membutuhkan suatu nilai yang dilempar sebagai parameter url. Perhatikan url berikut :  <http://localhost/users?id=101\\&name=jhon>

url di atas mempunyai dua parameter, yaitu parameter id dengan nilai 101, dan paremeter name dengan nilai jhon.

Untuk mengambil paremeter url, javascript sudah menyediakan object yang dibutuhkan, yaitu object location. Object location ini sudah sering kita gunakan sebagai redirect, yaitu dengan mengganti properti href dari object location tersebut.&#x20;

```javascript
console.log(location);
console.log(location.search);
```

Perhatikan location.search yang didapatkan yaitu ?id=101\&name=jhon, yang mempunyai pola diawali dengan '?' dan setiap parameter diseparator dengan '&'. Masing-masing parameter merupakan pasangan key dan value yang dipisahkan dengan '='.&#x20;

Dengan pola ini kita bisa mengubah paremeter url menjadi object json.

```javascript
function convertSearchToObj(){
    const paramUrl = {};
    location.search.substr(1).split("&").forEach((param) => {
      const pair = param.split("=");
      paramUrl[pair[0]] = pair[1];
    });
    return paramUrl;
  }

  const paramUrl = convertSearchToObj();
  console.log(paramUrl);
  if (paramUrl.id) {
    console.log(paramUrl.id);
  }
```


# Notification

Notification mutlak diperlukan ketika kita bertransaksi dengan data, apakah transaksi kita sukses atau gagal. Untuk membuat notification cukup sederhana, dengan memanfaatkan css modal dan fungsi setTimeout().

### Modal

&#x20;Buat modal notification dengan html dan css seperti berikut

```html
<style>
  #notification{
    display: none;
    position: fixed;
    height: 100%;
    width: 100%;
    top: 0;
    left: 0;
    z-index:99;
  }

  #notification div#notif-container{
    width:100%;
    height: 100%;
    display: flex;
    justify-content: center;
    margin-top: 20px;
  }

  #notification div#notif-container div#notif-content {
    width: 50%;
    height: 40px;
    padding: 1%;
  }

  .notif-success {
    background-color: green;
    color: white;
  }

  .notif-warning {
    background-color: yellow;
    color: black;
  }

  .notif-error {
    background-color: red;
    color: white;
  }

  .notif-info {
    background-color: grey;
    color: white;
  }
  
</style>

<div id="notification">
  <div id="notif-container">
    <div id="notif-content"></div>
  </div>
</div>
```

### SetTimeout

SetTimeout adalah fungsi javascript yang digunakan untuk memberi jeda eksekusi suatu callback (blok fungsi). Idenya adalah :&#x20;

1. Tampilkan modal notification
2. dengan fungsi setTimeout(), setlah beerapa mili second, modal notification kembali disembunyikan.
3. Redirect ke halaman yang diinginkan.

```javascript
function showNotification(message, type, redirect="") {
    let notifClass = "info";
    if (type === "error" || type === "warning" || type == "success") {
      notifClass = type;
    }

    const notifDiv = document.getElementById("notif-content");
    notifDiv.innerHTML = message;
    notifDiv.classList.add("notif-"+type);
    document.getElementById("notification").style.display = "block";
    
    setTimeout(function(){
      document.getElementById("notification").style.display = "none";
      notifDiv.classList.remove("notif-"+type);
      notifDiv.innerHTML = ""; 
      if (redirect) {
        location.href=redirect;
      }
    }, 3000); 
  }
```

### Implementasi Login Notification

Selanjutnya kita akan memodifikasi file login.html agar mempunyai notification. Fungsi listening event onload dimodifikasi agar jika sukses akan menampilkan notifikasi sukses, dan jika gagal login akan menampilkan notifikasi error login.&#x20;

```javascript
function login() {
    var xhttp = new XMLHttpRequest();
    xhttp.open("POST", "https://node-rest.rijalasepnugroho.com/login", true);
    xhttp.onload = function() {
      const loginResponse = JSON.parse(this.responseText);
      if (loginResponse.token) {
        localStorage.setItem("token", loginResponse.token);
        showNotification("Login success", "success", "./list-user.html");
      } else {
        showNotification("Login failed", "error");
      }
    }
    xhttp.setRequestHeader("Content-type", "application/json");
    xhttp.send(JSON.stringify(curUser));
  }
```

Berikut adalah kode lengkap file login.html nyang sudah ditambahkan notification.

```html
<style>
  #notification{
    display: none;
    position: fixed;
    height: 100%;
    width: 100%;
    top: 0;
    left: 0;
    z-index:99;
  }

  #notification div#notif-container{
    width:100%;
    height: 100%;
    display: flex;
    justify-content: center;
    margin-top: 20px;
  }

  #notification div#notif-container div#notif-content {
    width: 50%;
    height: 40px;
    padding: 1%;
  }

  .notif-success {
    background-color: green;
    color: white;
  }

  .notif-warning {
    background-color: yellow;
    color: black;
  }

  .notif-error {
    background-color: red;
    color: white;
  }

  .notif-info {
    background-color: grey;
    color: white;
  }
  
</style>

<div id="notification">
  <div id="notif-container">
    <div id="notif-content"></div>
  </div>
</div>

<main>
  <h1>Login</h1>
  <form id="form">
    <div>
      <label for="email">Email</label>
      <input type="email" onchange="changeUser('email', this.value)" name="email" placeholder="email" required/>
    </div>
  
    <div>
      <label for="password">Password</label>
      <input type="password" onchange="changeUser('password', this.value)" name="password" placeholder="password" required/>
    </div>
  
    <button onclick="login()">Login</button>
  </form>
</main>

<script>
  document.getElementById("form").addEventListener("submit", function(event){
    event.preventDefault();
  });

  const curUser = {};

  function changeUser(field, value) {
    curUser[field] = value;
  }

  function login() {
    var xhttp = new XMLHttpRequest();
    xhttp.open("POST", "https://node-rest.rijalasepnugroho.com/login", true);
    xhttp.onload = function() {
      const loginResponse = JSON.parse(this.responseText);
      if (loginResponse.token) {
        localStorage.setItem("token", loginResponse.token);
        showNotification("Login success", "success", "./list-user.html");
      } else {
        showNotification("Login failed", "error");
      }
    }
    xhttp.setRequestHeader("Content-type", "application/json");
    xhttp.send(JSON.stringify(curUser));
  }

  function showNotification(message, type, redirect="") {
    let notifClass = "info";
    if (type === "error" || type === "warning" || type == "success") {
      notifClass = type;
    }

    const notifDiv = document.getElementById("notif-content");
    notifDiv.innerHTML = message;
    notifDiv.classList.add("notif-"+type);
    document.getElementById("notification").style.display = "block";
    
    setTimeout(function(){
      document.getElementById("notification").style.display = "none";
      notifDiv.classList.remove("notif-"+type);
      notifDiv.innerHTML = ""; 
      if (redirect) {
        location.href=redirect;
      }
    }, 3000);
    
  }
  </script>
```


# Asynchronous

Asynchronous adalah suatu proses yang dikerjakan secara bersamaan. Di javascript, umumnya suatu kode dikerjakana secara berurutan (synchronous), namun ada banyak yang dikerjakan secara asynchronous sepert event dan Ajax.

Keuntungan penggunaan aynchronous adalah proses menjadi lebih cepat, karena tidak harus menunggu suatu blok kode selessai dikerjakan. Jika javascript menemukan suatu proses yang lama, maka sambil menunggu proses itu selesai, javascript akan mengeksekusi kode selanjutnya.

Kelemahan asynchronous adalah adanya kemungkinan race condition jika ada suatu blok kode yang membutuhkan hasil dari proses lain, tenryata dieksekusi ketika proses lain tersebut belum memberikan hasil. Besar kemungkinan ketika bliok kode tersebut, datanya masih kosong.

Untuk mengatasi hal tersebut, dalam pemrograman asynchronous dioptimalkan penggunaan callback, async/await dan promise.

## Callback

Kita telah mempelajari callback sebelumnya. Dalam proses asynchronous, penggunaan callback sangat masif.  Sebagai contoh, kita akan menggunakan kode pemanggilan AJAX dengan teknik callback. Namun agar pemahaman lebih utuh, awalnya kita aklan mebuat contoh kode tanpa callback.

```markup
<h1>Callback Async - AJAX - List User</h1>
<main></main>
<script>
  let users = [];

  function displayUser() {
    const tables = [];
      tables.push(`
        <tr>
          <th>No</th>
          <th>Nama</th>
          <th>Umur</th>
        </tr>
      `); 
      let no = 1;
      for (user of users) {
        tables.push(`
          <tr>
            <td>${no}</td>
            <td>${user.name}</td>
            <td>${user.age}</td>
          </tr>
        `);
        no++;
      }

      const html = `
        <table>
          ${tables.join("")}
        </table>
      ` 
      const parent = document.getElementsByTagName("main")[0];
      parent.innerHTML = "";
      parent.insertAdjacentHTML("beforeend", html);
  }

  function list() {
    const xhttp = new XMLHttpRequest();
    xhttp.onload = function() {
      users = JSON.parse(this.responseText);
    };  
    xhttp.open("GET", "https://node-rest.rijalasepnugroho.com/users");
    xhttp.send();
  }

  list();
  displayUser();
  </script>
```

Pada kode di atas, kita memanggil list(); kemudian memangil displayUser();. fungsi list() berguna untuk mengupdate variabel users dengan data hasil call ajax. Sementara fungsi displayUser() berguna untuk menampilkan data list user ke dalam tabel.

Harapannya akan tampil table list user dengan sleuruh data yang ada. Namun karena list() membutuhkan waktu lebih lama, maka displayUser hanya menampilkan header table saja, karena ketika fungsi displayUser() dijalankan, saat itu variabel users masih kosong.

Ide dasarnya adalah bagaimana caranya agar fungsi displayUser() dipanggil setelah fungsi list() selesai dieksekusi. Salah satu teknik yang digunakan adalah dengan callback, dimana funhsi displayUser() akan dipanggil tepat setelah variabel users diupdate.

Kita akan perbaiki kode di atas dengan teknik callback. fungsi displayUser akan dilempar sebagai parameter fungsi list(), dan dipanggil tepat setelah variabel users diupdate.

```javascript
  function list(myCallback) {
    const xhttp = new XMLHttpRequest();
    xhttp.onload = function() {
      users = JSON.parse(this.responseText);
      myCallback();
    };  
    xhttp.open("GET", "https://node-rest.rijalasepnugroho.com/users");
    xhttp.send();
  }

  list(displayUser);
```

## Promise

Promise adalah suatu teknik handling asynchronous dengan memberi janji bahwa suatu kode akan dieksekusi dan hasilnya (apakah akan berhasil atau tidak)  akan diberi tahu kemudian. Cara untuk mengetahui hasil suatu promise adalah dengan mendengarkan/mengikuti/listen promise.&#x20;

Dengan teknik ini, akan ad dua buah kode, yaiti kode producer (yang memberi janji), dan kode konsumer (yang mendengarkan hasil).

Kode producer mengembalikan suatiu promise dengan dua callback, yaitu bila sukses akan menjalankan callback resolve() sementara jika gagal akan mengembalikan callback reject(). Format producer promise adalah sebagai berikut :

```javascript
let myPromise = new Promise(function(myResolve, myReject) {
  // kode yang mungkin butuh waktu lama untuk eksekusi
  myResolve(); // when successful
  myReject();  // when error
});
```

Sementara kode untuk konsumer adalah dengan kata kunci then untuk handling jika hasilnya adalah sukses, dan catch jika hasilnya adalah error.

```javascript
myPromise
.then(result => console.log(result))
.catch(err => console.error(err));
```

Kita bisa melengkapi konsumer dengan kata kunci finally yang akan selalu dieksekusi baik sukses maupun error.

```javascript
myPromise
.then(result => console.log(result))
.catch(err => console.error(err))
.finally(console.log("seleseai"));
```

Sebagi contoh, kita akan mengubah penggunaan callback pada list user dengan promise. Karena pada contoh AJAX sebelumnya kita tidak menghandle error, saya akan mengenalkan event baru di xmlHttprequest yaitu onreadystatechange untuk menghandle event jika ajax sudah selesai. Juga ada suatu properti status untuk mengetahui status code dari response ajax.

```javascript
  function list() {
    return new Promise(function(resolve, reject){
      const xhttp = new XMLHttpRequest();
      xhttp.open("GET", "https://node-rest.rijalasepnugroho.com/users");
      xhttp.onreadystatechange = () => {
        if (xhttp.status !== 200) {
          reject(new Error("Error call list user"));
        } else {
          xhttp.onload = () => resolve(JSON.parse(xhttp.responseText));
        }
      };
      xhttp.send();
    });
  }

  list()
  .then(result => {
    users = result;
    displayUser();
  }).catch(err => console.error(err))
  .finally(console.log("selesai"));
```

## Promise.all()

Ada kalanya kode yang dijanjikan bukan hanya satu, namun bisa banyak kode yang dijanjikan. Untuk konsumer, bisa dengan memanfaatkan fitur Promise.all() untuk melisten seluruh kode yang dijanjikan.

```javascript
let promises = [];
promises.push(Promise.resolve("halo"));
promises.push(212);
promises.push(new Promise((res, rej) => {
    res(100);
}));

Promise.all(promises)
.then(result => console.log(result));
```

## async/await

Penulisan sintaks promise agak merepotkan, untunglah javascript menawarkan solusi async/await. kata kunci async yang diletakkan sebelum function membuat fungsi tersebut akan mengembalikan promise.

```javascript
async function salam () {
    return "Selamat Pagi";
}

// artinya sama dengan kode promise berikut
async function salam () {
    return Promise.resolve("Selamat Pagi");
}
 
```

Sementara sintaks await digunakan untuk menunggu promise selesai dieksekusi. Yang perlu diperhatikan adalah, async-await ini merupakan sintaks ES modern yang hanya bekerja dalam suatu module. Pastikan ketika menulis script, tambahkan informasi type=module.

```markup
<script type="module">
  // simple async-await
  async function salam() {
    return "Selamat Pagi";
  }

  const pagi = await salam();
  console.log(pagi);
  
  // async - promiseConsumer
  async function salam2() {
    return "Selamat Siang";
  }  
  
  salam2().then(result => console.log(result));
  
  // promiseProducer - await
  function salam3() {
    return new Promise(function(res, rej){
      res("Selamat Sore");
    });
  }
  
  const sore = await salam3();
  console.log(sore);
</script>
```

Dengan mengetahui konsep async dan await, kita bisa mengubah file list-user menjadi kode berikut:

```markup
<h1>Callback Async - AJAX - List User</h1>
<main></main>
<script type="module">
  let users = [];

  function displayUser() {
    const tables = [];
      tables.push(`
        <tr>
          <th>No</th>
          <th>Nama</th>
          <th>Umur</th>
        </tr>
      `); 
      let no = 1;
      for (const user of users) {
        tables.push(`
          <tr>
            <td>${no}</td>
            <td>${user.name}</td>
            <td>${user.age}</td>
          </tr>
        `);
        no++;
      }

      const html = `
        <table>
          ${tables.join("")}
        </table>
      ` 
      const parent = document.getElementsByTagName("main")[0];
      parent.innerHTML = "";
      parent.insertAdjacentHTML("beforeend", html);
  }

  function list() {
    return new Promise(function(resolve, reject){
      const xhttp = new XMLHttpRequest();
      xhttp.open("GET", "https://node-rest.rijalasepnugroho.com/users");
      xhttp.onreadystatechange = () => {
        if (xhttp.status !== 200) {
          reject(new Error("Error call list user"));
        } else {
          xhttp.onload = () => resolve(JSON.parse(xhttp.responseText));
        }
      };
      xhttp.send();
    });
  }

  users = await list();
  displayUser();
  </script>
```


# Praktikum II : Mengintegrasikan Halaman Login dan CRUD dengan AJAX

Setelah belajar tentang AJAX, yaitu teknik untuk mengintegrasikan aplikasi frontend (HTML, Javascript) dengan backend, saatnya kita mengerjakan tugas praktikum.

Untuk keperluan praktikum, sudah disediakan aplikasi backend : url : <https://node-rest.rijalasepnugroho.com> dengan endpoint:

* POST /login

  &#x20;data : {"email": "<saya@bangga.com>", "password": "1234"}
* GET /users
* POST /users

  &#x20;data : {"email": "<email@saya.com>", "password": "1234", "name": "nama saya", "age": 12}
* GET /users/6
* PUT /users/6

  &#x20;data: {"name": "saya bangga sekali", "age":23}
* DELETE /users/22 &#x20;

Tugas praktikum-nya adalah :&#x20;

1. Gunakan layout dari Tugas praktikum I yang dulu pernah dibuat.&#x20;
2. Mengintegrasikan dengan backend melalui AJAX.&#x20;
3. Tugas Praktikum akan dipresentasikan pada pertemuan mendatang.


# Pengenalan Database

Apa itu Database?

Apa itu MySQL?

Mengapa MySQL?

Apa itu MySQL Workbench?

Bagaimana Menginstall MySQL Workbench?


# Perancangan Database


# Operasi Select


# Operasi Join


# Operasi Insert


# Operasi Update


# Operasi Delete


# Pengenalan Node JS

Node JS memungkinkan javascript untuk bekerja di sisi server.

### Installasi NodeJS

Installasi NodeJS bisa dilakukan dengan mendownload melalui halaman <https://nodejs.org/en/download/> dan pilih versi LTS. Ikuti langkah-langkah yang disampaikan ketika melakukan instalasi.&#x20;

Untuk mengecek apakah installasi berhasil dengan baik, ketik perintah berikut :\
`node -v`\
`npm -v` \
npm adalah node package manager untuk mengelola paket-paket library di javascript.&#x20;

### Get Started

{% code title="index.js" %}

```javascript
var http = require('http');

http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/html'});
  res.end('Selamat Pagi!');
}).listen(8080);
```

{% endcode %}

Jalankan dengan perintah `node index.js`

Kemudian buka browser localhost:8080


# Module

module.export

required

import - export


# Express

Express JS adalah framework yang handal di nodejs. Pembuatan routing menjadi lebih mudah.

### Create Project

```
npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help init` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (nodejs) backend
version: (1.0.0) 
description: backend untuk latihan
entry point: (index.js) index.js
test command: 
git repository: 
keywords: 
author: 
license: (ISC) 
About to write to /Users/rijal/jackyhtg/seri-belajar-pemrograman/nodejs/package.json:

{
  "name": "backend",
  "version": "1.0.0",
  "description": "backend untuk latihan",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}


Is this OK? (yes) yes
```

### Install Express

Kemudian lanjukan dengan menginstall expres js

```
npm install express
```

### Basic Routing

```javascript
var express = require('./node_modules/express');

var app = module.exports = express();

app.use(express.json());

app.get('/', function (req, res) {
  res.send('Selamat Pagi!')
});

app.get('/users', function (req, res) {
  const users = [
    {name: "Jacky", age: 17},
    {name: "Jaya", age: 15},
    {name: "Baya", age: 12}
  ];
  res.json(users)
});

app.post('/users', function (req, res) {
  const user = {
    name: req.body.name,
    age: req.body.age
  };
  res.status(201).send(user);
});

app.put('/users/:id', function (req, res) {
  var id = req.params.id;
  const user = {
    id,
    name: req.body.name,
    age: req.body.age
  };
  res.json(user)
});

app.delete('/users/:id', function (req, res) {
  res.sendStatus(204);
});

app.listen(3000);
console.log('Express started on port 3000');
```


# Rest API

## Rest API

### Method

### Status Code

## Clean Arsitektur

### Routing

### Service

### Model

### Repositories

### Dependency Injection

## Mysql Connection

Buat file helper.config.js

```javascript
module.exports = {
  DB: {
    HOST: "localhost",
    USER: "root",
    PASSWORD: "pass",
    DB: "latihan"
  }
};
```

Buat file helper/mysql.js

```javascript
const mysql = require("mysql");
const DbConfig = require("./config");

// Create a connection to the database
const connection = mysql.createConnection({
  host: DbConfig.DB.HOST,
  user: DbConfig.DB.USER,
  password: DbConfig.DB.PASSWORD,
  database: DbConfig.DB.DB
});

// open the MySQL connection
connection.connect(error => {
  if (error) throw error;
  console.log("Successfully connected to the database.");
});

module.exports = connection;
```

## CRUD

Untuk Rest API, kita akan menyediakan 5 endpoint meliputi Create, Read, Update dan Delete (CRUD). Penamaaan dan method endpoint mengikuti konsep best practice Rest API, yaitu :\
\- GET /users --> untuk mendapatkan list seluruh users\
\- POST /users --> untuk membuat user baru\
\- GET /users/:id --> untuk mendapatkan satu user berdasarkan id\
\- PUT /users/:id --> untuk mengubah data user berdasarkan id\
\- DELETE /users/:id --> untuk menghapus user berdasarkan id\
\- POST /login --> untuk login user

Karena menggunakan desain Clean Arsiteksur, maka struktur folder project kita meliputi:

\[domain]\
\---- \[users]\
&#x20;     \---- \[repositories]\
&#x20;           \---- file-repository.js\
&#x20;     \----  \[services]\
&#x20;           \---- file-service.js\
&#x20;     \---- model.js\
&#x20;     \---- route.js\
&#x20;     \---- service.js\
\[helper]\
\---- file-helper.js\
index.js\
\
file index.js berisi :

```javascript
var express = require('./node_modules/express');
const DB = require('./helper/mysql');
var cors = require('cors');
var app = express();

app.use(cors());
app.use(express.json());

require("./domain/users/route.js")(app, DB);

app.listen(3000);
console.log('Express started on port 3000');
```

file index.js ini simple dan hanya bertugas untuk melakukan pekerjaan middleware berupa :\
\- handling cors melalui middleware cors()\
\- handling json body parser melalui middleware express.json()\
Untuk installasi cors jalankan `npm install cors`

Selain itu, konkesi database juga dicreate di file index,js yang nantinya akan diteruskan (diinjeksi) ke seluruh service yang membutuhkan mengikuti konsep dependency injection.

Routing dilakukan dengan memanggil routing yang ada di setiap domain.&#x20;

### GET /users

Buat file domain/users/route.js untuk membuat routing GET /users

```javascript
module.exports = (app, DB) => {
  const users = require("./service.js")(DB);

  app.get("/users", users.List);
};
```

Buat file domain/users/service.js

```javascript
module.exports = db => {
  const List = require("./services/list_user")(db);

  return { List };
};
```

Buat file domain/users/services/list\_user.js

```javascript
module.exports = db => {
  const User = require("../model.js")(db);

  return (req, res) => {
    User.List((err, data) => {
      if (err)
        res.status(500).send({
          message:
            err.message || "Some error occurred while retrieving users."
        });
      else res.send(data);
    });
  };
};
```

Buat file domain/users/model.js

```javascript
module.exports = db => {
  const User = function(user) {
    this.email = user.email;
    this.name = user.name;
    this.password = user.password;
    this.age = user.age;
  };

  User.List = require('./repositories/list_user')(db);

  return User;
};
```

model merupakan entity dari User yang berisi seluruh atribut (field) dan method dari User. Dalam hal ini, user mempunyai atribut email, name, password dan age. Sementara method yang disediakan untuk endpoint ini adalah User.List.

Buat file domain/users/repositories/list\_user.js

```javascript
module.exports = db => {
  return result => {
    db.query("SELECT id, email, name, age FROM users", function (err, res) {
      if (err) {
        console.log("error: ", err);
        result(null, err);
        return;
      }

      console.log("users: ", res);
      result(null, res);
    });
  };
};
```

endpoint GET /users sudah bisa dicoba melalui postman

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MjhGi2kJXwPskfHC6jr%2F-Mji6SDOymuecOequW5J%2FScreen%20Shot%202021-09-16%20at%2017.17.32.png?alt=media\&token=d42e071f-d537-4701-addb-9d01650f6839)

### POST /users

Update file domain/users/route.js untuk menambahkan routing POST /users

```javascript
module.exports = (app, DB) => {
  const users = require("./service.js")(DB);

  app.get("/users", users.List);
  app.post("/users", users.Create);
};
```

Update file domain/users/service.js untuk menambahkan handling service POST /users

```javascript
module.exports = db => {
  const List = require("./services/list_user")(db);
  const Create = require("./services/create_user")(db);

  return { List, Create };
};
```

Update file domain/users/model.js untuk menambahkan method User.Create

```javascript
module.exports = db => {
  const User = function(user) {
    this.email = user.email;
    this.name = user.name;
    this.password = user.password;
    this.age = user.age;
  };

  User.List = require('./repositories/list_user')(db);
  User.Create = require('./repositories/create_user')(db);

  return User;
};
```

Buat file domain/users/services/create\_user.js

```javascript
const bcrypt = require('bcrypt');
const saltRounds = 10;

module.exports = db => {
  const User = require("../model.js")(db);
  return (req, res) => {
    if (!req.body) {
      res.status(400).send({
        message: "Content can not be empty!"
      });
      return 
    }
    
    const user = new User({
      email: req.body.email,
      password: bcrypt.hashSync(req.body.password, saltRounds),
      name: req.body.name,
      age: req.body.age
    });

    User.Create(user, (err, data) => {
      if (err)
        res.status(500).send({
          message:
            err.message || "Some error occurred while create user."
        });
      else res.status(201).send(data);
    });
  };
};
```

Kode di atas membutuhkan bscrypt untuk hasih password. Jangan lupa install bcrypt melalui perintah `npm install bcrypt`.&#x20;

Buat file domain/users/repositories/create\_user.js

```javascript
module.exports = db => {
  return (newUser, result) => {
    db.query("INSERT INTO users SET ?", newUser, function (err, res) {
      if (err) {
        console.log("error: ", err);
        result(null, err);
        return;
      }

      delete newUser.password;
      console.log("created user: ", { id: res.insertId, ...newUser });
      result(null, { id: res.insertId, ...newUser });
    });
  };
};
```

Endpoint POST /users sudah bisa dicoba melalui postman

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MjhGi2kJXwPskfHC6jr%2F-Mji8a1dvTHOgcGHHBj0%2FScreen%20Shot%202021-09-16%20at%2017.27.47.png?alt=media\&token=a58e1dda-5aea-4ac5-81ed-66f6cabe6664)

### GET /users/:id

Update file domain/users/route.js untuk menambahkan routing GET /users/:id

```javascript
module.exports = (app, DB) => {
  const users = require("./service.js")(DB);

  app.get("/users", users.List);
  app.post("/users", users.Create);
  app.get("/users/:id", users.View);
};
```

Update file domain/users/service.js untuk menambahkan handling service GET /users/:id

```javascript
module.exports = db => {
  const List = require("./services/list_user")(db);
  const Create = require("./services/create_user")(db);
  const View = require("./services/view_user")(db);

  return { List, Create, View };
};
```

Update file domain/users/model.js untuk menambahkan method User.View

```javascript
module.exports = db => {
  const User = function(user) {
    this.email = user.email;
    this.name = user.name;
    this.password = user.password;
    this.age = user.age;
  };

  User.List = require('./repositories/list_user')(db);
  User.Create = require('./repositories/create_user')(db);
  User.View = require('./repositories/view_user')(db);

  return User;
};
```

Buat file domain/users/services/view\_user.js

```javascript
module.exports = db => {
  const User = require("../model.js")(db);
  
  return (req, res) => {
    const id = req.params.id;
    if (!id) {
      res.status(400).send({
        message: "please suply valid id!"
      });
      return 
    }
    
    User.View(id, (err, data) => {
      if (err)
        res.status(500).send({
          message:
            err.message || "Some error occurred while retrieving user."
        });
      else res.send(data);
    });
  };
}
```

Buat file domain/users/repositories/view\_user.js

```javascript
module.exports = db => {
  return (id, result) => {
    db.query(`SELECT id, email, name, age FROM users WHERE id = ?`, id, (err, res) => {
      if (err) {
        console.log("error: ", err);
        result(err, null);
        return;
      }

      if (res.length) {
        console.log("found user: ", res[0]);
        result(null, res[0]);
        return;
      }

      // not found Customer with the id
      result({ kind: "not_found" }, null);
    });
  };
};
```

Endpoint GET /users/:id sidah bisa dites.

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MjhGi2kJXwPskfHC6jr%2F-Mji9wJepoKO0ucm1XaJ%2FScreen%20Shot%202021-09-16%20at%2017.33.34.png?alt=media\&token=3b4e53cc-a91c-4c32-812d-b1213b00e515)

### PUT /users\:/id

Update file domain/users/route.js untuk menambahkan routing PUT /users/:id

```javascript
module.exports = (app, DB) => {
  const users = require("./service.js")(DB);

  app.get("/users", users.List);
  app.post("/users", users.Create);
  app.get("/users/:id", users.View);
  app.put("/users/:id", users.Update);
};
```

Update file domain/users/service.js untuk menambahkan handling service PUT /users/:id

```javascript
module.exports = db => {
  const List = require("./services/list_user")(db);
  const Create = require("./services/create_user")(db);
  const View = require("./services/view_user")(db);
  const Update = require("./services/update_user")(db);

  return { List, Create, View, Update };
};
```

Update file domain/users/model.js untuk menambahkan method User.Update

```javascript
module.exports = db => {
  const User = function(user) {
    this.email = user.email;
    this.name = user.name;
    this.password = user.password;
    this.age = user.age;
  };

  User.List = require('./repositories/list_user')(db);
  User.Create = require('./repositories/create_user')(db);
  User.View = require('./repositories/view_user')(db);
  User.Update = require('./repositories/update_user')(db);

  return User;
};
```

Buat file domain/users/services/update\_user.js

```javascript
module.exports = db => {
  const User = require("../model.js")(db);
  
  return (req, res) => {
    if (!req.body) {
      res.status(400).send({
        message: "Content can not be empty!"
      });
      return 
    }

    const id = req.params.id;
    if (!id) {
      res.status(400).send({
        message: "please suply valid id!"
      });
    }
    
    const user = new User({
      name: req.body.name,
      age: req.body.age
    });

    User.Update(id, user, (err, data) => {
      if (err)
        res.status(500).send({
          message:
            err.message || "Some error occurred while update user."
        });
      else res.send(data);
    });
  };
};
```

Buat file domain/users/repositories/update\_user.js

```javascript
module.exports = db => {
  return (id, user, result) => {
    db.query("UPDATE users SET name = ?, age = ? WHERE id = ?", 
      [user.name, user.age, id], 
      function (err, res) {
      if (err) {
        console.log("error: ", err);
        result(null, err);
        return;
      }

      if (res.affectedRows == 0) {
        result({ kind: "not_found" }, null);
        return;
      }

      console.log("update user: ", { id: id, ...user });
      result(null, { id: id, ...user });
    });
  };
};
```

Endpoint PUT /users/:id sidah bisa dites.

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MjhGi2kJXwPskfHC6jr%2F-MjiAo7uG6IzcPPSEI1C%2FScreen%20Shot%202021-09-16%20at%2017.37.35.png?alt=media\&token=9061bcf7-aa4b-4a85-b1ad-d397ba66bb57)

### DELETE /users/:id

Update file domain/users/route.js untuk menambahkan routing DELETE /users/:id

```javascript
module.exports = (app, DB) => {
  const users = require("./service.js")(DB);

  app.get("/users", users.List);
  app.post("/users", users.Create);
  app.get("/users/:id", users.View);
  app.put("/users/:id", users.Update);
  app.delete("/users/:id", users.Delete);
};
```

Update file domain/users/service.js untuk menambahkan handling service DELETE /users/:id

```javascript
module.exports = db => {
  const List = require("./services/list_user")(db);
  const Create = require("./services/create_user")(db);
  const View = require("./services/view_user")(db);
  const Update = require("./services/update_user")(db);
  const Delete = require("./services/delete_user")(db);

  return { List, Create, View, Update, Delete };
};
```

Update file domain/users/model.js untuk menambahkan method User.Delete

```javascript
module.exports = db => {
  const User = function(user) {
    this.email = user.email;
    this.name = user.name;
    this.password = user.password;
    this.age = user.age;
  };

  User.List = require('./repositories/list_user')(db);
  User.Create = require('./repositories/create_user')(db);
  User.View = require('./repositories/view_user')(db);
  User.Update = require('./repositories/update_user')(db);
  User.Delete = require('./repositories/delete_user')(db);

  return User;
};
```

Buat file domain/users/services/delete\_user.js

```javascript
module.exports = db => {
  const User = require("../model.js")(db);
  
  return (req, res) => {
    const id = req.params.id;
    if (!id) {
      res.status(400).send({
        message: "please suply valid id!"
      });
      return 
    }
    
    User.Delete(id, (err, data) => {
      if (err)
        res.status(500).send({
          message:
            err.message || "Some error occurred while delete user."
        });
      else res.sendStatus(204);
    });
  };
};
```

Buat file domain/users/repositories/delete\_user.js

```javascript
module.exports = db => {
  return (id, result) => {
    db.query("DELETE FROM users WHERE id = ?", id, (err, res) => {
      if (err) {
        console.log("error: ", err);
        result(null, err);
        return;
      }

      if (res.affectedRows == 0) {
        // not found Customer with the id
        result({ kind: "not_found" }, null);
        return;
      }

      console.log("deleted user with id: ", id);
      result(null, res);
    });
  };
};
```

Endpoint DELETE /users/:id sidah bisa dites.

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MjhGi2kJXwPskfHC6jr%2F-MjiBRy6Z3i9Asw2OdVc%2FScreen%20Shot%202021-09-16%20at%2017.40.20.png?alt=media\&token=b525cbbe-dac2-4a9f-985a-ee9a3a4ba4f2)

### Login

Update file domain/users/route.js untuk menambahkan routing POST /login

```javascript
module.exports = (app, DB) => {
  const users = require("./service.js")(DB);

  app.get("/users", users.List);
  app.post("/users", users.Create);
  app.get("/users/:id", users.View);
  app.put("/users/:id", users.Update);
  app.delete("/users/:id", users.Delete);
  app.post("/login", users.Login);
};
```

Update file domain/users/service.js untuk menambahkan handling service login

```javascript
module.exports = db => {
  const List = require("./services/list_user")(db);
  const Create = require("./services/create_user")(db);
  const View = require("./services/view_user")(db);
  const Update = require("./services/update_user")(db);
  const Delete = require("./services/delete_user")(db);
  const Login = require("./services/login")(db);

  return { List, Create, View, Update, Delete, Login };
};
```

Update file domain/users/model.js untuk menambahkan method User.Login

```javascript
module.exports = db => {
  const User = function(user) {
    this.email = user.email;
    this.name = user.name;
    this.password = user.password;
    this.age = user.age;
  };

  User.List = require('./repositories/list_user')(db);
  User.Create = require('./repositories/create_user')(db);
  User.View = require('./repositories/view_user')(db);
  User.Update = require('./repositories/update_user')(db);
  User.Delete = require('./repositories/delete_user')(db);
  User.Login = require('./repositories/login')(db);

  return User;
};
```

Buat file domain/users/services/login.js

```javascript
const bcrypt = require('bcrypt');

module.exports = db => {
  const User = require("../model.js")(db);

  return (req, res) => {
    if (!req.body || !req.body.email || !req.body.password) {
      res.status(400).send({
        message: "invalid email/password!"
      });
      return
    }
    const email = req.body.email;
    const password = req.body.password;
    User.Login(email, (err, data) => {
      if (err) {
        res.status(500).send({
          message:
            err.message || "Some error occurred while login user."
        });
        return 
      }

      if (!bcrypt.compareSync(password, data.password)) {
        res.status(400).send({
          message:
            err.message || "invalid email/password"
        });
        return 
      }
      res.send({token: "alabama-token"});
    });
  };
};
```

Buat file domain/users/repositories/login.js

```javascript
module.exports = db => {
  return (email, result) => {
    db.query(`SELECT password FROM users WHERE email = ?`, email, (err, res) => {
      if (err) {
        console.log("error: ", err);
        result(err, null);
        return;
      }

      if (res.length) {
        result(null, res[0]);
        return;
      }

      // not found Customer with the id
      result({ kind: "not_found" }, null);
    });
  };
};
```

Endpoint POST /login sudah bisa dites.

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MjhGi2kJXwPskfHC6jr%2F-MjiKXedcVkvqPLEMdYY%2FScreen%20Shot%202021-09-16%20at%2018.18.13.png?alt=media\&token=e6391007-bd40-43be-befc-a9a6ded4f886)


# JWT Token

Pada materi sebelumnya, kita telah membuat token yang isinya dihardcode berisi string biasa. Saat ini praktek yang umum adalah dengan menggunakan JWT Token.


# Pengenalan Svelte

Svelte adalah framework javascript yang modern, cepat dan handal. Keunggulan menggunakan framework utamanya adalah standarisasi kode dan reusable komponen.

### Mengapa Svelte

* Write less code
* No virtual DOM
* Truly reactive

### Installasi

Untuk instalasi dan membuat project, lakukan langkah-langkah berikut: &#x20;

* npx degit sveltejs/template nama-project
* npm install
* npm run dev

Sekarang aplikasi sudah bisa dibuka melalui [http://localhost:5000](http://localhost:5000/)

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-Mjbpc8ADzJ8ElTt3kBN%2F-MjbqLGCoB1Exak2BsII%2FScreen%20Shot%202021-09-15%20at%2011.59.32.png?alt=media\&token=1b4cc0b1-5b42-4713-81c5-3436d3ccd722)

### Struktur Halaman

Struktur halaman svelte sangat sederhana mirip seklai dengan HTML biasa. Terdiri dari tag \<script> untuk mengelola kode-kode javascript, tag-tag html biasa, dan dilengkapi dengan tag \<style> untuk css.

```markup
<script>
	export let name;
</script>

<main>
	<h1>Hello {name}!</h1>
	<p>Visit the <a href="https://svelte.dev/tutorial">Svelte tutorial</a> to learn how to build Svelte apps.</p>
</main>

<style>
	main {
		text-align: center;
		padding: 1em;
		max-width: 240px;
		margin: 0 auto;
	}

	h1 {
		color: #ff3e00;
		text-transform: uppercase;
		font-size: 4em;
		font-weight: 100;
	}

	@media (min-width: 640px) {
		main {
			max-width: none;
		}
	}
</style>
```

### Prop

prop adalah variabel yang diexport dari external. variabel ini bisa dilempar dari parent saat memanggil komponen, maupun dari url. Pada contoih kode di atas, name adalah sebuah prop, yang ditandai dari kata kunci : export.

Jika kita buka file src/main.js

```javascript
import App from './App.svelte';

const app = new App({
	target: document.body,
	props: {
		name: 'world'
	}
});

export default app;
```

Tampak bahwa ketika memanggil komponen App.Svelte, melempar sebuah props dengan nama "*name*" dan value "*world*".

### State

state adalah suatu variabel yang dibuat di internal dan value-nya bisa berubah-ubah tergangung pada operasi yang berhubungan dengan variabel tersebut. Untuk membuat state cukup dengan membuat variabel seperti biasa dengan kata kunci let maupun const.

Pada contoh kode berikut, selamat adalah sebuah state, yang isinya berubah-ubah tergantung jam. Jika PM akan berisi "*malam*" dan sebaliknya akan berisi "*pagi*".&#x20;

```javascript
<script>
	export let name

	let selamat = "pagi"
	
	if (new Date().toLocaleString("en-US", { hour: 'numeric', hour12: true }).split(" ")[1] === "PM") {
    selamat = "malam"
  } 
</script>

<main>
	<h1>Selamat {selamat} {name}!</h1>
	<p>Visit the <a href="https://svelte.dev/tutorial">Svelte tutorial</a> to learn how to build Svelte apps.</p>
</main>

<style>
	main {
		text-align: center;
		padding: 1em;
		max-width: 240px;
		margin: 0 auto;
	}

	h1 {
		color: #ff3e00;
		text-transform: uppercase;
		font-size: 4em;
		font-weight: 100;
	}

	@media (min-width: 640px) {
		main {
			max-width: none;
		}
	}
</style>
```


# Routing

### Routing

Kita akan mengimplementasikan routing di svelte dengan memanfaatkan library svelte-routing&#x20;

Ubah file src/main.js

```javascript
import App from './App.svelte';

const app = new App({
	target: document.body
});

export default app;
```

Buat file src/helper/path.js agart mudah mengelola path aplikasi.

```javascript
export const PATH_URL = {
  BASE: "/",
  ABOUT: "/tentang-kami"
}
```

Buat file src/routes/About.svelte

```markup
<h1>Tentang Kami</h1>
```

Buat file src/routes/Home.svelte

```markup
<h1>Home</h1>
```

Ubah file src/App.svelte

```markup
<script>
	import { Router, Route } from 'svelte-routing'
	import About from "./routes/About.svelte"
	import Home from "./routes/Home.svelte"
	import { PATH_URL } from "./helper/path"
</script>

<Router>
	<Route path={PATH_URL.BASE} component={Home}/>
	<Route path={PATH_URL.ABOUT} component={About}/>
</Router>
```

Script di atas mengimport svelte-routing, maka kita perlu install library ini dengan menjalankan `npm install svelte-routing`

Ubah file package.json -> scripts -> start dengan menambahkan --single

```markup
{
  "name": "svelte-app",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "build": "rollup -c",
    "dev": "rollup -c -w",
    "start": "sirv public --no-clear --single"
  },
  "devDependencies": {
    "@rollup/plugin-commonjs": "^17.0.0",
    "@rollup/plugin-node-resolve": "^11.0.0",
    "rollup": "^2.3.4",
    "rollup-plugin-css-only": "^3.1.0",
    "rollup-plugin-livereload": "^2.0.0",
    "rollup-plugin-svelte": "^7.0.0",
    "rollup-plugin-terser": "^7.0.0",
    "svelte": "^3.0.0"
  },
  "dependencies": {
    "sirv-cli": "^1.0.0",
    "svelte-routing": "^1.6.0"
  }
}

```

Kemudian jalankan ulang `npm run dev`

Sekarang kita sudah punya routing, yaitu /  yang mengharah ke fiule src/routes/Home.svelte dan /tentang-kami yang mengarah ke fiel src/routes/About.svelte

### Gambar

Ada kalanya kita perlu menampilkan gambar sebagai informasi maupun sebagai pemanis halaman. Kita akan mempraktekkan penggunaan gambar (maupun asset lainnya) di svelte. Pertama buat folder images di folder public. dan copy-kan gambar yang hendak digunakan ke folder tersebut. Untuk keperluan ini,  saya telah  menyimpan gambar di public/image/erp.png.

&#x20;Untuk memudahkan mengelola path gambar, kita akan membuat file helper, src/helper/images.js

```javascript
export const Images = {
  img_erp: './images/erp.png'
}
```

Sekarang kita ubah file src/routes/Home.svelte&#x20;

```javascript
<script>
  import { Images } from "../helper/images";
</script>

<div id="container">
  <h1>Home</h1>
  <img src={Images.img_erp} alt="Gambar ERP">
</div>

<style>
  #container {
    width:100%;
  }

  img {
    width:50%;
  }
</style>
```


# Protected Routing

Sering kali kita memerlukan halaman yang diproteksi. Hanya user yang sudah login yang bisa masuk ke halaman tersebut.

Buat Halaman src/routes/AccessDenied.svelte

```markup
<script>
  import { Link } from "svelte-routing"
  import { PATH_URL } from "../helper/path"
</script>

<h1>No access 🤕</h1>
<h2>
  Go back to <Link to={PATH_URL.BASE}>Home page</Link>
</h2>
```

Buat file src/stores/token.js

```javascript
import { writable } from 'svelte/store';

export const token = writable(localStorage.getItem('token'));
```

Buat file src/ProtectedRoute.svelte

```javascript
<script>
  import { Route } from "svelte-routing"
  import AccessDenied from "./routes/AccessDenied.svelte"
  import { token } from "./stores/token.js"

  export let path
  export let component
  $: isAuthenticated = $token;
</script>

{#if isAuthenticated}
  <Route path={path} component={component} />
{:else}
  <Route path={path} component={AccessDenied} />
{/if}
```

Buat file src/routes/UserList.svelte

```javascript
<h1>List User</h1>
```

Ubah file src/App.svelte

```javascript
<script>
	import { Router, Route } from "svelte-routing"
	import About from "./routes/About.svelte"
	import Home from "./routes/Home.svelte"
	import { PATH_URL } from "./helper/path"
	import UserList from "./routes/UserList.svelte"
	import ProtectedRoute from "./ProtectedRoute.svelte"
</script>

<Router>
	<Route path={PATH_URL.BASE} component={Home}/>
	<Route path={PATH_URL.ABOUT} component={About}/>
	<ProtectedRoute path={PATH_URL.USER_LIST} component={UserList} />
</Router>
```

Buat file src/components/Navigation.svelte

```javascript
<script>
  import { Link, navigate } from "svelte-routing"
  import { token } from "../stores/token"
  import { PATH_URL } from "../helper/path"

  let isToken = false

  if (localStorage.getItem("token")) {
    isToken = true
  }


  $: isAuthenticated = $token;

  const login = () => {
    localStorage.setItem("token", "sudah-login")
    token.set(localStorage.getItem("token"))
    isToken = true
    navigate(PATH_URL.USER_LIST, { replace: true })
  }

  function logout () {
    localStorage.removeItem("token")
    token.set(token, localStorage.getItem("token"))
    isToken = false
    navigate(PATH_URL.BASE, { replace: true })
  }

</script>

<div>
  {#if isToken}
  <ul>
    <li><Link to={PATH_URL.USER_LIST}>List User</Link></li>
  </ul>
  <button on:click="{logout}">Logout</button>
  {:else}
  <ul>
    <li><Link to={PATH_URL.BASE}>Home</Link></li>
    <li><Link to={PATH_URL.ABOUT}>Tentang Kami</Link></li>
  </ul>
  <button on:click="{login}">Login</button>
  {/if}

</div>

```

Update file-file routes untuk menambahkan Navigation

{% code title="src/routes/About.svelte" %}

```javascript
<script>
  import Navigation from "../components/Navigation.svelte"
</script>
<Navigation/>
<h1>Tentang Kami</h1>
```

{% endcode %}

{% code title="src/routes/Home.svelte" %}

```javascript
<script>
  import { Images } from "../helper/images"
  import Navigation from "../components/Navigation.svelte"
</script>
<Navigation/>

<div id="container">
  <h1>Home</h1>
  <img src={Images.img_erp} alt="Gambar ERP"/>
 </div>

<style>
  #container {
    width:100%;
  }

  img {
    width:50%;
  }
</style>
```

{% endcode %}

{% code title="src/routes/UserList.svelte" %}

```javascript
<script>
  import Navigation from "../components/Navigation.svelte"
</script>
<Navigation/>

<h1>List User</h1>
```

{% endcode %}


# Login

Saat ini login masih dihardcode di component Navigation, seharusnya halaman login diakses melalui form login. Sebagai contoh, kita akan membuat form login di halaman home. Selain form login kita juga akan membutuhkan toast notification, dan fetch api.

### Toast

buat file src/helper/toast.js

```javascript
import { writable, derived } from "svelte/store"

const TIMEOUT = 2000

function createNotificationStore (timeout) {
    const _notifications = writable([])

    function send (message, type = "default", timeout) {
        _notifications.update(state => {
            return [...state, { id: id(), type, message, timeout }]
        })
    }

    let timers = []

    const notifications = derived(_notifications, ($_notifications, set) => {
        set($_notifications)
        if ($_notifications.length > 0) {
            const timer = setTimeout(() => {
                _notifications.update(state => {
                    state.shift()
                    return state
                })
            }, $_notifications[0].timeout)
            return () => {
                clearTimeout(timer)
            }
        }
    })
    const { subscribe } = notifications

    return {
        subscribe,
        send,
		    default: (msg, timeout = TIMEOUT) => send(msg, "default", timeout),
        danger: (msg, timeout = TIMEOUT) => send(msg, "danger", timeout),
        warning: (msg, timeout = TIMEOUT) => send(msg, "warning", timeout),
        info: (msg, timeout = TIMEOUT) => send(msg, "info", timeout),
        success: (msg, timeout = TIMEOUT) => send(msg, "success", timeout),
    }
}

function id() {
    return '_' + Math.random().toString(36).substr(2, 9);
};

export const notifications = createNotificationStore()
```

Buat file src/components/Toast.svelte

```javascript
<script>
  import { flip } from "svelte/animate";
  import { fly } from "svelte/transition";
  import { notifications } from "../helper/toast.js";

  export let themes = {
      danger: "#E26D69",
      success: "#84C991",
      warning: "#f0ad4e",
      info: "#5bc0de",
      default: "#aaaaaa",
  };
</script>

<div class="notifications">
  {#each $notifications as notification (notification.id)}
      <div
          animate:flip
          class="toast"
          style="background: {themes[notification.type]};"
          transition:fly={{ y: 30 }}
      >
          <div class="content">{notification.message}</div>
          {#if notification.icon}<i class={notification.icon} />{/if}
      </div>
  {/each}
</div>

<style>
  .notifications {
    position: fixed;
    top: 10px;
    left: 0;
    right: 0;
    margin: 0 auto;
    padding: 0;
    z-index: 9999;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    align-items: center;
    pointer-events: none;
  }

  .toast {
    flex: 0 0 auto;
    margin-bottom: 10px;
    border-radius: 4px;
  }

  .content {
    padding: 16px 40px;
    display: block;
    color: white;
    font-weight: 500;
  }
</style>

```

Pasang component Toast di file src/App.svelte

```javascript
<script>
	import { Router, Route } from "svelte-routing"
	import About from "./routes/About.svelte"
	import Home from "./routes/Home.svelte"
	import { PATH_URL } from "./helper/path"
	import UserList from "./routes/UserList.svelte"
	import ProtectedRoute from "./ProtectedRoute.svelte"
	import Toast from "./components/Toast.svelte"
</script>

<Router>
	<Route path={PATH_URL.BASE} component={Home}/>
	<Route path={PATH_URL.ABOUT} component={About}/>
	<ProtectedRoute path={PATH_URL.USER_LIST} component={UserList} />
</Router>
<Toast/>
```

### Form Login

Buat komponen Input pada file src/components/Input.svelte

```javascript
<script>
  export let label
  export let value
</script>

<div>
  <label for={label}>{label}</label>
  <input bind:value id={label} name={label} {...$$restProps} />
</div>

```

Buat komponen Button pada file src/components/Button.svelte

```javascript
<script>
  import Loader from './Loader.svelte';
  export let bgColor = "#00FF00AA"
  export let bgHoverColor = "#00FF0088"
  export let size = "medium";
  export let className = "";
  export let isLoading = false;

  const getPaddingSize = (size) => {
    switch (size) {
      case "small":
        return "py-1 px-4"
      default:
        return "py-2 px-8"
    }
  }

  const getTextSize = (size) => {
    switch (size) {
      case "small":
        return "text-sm"
      default:
        return "text-lg"
    }
  }

  const getLoaderSize = (size) => {
    switch (size) {
      case "small":
        return "20"
      default:
        return "40"
    }
  }
  let padding = getPaddingSize(size);
  let text = getTextSize(size);
  let loaderSize = getLoaderSize(size);
  
</script>

<button
  disabled={isLoading}
  on:click
  class={`flex align-center justify-center text-white ${bgColor} border-0 ${padding} focus:outline-none hover:${bgHoverColor} rounded ${text} ${className}`}>
  {#if isLoading}
    <div class="relative">
      <div class="invisible"><slot /></div>
      <div class="loader-container">
        <Loader size={loaderSize}/>
      </div>
    </div>
  {:else}
    <slot />
  {/if}
</button>

<style>
  .loader-container {
    display: flex;
    justify-content: center;
    position: absolute;
    left: 0px;
    right: 0px;
    top: 0px;
    bottom: 0px;
    margin: auto;
    height: fit-content;
  }
</style>
```

Pada button dibuat suatu loader, ide-nya ketika button diklik, maka akan muncul loader selama sekian detik (sekitar 1,5 detik). Untuk buat file src/components/Loader/svelte

```javascript
<script>
  export const durationUnitRegex = /[a-zA-Z]/;
  export const range = (size, startAt = 0) =>
  [...Array(size).keys()].map(i => i + startAt);
  export let color = "#ffffff";
  export let unit = "px";
  export let duration = "1.5s";
  export let size = "60";
  let durationUnit = duration.match(durationUnitRegex)[0];
  let durationNum = duration.replace(durationUnitRegex, "");
</script>

<style>
  .wrapper {
    position: relative;
    display: flex;
    justify-content: center;
    align-items: center;
    width: var(--size);
    height: calc(var(--size) / 2.5);
    margin-top: calc(var(--size) / 5);
  }
  .circle {
    position: absolute;
    top: 0px;
    width: calc(var(--size) / 5);
    height: calc(var(--size) / 5);
    border-radius: 999px;
    background-color: var(--color);
    animation: motion var(--duration) cubic-bezier(0.895, 0.03, 0.685, 0.22)
      infinite;
  }
  @keyframes motion {
    0% {
      opacity: 1;
    }
    50% {
      opacity: 0;
    }
    100% {
      opacity: 1;
    }
  }
</style>

<div
  class="wrapper"
  style="--size: {size}{unit}; --color: {color}; --duration: {duration}">
  {#each range(3, 0) as version}
    <div
      class="circle"
      style="animation-delay: {version * (+durationNum / 10)}{durationUnit}; left: {version * (+size / 3 + +size / 15) + unit};" />
  {/each}
</div>

```

Update halaman src/routes/Home.svelte untuk menambahkan form login

```javascript
<script>
  import { Images } from "../helper/images"
  import Button from "../components/Button.svelte"
  import Input from "../components/Input.svelte"
  import { notifications } from '../helper/toast'
  import { PATH_URL } from "../helper/path"
  import { token } from "../stores/token"
  import { navigate } from "svelte-routing"

  const state = {
    username: "",
    password: ""
  }
  
  let isLoading = false;
  let isToken = false;

  if (localStorage.getItem("token")) {
    isToken = true
  }

  const handleInput = (e) => {
    const { value, name } = e.target
    state[name] = value
  }

  const loginCall = async (username, password) => {
    
    if (username === "rijal.asep.nugroho@gmail.com" && password === "1234") {
      return {
        Token: "sudah-login"
      }
    }

    return {}
  }

  const login = async () => {
    try {
      isLoading = true
      const user = await loginCall(state.username, state.password)
      
      if (!user.Token) {
        throw({message: "please suplay valid username and password"})
      }
      
      localStorage.setItem("token", user.Token)
      token.set(localStorage.getItem('token'));
      isLoading = false;
      isToken = true

      navigate(PATH_URL.USER_LIST, { replace: false })
    } catch(e) {
      isLoading = false;
      notifications.danger(e.message)
    }
  };

  let widthDiv = 50;
  if (isToken) {
    widthDiv = 100;
  }
 
</script>

<div id="container" style="background-image:url({Images.img_erp});">
  <div id="welcome-div" style="flex:{widthDiv}%;">
    <h1>Selamat datang di svelte skeleton</h1>
    <a href="{PATH_URL.ABOUT}">About Us</a>
  </div>
  {#if !isToken}
  <div id="loginDiv" style="flex: {widthDiv}%;">
    <form on:submit|preventDefault={login}>
      <Input label="Username" name="username" on:input={handleInput} bind:value={state.username} placeholder="username" type="text" required/>
      <Input label="Password" name="password" on:input={handleInput} bind:value={state.password} placeholder="password" type="password" required/>
      <Button isLoading={isLoading}>Login</Button>
    </form>
  </div>
  {/if}
 </div>

<style>
  #container {
    width:100vw;
    height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
  }

  #welcome-div, #loginDiv {
    display: flex;
    justify-content: center;
    align-items: center;
    flex-flow: wrap column;
  }

  a {
    color: wheat;
  }
</style>
```

Karena fungsi login sdh diambil alih di halaman Home, maka komponen Navigation kita update untuk menghapus kode tentang login.

```javascript
<script>
  import { Link, navigate } from "svelte-routing"
  import { token } from "../stores/token"
  import { PATH_URL } from "../helper/path"
  
  let isToken = false

  if (localStorage.getItem("token")) {
    isToken = true
  }


  function logout () {
    localStorage.removeItem("token")
    token.set(token, localStorage.getItem("token"))
    isToken = false
    navigate(PATH_URL.BASE, { replace: true })
  }

</script>

<div>
  {#if isToken}
  <ul>
    <li><Link to={PATH_URL.USER_LIST}>List User</Link></li>
  </ul>
  <button on:click="{logout}">Logout</button>
  {:else}
  <ul>
    <li><Link to={PATH_URL.BASE}>Home</Link></li>
    <li><Link to={PATH_URL.ABOUT}>Tentang Kami</Link></li>
  </ul>
  <Link to="{PATH_URL.BASE}">Login</Link>
  {/if}

</div>

```

### Call API

Saat ini, fungsi loginCall() pada halaman Home masih dihardcode. Pada aplikasi sesungguhnya fungsi ini memanggil api dari backend melalui Ajax.

Ubah file src/routes/Home.svelte&#x20;

```javascript
<script>
  import { Images } from "../helper/images"
  import Button from "../components/Button.svelte"
  import Input from "../components/Input.svelte"
  import { notifications } from '../helper/toast'
  import { PATH_URL } from "../helper/path"
  import { token } from "../stores/token"
  import { navigate } from "svelte-routing"

  const state = {
    username: "",
    password: ""
  }

  const user = {token: ""}
  
  let isLoading = false;
  let isToken = false;

  if (localStorage.getItem("token")) {
    isToken = true
  }

  const handleInput = (e) => {
    const { value, name } = e.target
    state[name] = value
  }

  function reqListener() {
    user.token = JSON.parse(this.responseText).token;
  }

  const loginCall = async (username, password) => {
    const url = "http://localhost:3000/login";
    const data = {
      email:username, 
      password:password
    }

    var xmlHttp = new XMLHttpRequest();
    xmlHttp.addEventListener("load", reqListener);
    xmlHttp.open("POST", url, false); // false for synchronous request
    xmlHttp.setRequestHeader("Content-type", "application/json");
    xmlHttp.send(JSON.stringify(data));
    
  }

  const login = async () => {
    try {
      isLoading = true
      await loginCall(state.username, state.password)
      
      if (!user.token) {
        throw({message: "please suplay valid username and password"})
      }
      
      localStorage.setItem("token", user.Token)
      token.set(localStorage.getItem('token'));
      isLoading = false;
      isToken = true

      navigate(PATH_URL.USER_LIST, { replace: false })
    } catch(e) {
      isLoading = false;
      notifications.danger(e.message)
    }
  };

  let widthDiv = 50;
  if (isToken) {
    widthDiv = 100;
  }
 
</script>

<div id="container" style="background-image:url({Images.img_erp});">
  <div id="welcome-div" style="flex:{widthDiv}%;">
    <h1>Selamat datang di svelte skeleton</h1>
    <a href="{PATH_URL.ABOUT}">About Us</a>
  </div>
  {#if !isToken}
  <div id="loginDiv" style="flex: {widthDiv}%;">
    <form on:submit|preventDefault={login}>
      <Input label="Username" name="username" on:input={handleInput} bind:value={state.username} placeholder="username" type="text" required/>
      <Input label="Password" name="password" on:input={handleInput} bind:value={state.password} placeholder="password" type="password" required/>
      <Button isLoading={isLoading}>Login</Button>
    </form>
  </div>
  {/if}
 </div>

<style>
  #container {
    width:100vw;
    height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
  }

  #welcome-div, #loginDiv {
    display: flex;
    justify-content: center;
    align-items: center;
    flex-flow: wrap column;
  }

  a {
    color: wheat;
  }
</style>
```


# Halaman List

Dengan semakin seringnya kita menggunakan url, ada baiknya untuk menyimpan url dalam sebuah env.

Buat file src/env.js

```javascript
export const HOST_URL = 'http://localhost:3000';
export const APP_ENV = 'development';
```

Ubah file src/routes/UserList.svelte

```javascript
<script>
  import { onMount } from "svelte"
  import { Link } from "svelte-routing"
  import Navigation from "../components/Navigation.svelte"
  import { HOST_URL } from '../env'
  import { PATH_URL } from "../helper/path";
  import { notifications } from '../helper/toast'

  let isLoadingTable = false
  let users = []
 
  function reqListener () {
    users = JSON.parse(this.responseText)
  }

  const fetchData = async() => {
    var oReq = new XMLHttpRequest()
    oReq.addEventListener("load", reqListener)
    oReq.open("GET", HOST_URL+ "/users")
    oReq.send()
  };

  onMount(async () => {
		try {
			isLoadingTable = true
			await fetchData()
			isLoadingTable = false
    } catch(e) {
			isLoading = false;
      notifications.danger(e.message)
    }
	})

  const onEdit = (event) => {
    let id = event.target.dataset.id
    console.log("edit", id)
  }

  const onView = (event) => {
    let id = event.target.dataset.id
    console.log("view", id)
  }

  const onDelete = (event) => {
    let id = event.target.dataset.id
    if (confirm("Yakin hendak menghapus?#"+id)) {
      console.log("delete", id)
    }
  }
</script>
<Navigation/>

<h1>List User</h1>

<Link to={PATH_URL.USER_CREATE}>Tambah User</Link>
<table>
  <tr>
    <th>ID</th>
    <th>Email</th>
    <th>Nama</th>
    <th>Umur</th>
    <th></th>
  </tr>

  {#each users as user}
  <tr>
    <td>{user.id}</td>
    <td>{user.email}</td>
    <td>{user.name}</td>
    <td>{user.age}</td>
    <td><button data-id="{user.id}" on:click="{onEdit}">Edit</button> <button data-id="{user.id}" on:click="{onView}">View</button> <button data-id="{user.id}" on:click="{onDelete}">Delete</button></td>
  </tr>
  {/each}
</table>
```


# Halaman Form

Update file src/helper/path.js&#x20;

```javascript
export const PATH_URL = {
  BASE: "/",
  ABOUT: "/tentang-kami",
  USER_LIST: "/admin/users",
  USER_CREATE: "/admin/users/add"
}
```

Buat file src/routes/UserAdd.svelte

```javascript
<script>
  import Navigation from "../components/Navigation.svelte"
  import Input from "../components/Input.svelte"
  import Button from "../components/Button.svelte" 
  import { notifications } from '../helper/toast'
  import { PATH_URL } from "../helper/path"
  import { navigate } from "svelte-routing"
  import { HOST_URL } from '../env'

  const state = {
    email: "",
    password: "",
    name: "",
    age: "" 
  }
  let isLoading = false

  const handleInput = (e) => {
    const { value, name } = e.target
    state[name] = value
  }

  const createUser = async () => {
    const url = HOST_URL + "/users"
    var xmlHttp = new XMLHttpRequest()
    xmlHttp.open("POST", url, true)
    xmlHttp.setRequestHeader("Content-type", "application/json")
    xmlHttp.send(JSON.stringify(state))
    
  }

  const onCreate = async () => {
    try {
      isLoading = true
      await createUser()
      isLoading = false

      navigate(PATH_URL.USER_LIST, { replace: true })
    } catch(e) {
      isLoading = false;
      notifications.danger(e.message)
    }
  };


</script>
<Navigation/>

<h1>Tambah User</h1>
<main>
  <form on:submit|preventDefault={onCreate}>
    <Input label="Email" name="email" on:input={handleInput} bind:value={state.email} placeholder="username" type="email" required/>
    <Input label="Password" name="password" on:input={handleInput} bind:value={state.password} placeholder="password" type="password" required/>
    <Input label="Name" name="name" on:input={handleInput} bind:value={state.name} placeholder="name" type="text" required/>
    <Input label="Age" name="age" on:input={handleInput} bind:value={state.age} placeholder="age" type="number" required/>
    <Button isLoading={isLoading}>Login</Button>
  </form>
</main>
```

Update file src/App.svelte

```javascript
<script>
	import { Router, Route } from "svelte-routing"
	import About from "./routes/About.svelte"
	import Home from "./routes/Home.svelte"
	import { PATH_URL } from "./helper/path"
	import UserList from "./routes/UserList.svelte"
	import ProtectedRoute from "./ProtectedRoute.svelte"
	import Toast from "./components/Toast.svelte"
	import UserAdd from "./routes/UserAdd.svelte"
</script>

<Router>
	<Route path={PATH_URL.BASE} component={Home}/>
	<Route path={PATH_URL.ABOUT} component={About}/>
	<ProtectedRoute path={PATH_URL.USER_LIST} component={UserList} />
	<ProtectedRoute path={PATH_URL.USER_CREATE} component={UserAdd} />
</Router>
<Toast/>
```


# Halaman View

Update file src/helper/path.js

```javascript
export const PATH_URL = {
  BASE: "/",
  ABOUT: "/tentang-kami",
  USER_LIST: "/admin/users",
  USER_CREATE: "/admin/users/add",
  USER_VIEW: "/admin/users/:id"
}
```

Buat file src/routes/UserView\.svelte

```javascript
<script>
  import { onMount } from "svelte"
  import Navigation from "../components/Navigation.svelte"
  import { HOST_URL } from "../env"
  import { notifications } from "../helper/toast"
  import Input from "../components/Input.svelte"
  
  export let id

  let isLoading = false
  let user = {}
 
  function reqListener () {
    user = JSON.parse(this.responseText)
  }

  const fetchData = async() => {
    var oReq = new XMLHttpRequest()
    oReq.addEventListener("load", reqListener)
    oReq.open("GET", HOST_URL+ "/users/"+id)
    oReq.send()
  };

  onMount(async () => {
		try {
			isLoading = true
			await fetchData()
			isLoading = false
    } catch(e) {
			isLoading = false;
      notifications.danger(e.message)
    }
	})
  
</script>

<Navigation />
<main>
  <h1>View User</h1>
  <Input label="Email" name="email" value={user.email} disabled />
  <Input label="Name" name="name" value={user.name} disabled />
  <Input label="Age" name="age" value={user.age} disabled />
</main>
```

Update file src/App.svelte

```javascript
<script>
	import { Router, Route } from "svelte-routing"
	import About from "./routes/About.svelte"
	import Home from "./routes/Home.svelte"
	import { PATH_URL } from "./helper/path"
	import UserList from "./routes/UserList.svelte"
	import ProtectedRoute from "./ProtectedRoute.svelte"
	import Toast from "./components/Toast.svelte"
	import UserAdd from "./routes/UserAdd.svelte"
	import UserView from "./routes/UserView.svelte"
</script>

<Router>
	<Route path={PATH_URL.BASE} component={Home}/>
	<Route path={PATH_URL.ABOUT} component={About}/>
	<ProtectedRoute path={PATH_URL.USER_LIST} component={UserList} />
	<ProtectedRoute path={PATH_URL.USER_CREATE} component={UserAdd} />
	<ProtectedRoute path={PATH_URL.USER_VIEW} component={UserView} let:params>
		<UserView id="{params.id}"/>
	</ProtectedRoute>
</Router>
<Toast/>
```

Pada file src/routes/UserList.svelte ubah fungsi onView

```javascript
  const onView = (event) => {
    let id = event.target.dataset.id
    navigate("/admin/users/"+id, { replace: true })
  }
```


# Delete Action

Untuk menghandle penghapusan data, cukup dengan mengupdate fungsi onDelete pada file src/routes/UserList.svelte

```javascript
<script>
  import { onMount } from "svelte"
  import { Link } from "svelte-routing"
  import Navigation from "../components/Navigation.svelte"
  import { HOST_URL } from '../env'
  import { PATH_URL } from "../helper/path"
  import { notifications } from '../helper/toast'
  import { navigate } from "svelte-routing"

  let isLoadingTable = false
  let users = []
 
  function reqListener () {
    users = JSON.parse(this.responseText)
  }

  const fetchData = async() => {
    var oReq = new XMLHttpRequest()
    oReq.addEventListener("load", reqListener)
    oReq.open("GET", HOST_URL+ "/users")
    oReq.send()
  };

  onMount(async () => {
		try {
			isLoadingTable = true
			await fetchData()
			isLoadingTable = false
    } catch(e) {
			isLoading = false;
      notifications.danger(e.message)
    }
	})

  const onEdit = (event) => {
    let id = event.target.dataset.id
    console.log("edit", id)
  }

  const onView = (event) => {
    let id = event.target.dataset.id
    navigate("/admin/users/"+id, { replace: true })
  }

  const deleteUser = async(id) => {
    var oReq = new XMLHttpRequest()
    oReq.open("DELETE", HOST_URL+ "/users/"+id)
    oReq.send()
  };

  const onDelete = async (event) => {
    let id = event.target.dataset.id
    if (confirm("Yakin hendak menghapus?#"+id)) {
      try {
        await deleteUser(id)
        document.getElementById("tr-"+id).remove()
      } catch(e) {
        notifications.danger(e.message)
      }
    }
  }
</script>
<Navigation/>

<h1>List User</h1>

<Link to={PATH_URL.USER_CREATE}>Tambah User</Link>
<table>
  <tr>
    <th>ID</th>
    <th>Email</th>
    <th>Nama</th>
    <th>Umur</th>
    <th></th>
  </tr>

  {#each users as user}
  <tr id="tr-{user.id}">
    <td>{user.id}</td>
    <td>{user.email}</td>
    <td>{user.name}</td>
    <td>{user.age}</td>
    <td><button data-id="{user.id}" on:click="{onEdit}">Edit</button> <button data-id="{user.id}" on:click="{onView}">View</button> <button data-id="{user.id}" on:click="{onDelete}">Delete</button></td>
  </tr>
  {/each}
</table>

```


# Pengenalan Svelte Native

Svelte native adalah framework untuk membuat aplikasi mobile, baik android maupun ios.

Persiapan : menginstall android emulator

install java

install android studio

install android emulator

install svelte native

npx degit halfnelson/svelte-native-template myapp

npm install&#x20;

ns doctor

ns build android

ns run android

![](https://2862583545-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfbY1GzaHftdclrckNE%2F-MjyTedSWb-GPypGG_NH%2F-Mk0dzQ0ih93QSItn5BK%2FScreen%20Shot%202021-09-20%20at%2012.21.36.png?alt=media\&token=bfb6eb3d-6332-45a2-8aef-8ab1386d7493)


