Ders 06 / 24
Form Olayları
Değer değişiminden gönderime uzanan akış; girdi ile değişim olaylarının ayrımı, gönderim listesinin kurulması, göndericinin katkısı, kısıt doğrulamasının durumları ve hatanın erişilebilir bildirimi.
İçindekiler
Önceki ders, bir alanın içeriğini öğrenmenin güvenilir yolunun tuş olayları olmadığını söyledi. Sayfadaki form yalnızca metin de toplamaz: ölçüm değeri sayıdır, tarih bir takvim denetiminden gelir, istasyon kodu bir listeden seçilir. Her denetim değerini farklı anlarda bildirir.
Bunun üstünde bir de gönderim vardır. Tarayıcı alanları toplar, kısıtları sınar ve isteği kurar. Bu ders akışı iki parçada ele alır: değer değiştiğinde ne bildirilir, gönderim istendiğinde ne olur.
Değişimi Bildiren Olaylar
Üç olay türü değerin değişimini bildirir ve üçü farklı anları işaretler.
Girdi öncesi olayı, değişiklik alana uygulanmadan önce üretilir. Ne olacağını bildirir ve iptal edilebilir; belirli bir girdiyi tümüyle reddetmek bu olayla mümkündür. Kullanıcının yazma, yapıştırma, geri alma gibi hangi işlemi yaptığı da bu olayda okunur.
Girdi olayı, değişiklik uygulandıktan sonra üretilir. Yazılan her karakterde, her yapıştırmada, her geri almada çalışır. Değeri sürekli izlemek isteyen kod bunu dinler. Önceki derste anılan birleştirme düzeneği, sesle giriş ve otomatik doldurma da bu olayı üretir; tuş olaylarının kaçırdığı durumlar buradan görülür.
Değişim olayı, değerin kesinleştiği anı bildirir. Metin alanında bu, alanın terk edilmesi ya da gönderimdir; onay kutusunda, seçenek düğmesinde ve açılır listede seçim yapıldığı andır. Yani metin alanlarında değişim olayı girdi olayından çok daha seyrek, seçim denetimlerinde ise onunla birlikte üretilir.
Seçim kuralı işin niteliğine bağlıdır. Sayfadaki süzgeç alanı yazdıkça sonucu daraltıyorsa girdi olayı gerekir. Alanın değeri bir kayda yazılacaksa değişim olayı yeterlidir ve daha azını yapar.
Girdi olayını dinleyen kodun ek bir sorumluluğu vardır: her tuşta çalışan bir işleyici, her tuşta bir istek üretmemelidir. Yerleşik çözüm gecikmeli tetiklemedir; olay geldiğinde iş hemen yapılmaz, kısa bir süre sonrasına ertelenir ve bu süre içinde yeni bir olay gelirse erteleme yeniden başlar. Kullanıcı yazmayı bıraktığında tek bir çalışma kalır. Sürenin ölçülmesi ve iptali Zamanlama ve Çizim Döngüsü dersinin konusudur.
Gönderim ve Giriş Listesi
Gönderim, tarayıcının form denetimlerini toplayıp bir istek gövdesi kurmasıdır. Web’in Temelleri ve HTML kursundaki Form Yapısı dersinde tanımlanan giriş listesi (entry list) bu toplamanın sonucudur. Hangi denetimin listeye girdiği kurallıdır.
// giris-listesi.mjs — gonderimde hangi denetimin listeye girdigi const denetimler = [ { ad: "istasyon", tur: "text", deger: "Kuzey Yamaç" }, { ad: "olcum", tur: "select", deger: "sicaklik" }, { ad: "deger", tur: "number", deger: "-4.2" }, { ad: "birim", tur: "radio", deger: "C", isaretli: true }, { ad: "birim", tur: "radio", deger: "F", isaretli: false }, { ad: "dogrulandi", tur: "checkbox", deger: "evet", isaretli: false }, { ad: "not", tur: "textarea", deger: "" }, { ad: "", tur: "text", deger: "adsiz alan" }, { ad: "gizliKod", tur: "text", deger: "K-9", devreDisi: true }, { ad: "eylem", tur: "submit", deger: "kaydet" }, { ad: "eylem", tur: "submit", deger: "sil" }, ]; // Gonderimi baslatan dugme: yalniz o listeye girer, digerleri girmez. const gonderici = denetimler.find((d) => d.tur === "submit" && d.deger === "kaydet"); function girisListesi(denetimler, gonderici) { const giris = []; for (const d of denetimler) { if (d.ad === "" || d.devreDisi) continue; if ((d.tur === "radio" || d.tur === "checkbox") && d.isaretli !== true) continue; if (d.tur === "submit" && d !== gonderici) continue; giris.push([d.ad, d.deger]); } return giris; } const giris = girisListesi(denetimler, gonderici); for (const [ad, deger] of giris) console.log(` ${ad.padEnd(11)} = ${JSON.stringify(deger)}`); console.log("govde:", new URLSearchParams(giris).toString());
istasyon = "Kuzey Yamaç" olcum = "sicaklik" deger = "-4.2" birim = "C" not = "" eylem = "kaydet" govde: istasyon=Kuzey+Yama%C3%A7&olcum=sicaklik°er=-4.2&birim=C¬=&eylem=kaydet
Dört kural çıktıdan okunur. Adı olmayan denetim listeye girmez; ad, alanın sunucuya görünen kimliğidir. Devre dışı denetim listeye girmez; bu, önceki derste anılan “devre dışı bırakmanın görünmez kılması” kuralının veri tarafındaki karşılığıdır. İşaretlenmemiş onay kutusu ve seçilmemiş seçenek düğmesi listeye girmez; alıcı taraf bu alanların yokluğunu “hayır” olarak yorumlamak zorundadır. Boş metin alanı listeye girer, çünkü boş bir değer de bir değerdir.
Gönderici düğme ayrı bir katkı yapar. Formda birden çok gönderim düğmesi varsa listeye yalnızca tıklanan düğmenin adı ve değeri girer; alıcı taraf hangi eylemin istendiğini buradan öğrenir. Gönderim olayı, gönderici düğmeyi olay nesnesi üzerinden bildirir.
Gönderim olayı iptal edilebilir. Varsayılan Davranış ve İptal dersindeki kural burada işler: gönderimi iptal eden kod, veriyi kendisi göndermek zorundadır. Giriş listesinin program tarafından da kurulabilen bir karşılığı vardır ve isteğe olduğu gibi verilebilir; böylece sunucu tarafı iki yolda da aynı gövdeyi görür.
Kısıt Doğrulaması
Gönderim olayı üretilmeden önce tarayıcı kısıt doğrulamasını (constraint validation) çalıştırır. Kısıtlar işaretlemede bildirilir; sonuçları bir durum kümesi olarak okunur.
// gecerlilik.mjs — kisit ozniteliklerinden gecerlilik durumunun turetilmesi const KISIT = { zorunlu: true, enAz: -50, enCok: 60, adim: 0.1, taban: 0 }; // Adim denetimi ikilik kesir hatasindan kacinmak icin tam sayiya olceklenir. const olcek = 1000; const adimUyumsuz = (sayi, k) => Math.round((sayi - k.taban) * olcek) % Math.round(k.adim * olcek) !== 0; function gecerlilik(ham, k = KISIT, devreDisi = false) { const durum = { degerEksik: false, turUyumsuz: false, aralikAlti: false, aralikUstu: false, adimUyumsuz: false, }; if (devreDisi) return { dogrulanir: false, durum, gecerli: true }; if (k.zorunlu && ham === "") durum.degerEksik = true; else if (ham !== "") { const sayi = Number(ham); if (Number.isNaN(sayi)) durum.turUyumsuz = true; else { if (sayi < k.enAz) durum.aralikAlti = true; if (sayi > k.enCok) durum.aralikUstu = true; if (adimUyumsuz(sayi, k)) durum.adimUyumsuz = true; } } const gecerli = Object.values(durum).every((v) => v === false); return { dogrulanir: true, durum, gecerli }; } const ornekler = [ ["", false], ["-4.2", false], ["-80", false], ["61.5", false], ["12.34", false], ["cok soguk", false], ["999", true], ]; for (const [ham, devreDisi] of ornekler) { const { dogrulanir, durum, gecerli } = gecerlilik(ham, KISIT, devreDisi); const bozuk = Object.entries(durum).filter(([, v]) => v).map(([ad]) => ad); console.log( JSON.stringify(ham).padEnd(12), "dogrulanir:", String(dogrulanir).padEnd(5), "gecerli:", String(gecerli).padEnd(5), bozuk.join(", "), ); }
"" dogrulanir: true gecerli: false degerEksik "-4.2" dogrulanir: true gecerli: true "-80" dogrulanir: true gecerli: false aralikAlti "61.5" dogrulanir: true gecerli: false aralikUstu "12.34" dogrulanir: true gecerli: false adimUyumsuz "cok soguk" dogrulanir: true gecerli: false turUyumsuz "999" dogrulanir: false gecerli: true
Model üç şeyi gösterir. Birincisi, geçerlilik tek bir doğru–yanlış değil, ayrı ayrı okunabilen durumlardan oluşur; hata iletisi hangi kısıtın bozulduğuna göre yazılabilir. İkincisi, adım kısıtı ondalık değerlerde doğrudan bölme ile sınanamaz; Bilgisayarlar Nasıl Çalışır kursundaki ikilik kesir sorunu burada belirir ve sınama tam sayıya ölçeklenerek yapılır. Üçüncüsü, devre dışı denetim hiç doğrulanmaz; son satırdaki aralık dışı değer geçerli sayılmıştır, çünkü o denetim doğrulamaya katılmaz.
Tarayıcının kendi sınaması, alanın ham değerini de düzeltebilir. Sayı bekleyen bir alana sayı olmayan bir dizgi yazıldığında değer boşaltılabilir; o durumda bildirilen durum “tür uyumsuz” değil “değer eksik” olur. Bu nedenle hata iletisi, kullanıcının gördüğü değere değil bildirilen duruma bakılarak seçilir.
Program tarafında üç işlem tanımlıdır. Biri geçerliliği sınar ve sonucu döndürür; ikincisi sınar ve geçersizse tarayıcının kendi iletisini gösterir; üçüncüsü alana özel bir hata iletisi yazar. Üçüncüsü uygulama kurallarını taşımak için vardır: işaretlemede bildirilemeyen bir kural — ölçüm tarihinin gelecekte olmaması gibi — bu yolla yerleşik düzeneğe bağlanır. Boş bir ileti yazmak alanı yeniden geçerli kılar.
Formun tamamında doğrulamayı kapatan bir bildirim de vardır. Bu bildirim tarayıcının kendi iletilerini kaldırır; kısıtlar okunmaya devam eder. Kendi hata sunumunu kuran sayfalar bu yolu izler. Hiçbir durumda istemci tarafı doğrulama sunucu tarafı doğrulamanın yerini tutmaz: istek, sayfa hiç kullanılmadan da kurulabilir.
Hatayı Bildirmek
Geçersiz her alan için bir olay üretilir ve bu olay kabarmaz; formun tamamındaki hataları tek yerde toplamak isteyen kod yakalama kipini kullanır. Olay Devri dersindeki kural bu noktada ikinci kez karşımıza çıkar.
Hatanın sunumu üç parçadan oluşur. Alanın yanında ilgili ileti durur ve alana ek açıklama bağıyla iliştirilir; alan geçersizlik bildirimiyle işaretlenir. Formun başında bir hata özeti bulunur ve her madde ilgili alana bağlantı verir. Gönderim denemesinden sonra odak ilk geçersiz alana ya da özetin kendisine taşınır; Odak ve Klavye Etkileşimi dersindeki programlı odak kuralı burada işler.
Hata iletilerinin yazılma anı da bir tasarım kararıdır. Kullanıcı alanı doldururken her tuşta hata göstermek, henüz bitmemiş bir girdiyi hatalı ilan eder. Yaygın düzen şudur: ilk ileti alan terk edildiğinde ya da gönderim denendiğinde yazılır; alan bir kez hatalı bulunduktan sonra girdi olayında güncellenir, böylece düzeltme anında ileti kaybolur.
Formun sıfırlanması ayrı bir olay üretir ve iptal edilebilir. Sıfırlama, alanları işaretlemede bildirilen başlangıç değerlerine döndürür — DOM API’si dersindeki öznitelik ile özellik ayrımının doğrudan sonucudur. Kendi tuttuğu durumu bu olayda temizlemeyen kod, ekranda boşalmış ama bellekte dolu bir formla kalır.
Özet
- Girdi öncesi olayı değişiklik uygulanmadan önce üretilir ve iptal edilebilir; girdi olayı her değişiklikte, değişim olayı değerin kesinleştiği anda üretilir.
- Girdi olayına bağlanan iş gecikmeli tetiklemeyle seyreltilir; her tuş bir istek üretmez.
- Giriş listesine adı olan, devre dışı olmayan ve seçim denetimlerinde işaretli olan denetimler girer; birden çok gönderim düğmesinden yalnızca tıklanan katkı verir.
- Kısıt doğrulaması tek bir doğru–yanlış değil ayrı ayrı okunabilen durumlar üretir; devre dışı denetimler doğrulamaya hiç katılmaz.
- Özel hata iletisi yazan işlem, işaretlemede bildirilemeyen uygulama kurallarını yerleşik doğrulamaya bağlar; istemci tarafı doğrulama sunucu tarafının yerini tutmaz.
- Geçersizlik olayı kabarmaz; hata sunumu ileti, özet ve odak taşıma olmak üzere üç parça hâlinde kurulur.
Sonraki Adım
Bu ders formun bir gönderimle bittiğini varsaydı. Oysa çoğu form yarım kalır: kullanıcı ölçüm değerini girer, sekmeyi kapatır, ertesi gün geri döner. Sayfa yeniden yüklendiğinde bellekte tutulan her şey silinmiştir; süzgeç alanına yazılan ölçüt de, yarım kalan form da. Bunları saklamak, tarayıcının sayfa ömrünü aşan bir yere yazmayı gerektirir. Sonraki ders bu yerleri — sekme ömrüyle sınırlı olanı, kaynak ömrü boyunca kalanı ve yapılandırılmış veriyi tutanı — ayrımlarıyla birlikte ele alır.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.