Javascript 30 - Gün 15

10 Mayıs 2023

Projenin 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>
GitHubBu sayfayı düzenle