Javascript 30 - Gün 15
10 Mayıs 2023Projenin demosu : Demo
Başlangıç dosyalarını bulabileceğiniz repom: js-30 | github
JS ile bugüne kadar oluşturduğumuz değerlerin tamamını her sayfa yenilenmesinde kaybediyorduk. Bugün Local Storage API kullanarak tarayıca kalıcı olarak veri saklayacağız ve demoda da görüleceği gibi bir Alışveriş Listesi projesi geliştireceğiz.
Başlamadan önce Local Storage hakkında bir not
LocalStorage ile yalnızca key-value değerleri saklayabiliriz ve value'muz sadece ve sadece string
olabilir. Dolayısıyla aşağıdaki gibi bir ekleme işleminde problem yaşamayız.
localStorage.setItem('isim','furkan')
localStorage.getItem('isim') // 'furkan'
Ancak örneğin bir object'i localStorage'a eklemeye çalışırsak;
const ogrenci = {
isim: 'Furkan',
yas: 24,
}
localStorage.setItem('ogrenci',ogrenci);
localStorage.getItem('ogrenci')// '[object Object]'
Burada görüleceği gibi object localStorage'a kaydedilerken .toString
metoduyla otomatik olarak stringe dönüştürüldüğünden doğru bir şekilde kaydedilmedi. Bu sorunu çözmek için JSON.stringify
kullanarak objecti stringe doğru bir şekilde dönüştürmeliyiz ve local storage'dan bu değeri okurdan JSON.parse
kullanmalıyız.
const ogrenci = {
isim: 'Furkan',
yas: 24,
}
localStorage.setItem('ogrenci',JSON.stringify(ogrenci));
JSON.parse(localStorage.getItem('ogrenci'));//{isim: 'Furkan', yas: 24}
Javascript Event Delegation Konsepti
Bu projede karşılaşacağımız önemli bir konsept ise Event Deleagation. Projemizde bir ul
etiketimiz var ve içerisinde alınacak ürünler li
etiketiyle oluşturuluyor. Bu ürünler alındığında üstüne tıklanarak işaretlenecek ancak site ilk açıldığında li
etiketleri olmadığından bunları takip etmemmiz mümkün değil. İşte burada li
elementlerini kapsayan parent'a (yani ul
elementine) event listener ekliyoruz ve dinlerken tıklanan ilgili elementi anlayabiliyoruz. Basit bir örnek şu olabilir:
<ul id="liste">
<li>Bana tıklarsan uyarırım!</li>
<button>Bana tıklarsan umrumda olmaz!<button>
</ul>
const liste = document.querySelector('#liste');
function uyar(e){
//aşağıda tiklanan öğeyi kontrol ettik eğer li değilse fonksiyon hiçbir şey yapmadan sonlanacaktır.
if(!e.target.matches('li')) return;
alert('Bana tıkladın ve uyarıyorum!')
}
liste.addEventListener('click',uyar)
Bu örnekte her element öge için ayrı ayrı olay dinleyicisi eklemek yerine, üst ögeye tek bir olay dinleyicisi ekleyerek işlemi gerçekleştirdik.
Çözümüm
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>LocalStorage</title>
<link rel="stylesheet" href="style.css">
<link rel="icon" href="https://fav.farm/🔥" />
</head>
<body>
<div class="wrapper">
<h2>SHOPPING LIST</h2>
<p></p>
<ul class="products">
<li>Loading shopping list...</li>
</ul>
<form class="add-items">
<button type="button" id="clear">Clear</button>
<input type="text" name="item" placeholder="Item Name" required>
<input type="submit" value="+ Add Item">
</form>
</div>
<script>
const addItems = document.querySelector('.add-items');
const itemsList = document.querySelector('.products');
// localStorage'dan items adlı değişkeni al, yoksa boş bir array oluştur
const items = JSON.parse(localStorage.getItem('items')) || [];
const clearButton = document.querySelector('#clear');
function addItem(e) {
// varsayılan olarak form gönderildiginde sayfa yenilenecektir bunu engelleyelim
e.preventDefault();
// inputa eklenen yeni elemanin değerini inputu seçip .value değerine bakarak alıyoruz
const text = (this.querySelector('[name=item]')).value;
// yeni alınacak ürün için bir obje oluşturuyoruz
const item = {
text: text,
done: false
}
// oluşturduğumuz objeyi ürünleri sakladığımız array'e ekliyoruz.
items.push(item);
//Güncellenmiş listeyi göstermek için populateList fonksiyonunu çağırıyoruz
populateList(items, itemsList);
// Güncellenmiş items dizisini localStorage'a kaydediyoruz
localStorage.setItem('items', JSON.stringify(items));
// formu sıfırlayalım
this.reset();
}
function toggleDone(e) {
//Tıklanan element input değilse fonksiyondan çıkıyoruz
if (!e.target.matches('input')) return;
const el = e.target;
// Tıklanan öğenin 'data-index' özelliğinden hangi öğe olduğunu belirliyoruz
const index = el.dataset.index
// Seçilen öğenin 'done' özelliğini tersine çeviriyoruz
items[index].done = !items[index].done;
// Güncellenmiş items dizisini localStorage'a kaydediyoruz
localStorage.setItem('items', JSON.stringify(items));
// Güncellenmiş listeyi göstermek için populateList fonksiyonunu çağırıyoruz
populateList(items, itemsList);
}
function clearAll(){
//localStorage'daki tüm verileri siliyoruz
localStorage.setItem('items',JSON.stringify([]))
// urunleri sakladığımız listeyi sıfırlayalım (items=[] yapamayız çünkü const olarak başlattık)
items.length = 0;;
// sildikten sonra tekrar fonksiyonumuz ile görünen listeyi güncelliyoruz
populateList(items,itemsList);
}
// populateList fonksiyonu bir liste ve hedef element alıyor.
// listedeki her bir obje için li ve input elementlerinden oluşan bir HTML hazırlıyor
// son olarak hedef elementinin içindeki HTMLi güncelliyor
// böylece her bir ürün için sayfada li elementi oluşturuluyor
function populateList(list = [], element) {
element.innerHTML = list.map((item, i) => {
return `
<li>
<input type="checkbox" data-index=${i} id="item${i}" ${item.done ? 'checked' : ''}>
<label for="item${i}">${item.text}</label>
</li>
`
}).join('');
}
addItems.addEventListener('submit', addItem)
itemsList.addEventListener('click', toggleDone)
clearButton.addEventListener('click',clearAll)
// sayfa yüklendiğinde öğeleri listele
populateList(items, itemsList);
</script>
</body>
</html>