Masukkan Password
78 Cineflix: Menghapus Film
Lecture ini melanjutkan fitur sebelumnya, yaitu menampilkan detail movie, lalu sekarang ditambahkan kemampuan untuk menghapus movie.
Kalau lecture sebelumnya fokus pada:
Details
↓
find()
↓
selectedMovie
↓
tampilkan detail
lecture sekarang fokus pada:
Delete
↓
cari movie
↓
cari index movie
↓
konfirmasi user
↓
splice()
↓
movies berubah
↓
render ulang UI
Yang paling penting dari lecture ini adalah memahami hubungan antara find(), findIndex(), splice(), dan renderAllMovies().
1. Tujuan fitur Delete
Misalnya sekarang ada:
┌──────────────────────────┐
│ Interstellar │
│ ★★★★★ │
│ [Details] [Delete] │
└──────────────────────────┘
┌──────────────────────────┐
│ Fast & Furious │
│ ★★★★☆ │
│ [Details] [Delete] │
└──────────────────────────┘
┌──────────────────────────┐
│ Bahubali │
│ ★★★★☆ │
│ [Details] [Delete] │
└──────────────────────────┘
Ketika user klik:
Delete Interstellar
kita ingin:
Klik Delete
↓
Tanya: "Yakin mau menghapus Interstellar?"
↓
┌───────────┐
│ │
OK Cancel
│ │
↓ ↓
hapus movie batal
│
↓
movies array berubah
│
↓
render ulang
│
↓
Interstellar hilang dari UI
2. Kenapa harus menghapus dari movies array?
Ini konsep yang sangat penting.
Sebelumnya kita sudah punya prinsip:
movies array = sumber data utama
UI hanya merupakan tampilan dari data tersebut.
Misalnya:
let movies = [
{ id: 1, name: "Interstellar" },
{ id: 2, name: "Fast & Furious" },
{ id: 3, name: "Bahubali" }
];
UI dibuat berdasarkan array tersebut.
Jadi kalau hanya menghapus HTML:
someMovieCard.remove();
tetapi movies masih berisi:
[
Interstellar,
Fast & Furious,
Bahubali
]
maka data dan UI menjadi tidak sinkron.
Contohnya nanti ketika kita melakukan:
renderAllMovies(movies);
Interstellar akan muncul lagi.
Maka yang benar:
movies array
↓
hapus movie dari array
↓
render ulang UI
3. Langkah pertama: tombol Delete
Di dalam HTML movie card, lecture menambahkan:
<button onclick="deleteMovie(${movie.id})">
Delete
</button>
Misalnya movie:
{
id: 1,
name: "Interstellar"
}
maka hasil template literal menjadi:
<button onclick="deleteMovie(1)">
Delete
</button>
Kalau Fast & Furious:
<button onclick="deleteMovie(2)">
Delete
</button>
Jadi setiap tombol Delete membawa ID movie masing-masing.
4. Kenapa kita menggunakan ID?
Bayangkan ada:
Interstellar → index 0 → id 1
Fast Furious → index 1 → id 2
Bahubali → index 2 → id 3
User klik Delete Bahubali.
Kita menerima:
movieId = 3
Tapi masalahnya:
3adalah ID, bukan index.
Padahal splice() membutuhkan index.
Jadi kita perlu mengubah:
movie ID
↓
movie index
↓
splice()
Inilah alasan kita membutuhkan findIndex().
5. Function deleteMovie()
Lecture membuat:
function deleteMovie(id) {
// proses delete
}
Ketika tombol Bahubali diklik:
deleteMovie(3);
maka:
id = 3
Parameter id berisi ID movie yang ingin dihapus.
6. Sebelum menghapus, kita perlu konfirmasi
Ini adalah langkah UX yang bagus.
Bayangkan user tidak sengaja menekan Delete.
Kalau langsung dihapus:
Click Delete
↓
Movie langsung hilang
bisa berbahaya.
Maka kita gunakan:
confirm()
yang sudah kita pelajari sebelumnya.
Contoh:
let doDelete = confirm("Do you really want to delete this movie?");
Browser akan menampilkan:
┌─────────────────────────────────────┐
│ Do you really want to delete │
│ Interstellar? │
│ │
│ [Cancel] [OK] │
└─────────────────────────────────────┘
7. confirm() menghasilkan Boolean
Ini penting.
confirm("Are you sure?");
akan menghasilkan:
OK → true
Cancel → false
Jadi:
let doDelete = confirm(message);
bisa menghasilkan:
doDelete = true;
atau:
doDelete = false;
Kemudian:
if (doDelete) {
// lakukan delete
}
Artinya:
Kalau user menekan OK, baru hapus.
8. Membuat pesan konfirmasi dinamis
Lecture tidak hanya menampilkan:
Do you really want to delete this movie?
Tetapi juga nama movie.
Misalnya:
Do you really want to delete movie Interstellar?
Caranya dengan template literal:
let message = `
Do you really want to delete movie '${movieToDelete.name}'?
`;
Misalnya:
movieToDelete.name
adalah:
Interstellar
maka hasilnya:
Do you really want to delete movie 'Interstellar'?
Ini sama seperti yang kita lakukan di lecture detail movie:
${selectedMovie.name}
9. Tapi dari mana movieToDelete berasal?
Nah, ini bagian yang penting.
Kita ingin mencari movie berdasarkan ID.
Gunakan find():
let movieToDelete = movies.find((movie) => {
return movie.id === id;
});
Misalnya:
id = 3;
dan:
movies = [
{ id: 1, name: "Interstellar" },
{ id: 2, name: "Fast & Furious" },
{ id: 3, name: "Bahubali" }
];
find() akan mencari:
movie.id === 3
Hasil:
{
id: 3,
name: "Bahubali"
}
Kemudian:
movieToDelete
berisi object Bahubali.
10. Kenapa masih perlu find() kalau kita nanti memakai findIndex()?
Ini pertanyaan yang sangat bagus.
Sebenarnya untuk menghapus, kita tidak membutuhkan object movie.
Kita hanya membutuhkan:
index
Tetapi kita menggunakan find() terlebih dahulu karena kita ingin mendapatkan:
movieToDelete.name
untuk pesan konfirmasi.
Jadi:
find()
↓
dapat object movie
↓
ambil movie.name
↓
buat confirmation message
Sedangkan:
findIndex()
↓
dapat index
↓
splice()
↓
hapus
Jadi kedua method mempunyai tugas berbeda.
11. find() vs findIndex()
Ini salah satu hal paling penting dari lecture.
find()
Mengembalikan element/object.
let movie = movies.find((movie) => {
return movie.id === 3;
});
Hasil:
{
id: 3,
name: "Bahubali"
}
findIndex()
Mengembalikan posisi/index.
let index = movies.findIndex((movie) => {
return movie.id === 3;
});
Hasil:
2
Karena:
index
0 → Interstellar
1 → Fast & Furious
2 → Bahubali
12. Mental model find() vs findIndex()
Bayangkan kamu punya rak buku:
Index:
0 Interstellar
1 Fast & Furious
2 Bahubali
3 Inception
find()
Kamu bertanya:
“Buku Bahubali yang mana?”
Jawab:
Bahubali
findIndex()
Kamu bertanya:
“Bahubali ada di posisi berapa?”
Jawab:
2
Jadi:
find()
→ "BERIKAN BARANGNYA"
findIndex()
→ "BERIKAN POSISINYA"
13. Kenapa splice() membutuhkan index?
Sekarang kita sudah tahu index.
Misalnya:
index = 2;
Kita bisa melakukan:
movies.splice(index, 1);
Artinya:
mulai dari index 2
hapus 1 element
Maka:
Sebelum:
0 → Interstellar
1 → Fast & Furious
2 → Bahubali
3 → Inception
Setelah:
movies.splice(2, 1);
menjadi:
0 → Interstellar
1 → Fast & Furious
2 → Inception
Bahubali sudah hilang.
14. Struktur splice()
Sintaks dasar:
array.splice(start, deleteCount);
Contoh:
movies.splice(2, 1);
Ada dua informasi:
splice(2, 1)
│ │
│ └── berapa element dihapus
└───── mulai dari index berapa
Jadi:
2 = start index
1 = jumlah element yang dihapus
15. Kalau splice(0, 1)?
Misalnya:
movies.splice(0, 1);
Artinya:
Mulai dari index 0, hapus 1 element.
Yang hilang:
Interstellar
16. Kalau splice(2, 2)?
Misalnya:
movies.splice(2, 2);
Artinya:
Mulai dari index 2, hapus 2 element.
Misalnya:
0 → A
1 → B
2 → C
3 → D
4 → E
setelah:
movies.splice(2, 2);
menjadi:
0 → A
1 → B
2 → E
Yang dihapus:
C
D
Makanya lecture menggunakan:
splice(index, 1)
karena kita hanya ingin menghapus satu movie.
17. splice() mengubah array asli
Ini sangat penting.
splice() adalah mutating method.
Misalnya:
let movies = [
"A",
"B",
"C"
];
movies.splice(1, 1);
Array movies langsung berubah menjadi:
[
"A",
"C"
]
Tidak perlu:
movies = ...
karena splice() sudah memodifikasi array asli.
18. Bandingkan dengan filter()
Ini juga penting karena kita baru saja belajar filter().
filter()
let filteredMovies = movies.filter(...);
Membuat array baru.
movies
↓
filter()
↓
filteredMovies
Original:
movies → tetap
splice()
movies.splice(index, 1);
langsung mengubah:
movies
Jadi:
| Method | Mengubah array asli? | Return |
|---|---|---|
filter() | ❌ | Array baru |
find() | ❌ | Element |
findIndex() | ❌ | Number/index |
splice() | ✅ | Array element yang dihapus |
19. Kenapa tidak menggunakan filter() untuk delete?
Sebenarnya bisa.
Misalnya:
movies = movies.filter((movie) => {
return movie.id !== id;
});
Ini juga bisa menghapus movie.
Caranya:
Pertahankan semua movie yang ID-nya bukan ID yang ingin dihapus.
Tetapi lecture sedang mengajarkan findIndex() + splice(), sehingga menggunakan:
findIndex()
↓
splice()
Ini juga merupakan pola yang sangat umum.
20. Alur lengkap deleteMovie()
Secara konsep:
function deleteMovie(id) {
let movieToDelete = movies.find((movie) => {
return movie.id === id;
});
let message = `
Do you really want to delete movie
'${movieToDelete.name}'?
`;
let doDelete = confirm(message);
if (doDelete) {
let index = movies.findIndex((movie) => {
return movie.id === id;
});
movies.splice(index, 1);
renderAllMovies(movies);
}
}
Sekarang kita bedah satu-satu.
21. Step 1 — Cari movie
let movieToDelete = movies.find((movie) => {
return movie.id === id;
});
Tujuannya:
Dapatkan object movie yang ingin dihapus.
Kenapa?
Karena kita membutuhkan:
movieToDelete.name
untuk confirmation.
22. Step 2 — Buat pesan
let message = `
Do you really want to delete movie
'${movieToDelete.name}'?
`;
Misalnya:
movieToDelete.name
adalah:
Fast & Furious
maka:
Do you really want to delete movie
'Fast & Furious'?
23. Step 3 — Tanya user
let doDelete = confirm(message);
Hasilnya:
OK
↓
true
atau:
Cancel
↓
false
24. Step 4 — Cek apakah user benar-benar setuju
if (doDelete) {
// delete
}
Kalau:
doDelete === true
lanjut.
Kalau:
doDelete === false
tidak melakukan apa-apa.
Jadi:
confirm()
│
┌──────┴──────┐
↓ ↓
true false
↓ ↓
delete stop
25. Step 5 — Cari index
Setelah user menekan OK:
let index = movies.findIndex((movie) => {
return movie.id === id;
});
Misalnya:
movies:
index 0 → Interstellar, id 1
index 1 → Fast Furious, id 2
index 2 → Bahubali, id 4
index 3 → Inception, id 5
User ingin menghapus:
id = 4
findIndex() menghasilkan:
index = 2;
26. Step 6 — Hapus menggunakan splice()
Kemudian:
movies.splice(index, 1);
menjadi:
movies.splice(2, 1);
Artinya:
Mulai index 2, hapus satu movie.
Hasil:
Sebelum:
0 → Interstellar
1 → Fast Furious
2 → Bahubali
3 → Inception
Sesudah:
0 → Interstellar
1 → Fast Furious
2 → Inception
27. Step 7 — Render ulang UI
Ini bagian yang sering dilupakan.
Setelah:
movies.splice(index, 1);
data sudah berubah.
Tetapi browser belum otomatis tahu bahwa kita ingin membuat ulang movie cards.
Karena itu:
renderAllMovies(movies);
dipanggil lagi.
28. Kenapa harus render ulang?
Ingat:
movies array
↓
renderAllMovies()
↓
HTML
↓
DOM
↓
UI
Ketika kita mengubah:
movies
menjadi:
movies baru
kita perlu melakukan:
movies
↓
renderAllMovies()
↓
UI baru
Jadi:
DATA berubah
↓
RENDER ULANG
↓
UI berubah
29. Kenapa movie yang dihapus benar-benar hilang?
Misalnya awal:
movies = [
A,
B,
C,
D,
E
];
User menghapus C.
Setelah:
movies.splice(2, 1);
menjadi:
movies = [
A,
B,
D,
E
];
Kemudian:
renderAllMovies(movies);
Renderer menerima:
A
B
D
E
Tidak ada C.
Maka UI juga:
A
B
D
E
C tidak muncul lagi.
30. Ingat renderAllMovies() harus membersihkan UI
Sebelumnya kita sudah belajar bahwa function renderer harus melakukan:
movieListSection.innerHTML = "";
sebelum render.
Jadi:
function renderAllMovies(movieList) {
movieListSection.innerHTML = "";
movieList.forEach((movie) => {
...
});
}
Ini penting.
Kalau tidak dibersihkan:
UI lama
+
UI hasil render baru
=
duplicate cards
Dengan:
innerHTML = "";
maka:
UI lama
↓
dihapus
↓
UI baru dibuat
31. Alur keseluruhan delete
Sekarang satukan semuanya:
User klik Delete
↓
onclick="deleteMovie(movie.id)"
↓
deleteMovie(id)
↓
movies.find()
↓
movieToDelete
↓
ambil movieToDelete.name
↓
confirm()
↓
┌───────┐
│ │
OK Cancel
│ │
true false
│ │
↓ ↓
findIndex STOP
↓
dapat index
↓
splice(index, 1)
↓
movies array berubah
↓
renderAllMovies(movies)
↓
UI diperbarui
32. Kenapa mencari object dulu baru index?
Pada pandangan pertama memang terlihat seperti pekerjaan dua kali:
find()
kemudian:
findIndex()
Tapi masing-masing punya tujuan.
find()
Untuk mendapatkan:
movieToDelete.name
yang dibutuhkan confirmation.
findIndex()
Untuk mendapatkan:
index
yang dibutuhkan splice().
Jadi:
find()
↓
OBJECT
↓
name
↓
confirmation
findIndex()
↓
INDEX
↓
splice()
↓
delete
33. Analogi sederhana: daftar siswa
Bayangkan:
students = [
{ id: 101, name: "Budi" },
{ id: 102, name: "Andi" },
{ id: 103, name: "Siti" }
];
Kamu ingin menghapus siswa dengan ID 103.
find()
students.find(student => student.id === 103)
menghasilkan:
{
id: 103,
name: "Siti"
}
Kamu bisa bertanya:
“Yakin mau menghapus Siti?”
findIndex()
students.findIndex(student => student.id === 103)
menghasilkan:
2
Kemudian:
students.splice(2, 1);
Siti dihapus.
Jadi:
find()
→ Siapa?
findIndex()
→ Di posisi mana?
splice()
→ Hapus dari posisi tersebut.
34. Jangan tertukar slice() dan splice()
Ini juga penting karena namanya mirip.
slice()
Mengambil sebagian data.
let result = movies.slice(0, 2);
Tidak mengubah array asli.
slice()
→ ambil sebagian
→ original tidak berubah
splice()
Mengubah array asli dengan menambah/menghapus/mengganti element.
movies.splice(2, 1);
splice()
→ ubah array
→ original berubah
Mental model:
slice()
"fotokopi sebagian"
splice()
"operasi langsung pada array"
35. Satu detail penting: splice() bukan slice()
Lecture sempat mengatakan:
“start index for the slice method. I mean for the splice method”
Yang benar dalam kode ini adalah:
splice()
bukan:
slice()
Karena kita ingin menghapus element dari array asli.
36. Apa yang terjadi pada index setelah delete?
Ini menarik.
Misalnya:
0 → A
1 → B
2 → C
3 → D
4 → E
Hapus C:
movies.splice(2, 1);
menjadi:
0 → A
1 → B
2 → D
3 → E
D yang tadinya index 3 sekarang menjadi index 2.
E yang tadinya 4 sekarang menjadi 3.
Jadi index array bisa berubah setelah penghapusan.
Makanya lebih aman menggunakan ID sebagai identitas movie, bukan menyimpan index sebagai identitas permanen.
37. Kenapa ID lebih baik daripada index?
Misalnya:
Interstellar → index 0
Fast Furious → index 1
Bahubali → index 2
Setelah Interstellar dihapus:
Fast Furious → index 0
Bahubali → index 1
Index berubah.
Tetapi ID:
Interstellar → id 1
Fast Furious → id 2
Bahubali → id 3
tetap.
Jadi:
index
→ posisi sementara
id
→ identitas movie
Ini alasan project menggunakan:
movie.id
untuk mengidentifikasi movie.
38. Hubungan dengan lecture sebelumnya
Sekarang project kita sudah mempunyai beberapa operasi penting.
Search
filter()
Cari movie berdasarkan nama
Genre
filter()
Pilih movie berdasarkan genre
Detail
find()
Cari satu movie berdasarkan ID
Delete
findIndex()
+
splice()
Cari posisi movie
+
hapus movie
Sort
sort()
Ubah urutan movie
39. Cheat sheet semua method project sejauh ini
| Method | Fungsi |
|---|---|
forEach() | lakukan sesuatu untuk setiap element |
map() | transform setiap element |
filter() | ambil semua element yang cocok |
find() | ambil satu element yang cocok |
findIndex() | cari index element yang cocok |
sort() | mengurutkan array |
splice() | menambah/menghapus/mengganti element pada array |
includes() | mengecek apakah nilai terdapat di String/Array |
Cara mengingat:
forEach()
→ KERJAKAN SEMUA
map()
→ UBAH SEMUA
filter()
→ PILIH BANYAK
find()
→ CARI SATU
findIndex()
→ CARI POSISI
sort()
→ URUTKAN
splice()
→ UBAH/HAPUS ISI ARRAY
includes()
→ CEK ADA ATAU TIDAK
40. Hal yang paling penting: find() ≠ findIndex()
Kalau kamu masih bingung, fokus ke bagian ini.
Misalnya:
let movies = [
{ id: 10, name: "A" },
{ id: 20, name: "B" },
{ id: 30, name: "C" }
];
find()
movies.find(movie => movie.id === 20);
hasil:
{ id: 20, name: "B" }
OBJECT
findIndex()
movies.findIndex(movie => movie.id === 20);
hasil:
1
NUMBER / INDEX
splice()
movies.splice(1, 1);
hasil:
B dihapus
Jadi hubungan ketiganya:
ID
↓
findIndex()
↓
INDEX
↓
splice()
↓
DELETE
Sedangkan find() dipakai ketika kita membutuhkan object-nya:
ID
↓
find()
↓
MOVIE OBJECT
↓
movie.name
↓
confirmation message
41. Ada satu potensi masalah yang perlu kamu pahami
Kode lecture mengasumsikan bahwa movie pasti ditemukan:
let movieToDelete = movies.find(...);
movieToDelete.name
Kalau ternyata tidak ada:
movieToDelete === undefined
maka:
movieToDelete.name
akan error.
Dalam aplikasi yang lebih aman, kita bisa melakukan:
if (!movieToDelete) {
return;
}
Begitu juga setelah findIndex():
if (index === -1) {
return;
}
Karena findIndex() menghasilkan:
tidak ketemu → -1
Tetapi untuk project pembelajaran ini, ID berasal langsung dari movie yang ada, sehingga kasus tersebut biasanya tidak terjadi.
42. Pola data → UI yang sekarang semakin jelas
Sebelumnya kita sudah melihat:
movies
↓
renderAllMovies()
↓
UI
Sekarang:
User action
↓
ubah movies
↓
renderAllMovies()
↓
UI
Untuk delete:
DELETE BUTTON
↓
deleteMovie(id)
↓
movies.splice(...)
↓
movies berubah
↓
renderAllMovies(movies)
↓
UI berubah
Ini pola yang sangat penting dalam pengembangan aplikasi:
Jangan hanya mengubah tampilan. Ubah data sumbernya, kemudian render ulang tampilan berdasarkan data terbaru.
43. Mental model akhir lecture
Bayangkan movies sebagai database kecil sementara:
movies array
┌─────────────────┐
│ Interstellar │
│ Fast & Furious │
│ Bahubali │
│ Inception │
└────────┬────────┘
│
↓
renderAllMovies()
│
↓
UI
Ketika Delete:
User klik Delete
↓
movie.id
↓
find()
↓
movieToDelete
↓
confirm()
↓
OK
↓
findIndex()
↓
index
↓
splice(index, 1)
↓
movies array berubah
↓
renderAllMovies()
↓
UI diperbarui
44. Ringkasan super singkat
Kalau nanti kamu lupa lecture ini, ingat formula:
function deleteMovie(id) {
// 1. Cari movie untuk mendapatkan namanya
let movieToDelete = movies.find((movie) => {
return movie.id === id;
});
// 2. Tanya user
let doDelete = confirm(
`Do you really want to delete '${movieToDelete.name}'?`
);
// 3. Kalau OK
if (doDelete) {
// 4. Cari posisi movie
let index = movies.findIndex((movie) => {
return movie.id === id;
});
// 5. Hapus dari array
movies.splice(index, 1);
// 6. Render ulang
renderAllMovies(movies);
}
}
Mental modelnya:
DELETE
↓
movie ID
↓
find()
↓
"movie yang mana?"
↓
confirm()
↓
user OK?
/ \
NO YES
↓ ↓
STOP findIndex()
↓
"posisinya di mana?"
↓
splice()
↓
HAPUS
↓
renderAllMovies()
↓
UI baru
Tiga method utama yang harus benar-benar kamu kuasai dari lecture ini:
find()
→ mendapatkan OBJECT
findIndex()
→ mendapatkan INDEX
splice()
→ MENGHAPUS dari array asli
Dan jangan lupa hubungan dengan lecture sebelumnya:
filter() → pilih movie
find() → cari satu movie
findIndex() → cari posisi movie
splice() → hapus movie
render() → tampilkan hasil terbaru
Jadi fitur Delete sebenarnya bukan sekadar “menghilangkan card dari layar”, tetapi prosesnya adalah menghapus data dari movies terlebih dahulu, kemudian membuat UI mengikuti data yang sudah berubah. Itu konsep yang sangat penting untuk project-project JavaScript berikutnya.