Bu yazılarda ve yazılar dışında yaptığım pratik projelerini burada tutuyorum.
Öğrenmenin en verimli yolu pratik yapmak, ben de bu yolda bazı projeler yapıyorum. Bir su takipçisi programı yazmayı denedim ve bu yazı da benim serüvenim.
Yaptığım su takipçisi aslında tablodaki günleri işaretlemeye yarayan bir program. localStorage kullanarak bu günler tarayıcı belleğine kaydediliyor, böylece sayfayı yenilediğinizde veya başka bir sefer tekrar açtığınızda işaretlediğiniz günler kaybolmuyor.
Bu su takipçisini iki farklı şekilde yapmayı öğrendim, ikisinin de işlevi aynı fakat çalışma mantıklarında farklar var.
V1: <input type=”checkbox”>
HTML elementi input kullanıcının veri girişi yapabilmesini sağlıyor ve bu elementin farklı tipleri var. <input type=”checkbox”> sayesinde her güne bir checkbox koydum, bu sayede günleri işaretleyebiliyordum.
let items = document.getElementsByClassName('day').length;
function save() {
for(let i = 1; i <= items; i++){
var checkbox = document.getElementById(String(i));
localStorage.setItem("checkbox" + String(i), checkbox.checked);
}
}
for(let i = 1; i <= items; i++){
if(localStorage.length > 0){
var check = JSON.parse(localStorage.getItem("checkbox" + String(i)));
document.getElementById(String(i)).checked = check;
}
}
window.addEventListener('change', save);
Bu kodda yaptığım ufak bir hata var; yazarken günlerin IDlerinin sayı olmayacağı ihtimalini düşünmedim, her ne kadar sayı oldukları için çalışsalar da gün isimleri a-b-c olsaydı bu kod çalışmayabilirdi.
JavaScript tarafında ise günlerin işaretli olup olmadığını kontrol etmek için .checked kullanabilmek, checkboxların doğasından ötürü kolaydı. İşi biraz daha zorlaştıran checkbox kullanmadan işaretleme yapmak…
V2: addEventListener( “click”, …), .classList.toggle(), forEach(), .querySelector()
V1’de <input type=”checkbox”> ile aslında günleri işaretlemeyi HTML’e bıraktım denebilir. İşaretlilik durumunu nasıl yapacağıma dair hiçbir şey kodlamadım. Şimdi ise checkbox kullanmadan nasıl işaretleme yapabileceğimi çözmeliyim.
Bunu yapmak benim için iki yönden zordu; birincisi checkboxsız nasıl işaretleme yapabileceğimi bilmiyordum, ikincisi ise forEach’i nasıl kullanacağımı çözememiştim. İkisinde de Barış abimden destek aldım.
Bir günün işaretli olup olmadığını anlamak için onun üstüne tıkladığımda öncesinden farklı gözükmesi gerekiyordu. Bu değişikliği benim yapma şeklim, tıklanan günün görünümünün değişmesiydi, bu da class atamakla yapabileceğim bir şey.
classları atayacağım elementleri çağırmak için bu sefer getElementById() yerine querySelector() kullanmayı öğrenmem gerekti, çünkü elementlere bu sefer sadece id atamak yerine data-birşey yoluyla veri atadım. labellara data-day adıyla her birine gün atadım ve bunları çağırmak için de querySelector(`[data-day=${i}]`) kullandım.
CSS tarafında mark sınıfında olan elementlerin arka planını mavi yaptım. Daha sonrasında ise günlerin üstüne tıkladığımda bu sınıfı atayacak, tekrar tıkladığımda da geri sınıfı kaldıracak bir şey kodlamam gerekiyordu. .classList.toggle() ile bunu yapmam mümkündü. Çalıştırıldığında bağlı olduğu elementin classını değiştiriyor. Bunu mark() adında bir fonksiyona bağladım.
Bunu tıklandığında çalıştırmak için her bir labela onclick atamaktansa .addEventListener() daha kullanışlı oldu.
//kaç tane data-day parametreli element varsa hepsini seçtim
let items = document.querySelectorAll(`[data-day]`);
function mark() {
//her bir güne işaretlemeyi yaptığım hatalı şekil
for(let i = 1; i <= items.length; i++){
var chk = document.querySelector(`[data-day="${i}"]`);
chk.classList.toggle('mark');
}
}
//.addEventListener ile tıklandığında yukarıdaki fonksiyonu çalıştırmasını sağladım
for(let i = 1; i <= items.length; i++){
document.querySelector(`[data-day="${i}"]`).addEventListener("click", mark);
}
Şimdi bu kodda iki hata var. mark() fonksiyonunu çalıştırdığımda .classList.toggle elemente mark classını atıyor ama kullandığım for() döngüsü her birine değil, gün aralığındaki hepsinde bunu uyguluyordu. Bu da hangisine tıklarsam tıklayayım, hepsinin işaretlenmesine sebep oluyordu.
İkinci hata ise bu kod ile işaretlenmiş olan hiçbir şey tarayıcıda kayıtlı kalmıyordu, çünkü bir elementin classının ne olduğunu localStorage‘e nasıl kaydedeceğimi bilmiyordum.
Kendimce araştırıp denesem de nasıl bunu yapacağımı çözemedim ve Barış abimden yine destek istedim. İki sıkıntı için de bulduğu çözümleri size aktarıyorum.
// localStorage dolu mu diye bak
if( localStorage.length > 0 ) {
// markedDays değişkenine localStorage'dan aldığın markedDays verisini ata
let markedDays = JSON.parse( localStorage.getItem("markedDays") );
// markedDays değişkeni var mı VE markedDays değişkeninin içi dolu mu diye bak
if( markedDays && markedDays.length > 0) {
// markedDays verisi içindeki her dizi elemanını "markedDay" ismiyle forEach'ten geçir
markedDays.forEach( markedDay => {
// markedDays değişkeninin içindeki sayıları kullanarak,
// data-day parametresi o sayı olan her elemente mark sınıfını ata
document.querySelector( '[data-day="'+markedDay+'"]' ).classList.add('mark');
});
}
}
// data-day parametresine sahip bütün elementleri "item" ismiyle forEach'ten geçir
document.querySelectorAll('[data-day]').forEach( item => {
// her "item"ın "click" olayına yine "item" ismiyle fonksiyon ata
item.addEventListener('click', function(item) {
// markedDaysArray isimli bir dizi oluştur
let markedDaysArray = [];
// "mark" sınıfı varsa kaldır, yoksa ata
item.target.classList.toggle('mark');
// "mark" sınıfına ait tüm elementleri "markedItem" ismiyle forEach'ten geçir
document.querySelectorAll('.mark').forEach( markedItem => {
// markedDaysArray dizisine markedItem'ın dataset'inden
// (data parametreleri arasından) day parametresini ekle
markedDaysArray.push( markedItem.dataset.day );
});
// localStorage'ın "markedDays" öğesini markedDaysArray verisini
// (string'leştirerek) güncelle
localStorage.setItem("markedDays", JSON.stringify( markedDaysArray ));
});
});
Ben her bir günün data-day parametresini bir sayı olarak atadığım için eğer gün sayısından küçükse bir ekle şeklinde adım adım ilerletiyordum. Bu yaptığım her ne kadar sayı kapsamında mantıklı olsa da sayı olmadığında (mesela a-b-c deseydi) hata verecekti.
markedDay değişkenine localStorage‘e her bir labelın data-day verisini kaydetmek bu sorunu çözüyor. 1-2-3 diye sıralı ilerletmek yerine günler yerine a-b-c de yazabilirim ve kod yine çalışır halde olur.
forEach()’i nasıl kullanacağımı ben bilmiyordum ve Barış abinin yardımıyla öğrendim. Benim kullandığım for, aralıktaki hepsine aynı fonksiyonu uygularken forEach her birine ayrı ayrı uyguluyor. Bu da her birinin tıklandığında sadece kendi üstünde o değişikliği yapmasını sağlıyor.
markedDaysArray ise hangi günlerin işaretlendiğini bir dizi formatında kaydetmek için var. İşaretli günler 8, 15 ve 21 olsun mesela, bunları localStorage‘a markedDaysArray aracılığıyla kaydediyoruz. .push() da bu değişkene işaretli günlerin verilerini işlememizi sağlıyor, böylece sayfayı yeniden açtığımızda kayıtlı günler sıralı bir şekilde karşımıza çıkıyor.
En sondaki JSON.stringify() sayesinde de dizideki günleri localStorage‘den çağırdığımızda ayrı ayrı işlenebilir hale geliyor, böylece gün isimleri a-b-c olduğunda bunları değişken değil, string olarak almasını sağlıyor.
İkinci kodu ben yazamadım çünkü nasıl ilerleyeceğimi bilmiyordum ve her ne kadar StackOverFlow’da araştırıp yapmayı denesem de başaramadım, bu yüzden kendimi daha da geliştirmem lazım. Bu kodun mantığını kavramak bir yana, hâlâ öğreneceğim çok şey var.


Yorum bırakın