IlmHamroh
JavaScript Full-stack/9-qism. JavaScript brauzerda va debugging23/29-dars19 daqiqa
Mundarija (33)

JavaScript input va change hodisalari: formani jonli tekshirish

Qisqacha: input hodisasi maydon qiymati har o'zgarganda keladi — har harf, o'chirish, nusxa joylash. change esa qiymat "tasdiqlanganda" keladi: matn maydonida mehmon maydondan chiqqanda, checkbox va select da esa darhol. Jonli tekshirishning qulay qoidasi: xatoni birinchi marta change da ko'rsating, xato chiqqan maydonni esa har input da qayta tekshirib, tuzatilishi bilan xabarni olib tashlang.

Bu darsda

  • input va change qachon kelishini aniq ayta olasiz va to'g'risini tanlaysiz.
  • Belgi hisoblagichi kabi "yozayotgan paytdagi" javoblarni yozasiz.
  • Xato xabarini mehmonni oldindan ayblamasdan, o'z vaqtida ko'rsatasiz va olib tashlaysiz.
  • disabled va readOnly ni JavaScript'dan yoqib-o'chirasiz va ularning farqini bilasiz.
  • Portfolio'dagi aloqa formasiga xabar hisoblagichini qo'shasiz.

Oldin bilishingiz kerak: Forma qiymatlarini o'qish va submit, Event delegation, Qulay va accessible forma, Element yaratish, joylash va o'chirish.

1. Nega bu kerak?

O'tgan darsda forma submit paytida tekshirildi. Bu yetarlimi? Bir vaziyatni ko'raylik.

Ali «Bahor» bron formasining "Izoh" maydoniga uzun xat yozdi: qaysi stol, nechta bola, qanday taom. Maydonda 200 belgi chegarasi bor. 200-belgidan keyin harflar shunchaki yozilmay qoldi — Ali buni sezmadi va gapi o'rtasida uzilib qoldi. Mehmonga oldindan "37 belgi qoldi" deb aytish kerak edi.

Ikkinchi holat. Ali kishi soniga 25 yozdi, keyin yana uchta maydonni to'ldirdi va oxirida «Bron qilish» ni bosdi. Shundagina xato chiqdi va fokus yana tepaga sakradi. Xatoni Ali kishi soni maydonidan chiqishi bilanoq bilishi kerak edi.

Qulay va accessible forma darsidagi jadvalni eslang: xatoni "yozayotganda", "maydondan chiqqanda" yoki "yuborishda" ko'rsatish mumkin. O'shanda faqat HTML bilan bizda oxirgi usul bor edi. Bugun JavaScript qolgan ikkitasini beradi — ikki hodisa orqali: input va change.

2. input hodisasi — har o'zgarishda

2.1 Belgi hisoblagichi

input (kiritish) hodisasi maydon qiymati har safar o'zgarganda keladi. Ali bitta harf yozdi — bitta hodisa. Bitta harf o'chirdi — yana bitta.

html
<style>
  textarea { width: 100%; max-width: 320px; }
</style>
<label for="izoh">Izoh (200 belgigacha)</label>
<textarea id="izoh" name="izoh" rows="3" maxlength="200"></textarea>
<p id="hisob">0 / 200</p>
<script>
  const izoh = document.querySelector("#izoh");
  const hisob = document.querySelector("#hisob");

  izoh.addEventListener("input", (event) => {
    const soni = event.target.value.length;
    hisob.textContent = `${soni} / 200`;
    console.log(event.target.value);
  });
</script>

Maydonga "Osh" deb yozing. Hisoblagich har harfda o'zgaradi: 1 / 200, 2 / 200, 3 / 200. Konsolda uch qator chiqadi:

text
O
Os
Osh

Hodisa kelgan paytda value allaqachon yangilangan — unda yangi harf bor. Shuning uchun input tinglovchisi ichida qiymatni bemalol o'qiysiz.

2.2 input ni nima chaqiradi

Klaviaturadan yozishdan tashqari, input hodisasini yana ko'p narsa chaqiradi:

  • Matnni joylash (Ctrl + V yoki sichqonchaning o'ng tugmasi → "Paste").
  • Belgilangan matnni o'chirish yoki kesish.
  • Brauzerning avtoto'ldirishi (autocomplete darsi).
  • Telefondagi ovozli yozish va so'z tavsiyalari.
  • Checkbox, radio, select, range surgichining o'zgarishi.

Shu sababli qiymat o'zgarishini klaviatura hodisalari bilan emas, input bilan kuzatiladi. keydown sichqoncha bilan joylashni ko'rmaydi, uning ichida esa yangi harf hali value ga tushmagan bo'ladi.

Qiymat qanday o'zgarganini event.inputType aytadi: "insertText" — yozildi, "deleteContentBackward" — Backspace bilan o'chirildi, "insertFromPaste" — joylandi. Bu kamdan-kam kerak bo'ladi, lekin borligini bilib qo'ying.

Tekshirib ko'ring: Hisoblagichni keyup hodisasi bilan yozsa, qaysi holatda u xato son ko'rsatadi?

Javob

Mehmon matnni sichqoncha bilan joylasa yoki kessa ("Paste", "Cut" menyusi) — bitta ham tugma bosilmaydi, keyup kelmaydi. Avtoto'ldirish ham klaviaturasiz ishlaydi. Hisoblagich eski sonda qolib ketadi. input esa bu holatlarning hammasida keladi.

3. change hodisasi — qiymat tasdiqlanganda

3.1 Ikkalasini yonma-yon kuzatamiz

change (o'zgarish) — "mehmon qiymatni o'zgartirib bo'ldi" degan signal. U qachon kelishi maydon turiga bog'liq. Buni jurnal bilan ko'ramiz:

html
<form>
  <label>Ism <input name="ism"></label>
  <label><input type="checkbox" name="choy"> Ko'k choy</label>
  <label>Taom
    <select name="taom">
      <option>Osh</option>
      <option>Manti</option>
    </select>
  </label>
</form>
<script>
  const forma = document.querySelector("form");

  function qiymati(maydon) {
    return maydon.type === "checkbox" ? maydon.checked : maydon.value;
  }

  forma.addEventListener("input", (event) => {
    console.log("input:", event.target.name, qiymati(event.target));
  });
  forma.addEventListener("change", (event) => {
    console.log("change:", event.target.name, qiymati(event.target));
  });
</script>

Tartib bilan sinab ko'ring va konsolni kuzating:

  1. Ism maydoniga "Ali" yozing — uchta input qatori chiqadi, change yo'q.
  2. Tab bilan maydondan chiqing — endi change: ism Ali chiqadi.
  3. Maydonga qayting va hech narsa o'zgartirmasdan yana chiqing — konsol jim. Qiymat o'zgarmagan bo'lsa, change kelmaydi.
  4. "Ko'k choy" ni belgilang — input: choy true va change: choy true birdaniga.
  5. Taomni "Manti" ga almashtiring — yana ikkalasi birga.

Ikkinchi qadamni Tab o'rniga Enter bilan ham sinang: matn maydonida Enter ham qiymatni tasdiqlaydi va change chiqaradi.

Matn maydonida voqealar ketma-ketligi shunday:

sequenceDiagram
  participant A as Ali
  participant M as Ism maydoni
  participant J as JavaScript
  A->>M: "A" yozdi
  M->>J: input
  A->>M: "l", "i" yozdi
  M->>J: input, input
  A->>M: Tab — maydondan chiqdi
  M->>J: change (qiymat o'zgargan)

Natijani jadvalda jamlaymiz:

Maydon input change
Matn, textarea Har harfda Chiqqanda yoki Enter da (o'zgargan bo'lsa)
Checkbox, radio Bosilganda Bosilganda — input bilan birga
select Tanlanganda Tanlanganda — input bilan birga
number (strelka bilan) Har qadamda Har qadamda

Nimaga qarang: ikki hodisa faqat matn maydonlarida farq qiladi. Checkbox va select da ikkalasi bir vaqtda keladi — bunday maydonlarda odatda change tinglanadi, chunki nomi ma'noga mos.

3.2 Ikkalasi ham ko'tariladi

Yuqoridagi misolda tinglovchi har maydonga emas, formaning o'ziga qo'yildi. input va change ham submit kabi ko'tariladi (bubble) — Event delegation darsidagi qoida ishlaydi. Qaysi maydondan kelganini event.target aytadi, ajratish uchun esa name qulay.

Bu focus va blur dan farq qiladi: ular ko'tarilmaydi (Fokus, scroll va resize hodisalari). change esa ko'tariladi, shuning uchun "maydondan chiqdi va qiymat o'zgardi" signalini butun forma uchun bitta tinglovchi bilan olish mumkin.

Tekshirib ko'ring: Qaysi hodisani tinglaysiz? a) qidiruv maydonida natijalarni yozilgan sari filtrlash; b) "Yetkazib berish" checkbox'i belgilanganda manzil maydonini ko'rsatish; c) email maydonidan chiqqanda uni kichik harflarga o'tkazish.

Javob

a) input — har harfda javob kerak. b) change — checkbox'da ikkalasi bir vaqtda keladi, change ma'noga mosroq. c) change — mehmon yozib bo'lgach, bir marta. input da qilinsa, kursor har harfda sakrab ketishi mumkin.

4. Ikki tuzoq

4.1 Kod yozgan qiymat hodisa chiqarmaydi

input va change faqat mehmon qiymatni o'zgartirganda keladi. JavaScript maydon.value = ... deb yozsa, hech qanday hodisa bo'lmaydi:

html
<label for="izoh">Izoh (200 belgigacha)</label>
<textarea id="izoh" rows="3" maxlength="200"></textarea>
<p id="hisob">0 / 200</p>
<button type="button" id="namuna">Namuna bilan to'ldirish</button>
<script>
  const izoh = document.querySelector("#izoh");
  const hisob = document.querySelector("#hisob");

  function hisobniYangila() {
    hisob.textContent = `${izoh.value.length} / 200`;
  }
  izoh.addEventListener("input", hisobniYangila);

  document.querySelector("#namuna").addEventListener("click", () => {
    izoh.value = "Deraza yonidagi stol bo'lsa yaxshi.";
  });
</script>

«Namuna bilan to'ldirish» ni bosing. Maydonda 35 belgilik matn paydo bo'ldi, hisoblagich esa 0 / 200 da qoldi. Bu ataylab shunday qilingan: aks holda kod va hodisa bir-birini cheksiz chaqirib qolishi mumkin edi.

Tuzatish: qiymatni yozgan joyda ishni o'zingiz bajaring — izoh.value = "..." dan keyin hisobniYangila(); ni chaqiring. Shuning uchun tinglovchi ichidagi ishni alohida, nomli funksiyaga chiqarish foydali: uni ham hodisa, ham kod chaqira oladi.

Ikkinchi yo'l ham bor — hodisani o'zingiz "chiqarish": izoh.dispatchEvent(new Event("input", { bubbles: true })). U Custom events darsidagi dispatchEvent ning o'zi. Bu yo'l boshqa birov yozgan tinglovchilarni ham ishga tushirish kerak bo'lganda qo'llanadi. O'z kodingizda funksiyani to'g'ridan-to'g'ri chaqirish soddaroq.

4.2 change bilan "jonli" hisoblagich

Hisoblagichni change ga ulasangiz, u faqat mehmon maydondan chiqqanda yangilanadi — Ali yozayotganda son qotib turadi. Qoida: ko'rinadigan javob har harfda kerak bo'lsa — input; "tayyor" qiymat bilan ish qilish kerak bo'lsa — change.

5. Jonli tekshirish: qachon ayblash kerak

5.1 "Kech ayblash, tez kechirish"

Eng sodda jonli tekshirish — har input da tekshirish. Lekin Ali ism maydoniga birinchi harf "A" ni yozishi bilan "Ism kamida 2 harf bo'lsin!" degan qizil xabar chiqadi. U hali yozib bo'lmadi-ku! Bu asabni buzadi.

Ko'p tajribali jamoalar quyidagi qoidaga amal qiladi:

  1. Toza maydon — mehmon yozayotganda hech narsa demang.
  2. Maydondan chiqdi (change) — endi tekshiring. Xato bo'lsa, xabarni ko'rsating.
  3. Xatoli maydonga qaytdi va yozyapti (input) — har harfda qayta tekshiring. Qiymat to'g'ri bo'lishi bilanoq xabarni olib tashlang.

Ya'ni xato kechroq ko'rsatiladi, tuzatish esa darhol qabul qilinadi. Mehmon xatoni tuzatayotganda qizil yozuv qachon yo'qolishini kutib o'tirmaydi.

stateDiagram-v2
  [*] --> Toza
  Toza --> Xato: change, qiymat xato
  Toza --> Togri: change, qiymat to'g'ri
  Xato --> Togri: input, tuzatildi
  Togri --> Xato: change, yana buzildi

Diagrammaga qarang: input faqat Xato holatidan chiqish yo'li. Toza yoki to'g'ri maydonda yozish hech narsani o'zgartirmaydi.

CSS'dagi :user-invalid (Holat pseudo-klasslari) ham aynan shunga yaqin ishlaydi: mehmon maydonga tegib, chiqib ketmaguncha qizarmaydi. Bugun xuddi shu xulqni o'zimiz yozamiz — o'z o'zbekcha xabarimiz bilan.

5.2 Xato xabari: HTML tuzilmasi

Xabar qanday ko'rinishi Qulay va accessible forma darsida kelishilgan:

  • Xato matni maydon yonidagi alohida elementda, id si <maydon>-xato (masalan ism-xato).
  • Maydonda aria-invalid="true" — ekran o'quvchi "noto'g'ri" deb aytadi.
  • Maydonning aria-describedby si xato elementiga ishora qiladi — Malika maydonga kelganda xabar matnini ham eshitadi.
  • Xato yo'q bo'lsa — uchalasi ham yo'q. Yashirin xato matni ham o'qilib qoladi (Forma komponentlari).

Forma komponentlari darsida CSS [aria-invalid="true"] ni qizil chizgan va "bu atributni keyin JavaScript qo'yadi" degan edik. Mana o'sha payt keldi.

5.3 To'liq misol

html
<style>
  form { display: grid; gap: 4px; max-width: 320px; }
  input { padding: 6px; border: 2px solid #5b6660; }
  [aria-invalid="true"] { border-color: #b3261e; }
  [id$="-xato"] { color: #b3261e; font-size: 14px; }
  button { margin-top: 8px; padding: 8px; }
</style>
<form action="https://example.com/bron" method="post">
  <label for="ism">Ismingiz (2–50 belgi)</label>
  <input id="ism" name="ism" required maxlength="50">
  <label for="odam">Necha kishi (1–20)</label>
  <input id="odam" name="odam" type="number" required>
  <button type="submit">Bron qilish</button>
</form>
<script>
  const forma = document.querySelector("form");

  function ismniTekshir(qiymat) {
    if (qiymat.trim().length < 2) {
      return "Xato: ism kamida 2 harf bo'lsin.";
    }
    return "";
  }

  function odamniTekshir(qiymat) {
    const odam = Number(qiymat);
    if (qiymat === "" || odam < 1 || odam > 20) {
      return "Xato: kishi soni 1 dan 20 gacha bo'lsin.";
    }
    return "";
  }

  const tekshiruvlar = { ism: ismniTekshir, odam: odamniTekshir };

  function xatoniYangila(maydon, matn) {
    const id = `${maydon.id}-xato`;
    let xato = document.getElementById(id);
    if (matn === "") {
      xato?.remove();
      maydon.removeAttribute("aria-invalid");
      maydon.removeAttribute("aria-describedby");
      return;
    }
    if (xato === null) {
      xato = document.createElement("span");
      xato.id = id;
      maydon.after(xato);
    }
    xato.textContent = matn;
    maydon.setAttribute("aria-invalid", "true");
    maydon.setAttribute("aria-describedby", id);
  }

  function maydonniTekshir(maydon) {
    const tekshir = tekshiruvlar[maydon.name];
    if (tekshir !== undefined) {
      xatoniYangila(maydon, tekshir(maydon.value));
    }
  }

  forma.addEventListener("change", (event) => {
    maydonniTekshir(event.target);
  });

  forma.addEventListener("input", (event) => {
    if (event.target.hasAttribute("aria-invalid")) {
      maydonniTekshir(event.target);
    }
  });
</script>

Endi qoidani o'z qo'lingiz bilan tekshiring:

  1. Ismga "A" yozing — hech narsa chiqmaydi. Siz hali yozyapsiz.
  2. Tab bosing — ism ostida qizil "Xato: ism kamida 2 harf bo'lsin." chiqadi, ramka qizaradi.
  3. Ismga qaytib "li" ni qo'shing. "Al" bo'lgan zahoti xabar yo'qoladi — Tab ni kutmaydi.
  4. Kishi soniga 25 yozib chiqing — xabar chiqadi. 2 ni o'chirsangiz, 5 qoladi va xabar darhol yo'qoladi.

Kodni bo'laklab o'qiymiz:

  • ismniTekshir, odamniTekshir — toza funksiyalar: qiymat oladi, xato matnini yoki bo'sh satrni qaytaradi. Sahifaga tegmaydi, shuning uchun ularni alohida sinash oson.
  • tekshiruvlar — obyekt: kalit — maydon nomi, qiymat — o'sha maydonning tekshiruvchi funksiyasi. Yangi maydon qo'shish uchun bitta qator yetadi. Funksiyani obyektga qiymat qilib qo'yish — Funksiya — qiymat darsidagi g'oya.
  • xatoniYangila — sahifa bilan ishlaydigan yagona joy. Xato bo'lsa — span yaratadi yoki borini yangilaydi, atributlarni qo'yadi. Bo'lmasa — hammasini olib tashlaydi. xato?.remove() — element bo'lmasa, jimgina hech narsa qilmaydi.
  • Ikki tinglovchi — «Kech ayblash, tez kechirish» qoidasining o'zi. change doim tekshiradi. input esa faqat aria-invalid li, ya'ni xato ko'rsatilgan maydonni.

Brauzerning o'z tekshiruvi ham joyida qoldi: maydonlarni bo'sh qoldirib «Bron qilish» ni bossangiz, required pufagi chiqadi. Bizning kod ustiga qo'shildi, brauzerni almashtirmadi. "Ali" va 4 bilan bossangiz, pastda yashil " Forma tekshiruvdan o'tdi" yozuvi chiqadi: bu misolda submit tinglovchisi yo'q, forma to'xtatilmadi (Forma qiymatlarini o'qish darsidagi yashil yozuv). Ikkalasini birlashtirish — Constraint Validation API darsida.

Maslahat: Maydonda boshqa yordam matni ham bo'lsa (aria-describedby="telefon-yordam"), removeAttribute("aria-describedby") uni ham o'chirib yuboradi. Unda atributni to'liq qayta yozing: xato bor — "telefon-yordam telefon-xato", yo'q — "telefon-yordam". 3-mashqda shunday qilamiz.

Tekshirib ko'ring: Nega input tinglovchisidagi if ni olib tashlasak, mehmon uchun yomonroq bo'ladi?

Javob

Unda har bir maydon har harfda tekshiriladi. Ali ismga "A" yozishi bilan, hali maydondan chiqmasdan, qizil xato chiqadi — "Toza" holat yo'qoladi. if xatoli maydonnigina har harfda tekshiradi: ayblash change gacha kechikadi, kechirish esa darhol.

6. disabled va readOnly ni boshqarish

6.1 Maydonni yoqish va o'chirish

Ba'zi maydonlar faqat ma'lum shartda kerak. «Bahor»da tug'ilgan kun bron qilinsa, tortga yoziladigan matn so'raladi. Boshqa mehmonlarga bu maydon kerak emas.

html
<form action="https://example.com/bron" method="post">
  <label>
    <input type="checkbox" id="tugilgan" name="tugilgan">
    Tug'ilgan kun uchun
  </label>
  <p>
    <label for="yozuv">Tortdagi yozuv</label>
    <input id="yozuv" name="yozuv" required maxlength="30" disabled>
  </p>
  <button type="submit">Bron qilish</button>
</form>
<script>
  const forma = document.querySelector("form");
  const katak = document.querySelector("#tugilgan");
  const yozuv = document.querySelector("#yozuv");

  katak.addEventListener("change", () => {
    yozuv.disabled = !katak.checked;
    console.log("yozuv.disabled:", yozuv.disabled);
  });

  forma.addEventListener("submit", (event) => {
    event.preventDefault();
    console.log("Yuborildi. yozuv:", forma.elements.yozuv.disabled
      ? "yuborilmaydi (disabled)"
      : forma.elements.yozuv.value);
  });
</script>

Ikki tajriba:

  1. Checkbox'ga tegmasdan «Bron qilish» ni bosing. Konsolda "Yuborildi. yozuv: yuborilmaydi (disabled)" chiqadi. "Tortdagi yozuv" required, lekin bo'sh — baribir o'tdi!
  2. Checkbox'ni belgilang (konsolda yozuv.disabled: false) va yana bosing. Endi brauzer bo'sh yozuvni to'xtatadi.

Maydon holatlari darsidagi qoidalar JavaScript'da ham o'z kuchida: disabled maydon fokus olmaydi, brauzer uni tekshirmaydi va serverga yubormaydi. JavaScript'da u disabled xususiyati — true yoki false.

6.2 readOnly — o'qish uchun

readonly maydon ko'rinadi, fokus oladi, serverga ketadi — faqat o'zgartirib bo'lmaydi. Masalan, ro'yxatdan o'tgan mehmonning telefoni oldindan yozilgan. Uni "O'zgartirish" tugmasi bilan ochamiz:

html
<form>
  <label for="telefon">Telefon</label>
  <input id="telefon" name="telefon" readonly
         value="+998 90 000 00 00">
  <button type="button" id="ozgartir">O'zgartirish</button>
</form>
<script>
  const telefon = document.querySelector("#telefon");
  const tugma = document.querySelector("#ozgartir");
  console.log(telefon.readOnly, telefon.readonly);

  tugma.addEventListener("click", () => {
    telefon.readOnly = false;
    telefon.focus();
    telefon.select();
    tugma.hidden = true;
  });
</script>

Konsolda:

text
true undefined

Ikkinchi qiymatga qarang: telefon.readonly — undefined. HTML atributi readonly, lekin JavaScript xususiyati readOnly — katta O bilan. Kichik harf bilan yozilgan telefon.readonly = false xato bermaydi: u shunchaki obyektga yangi, keraksiz xususiyat qo'shadi va maydon qulflanganicha qoladi.

«O'zgartirish» ni bosing: maydon ochildi, fokus unga o'tdi, select() metodi esa ichidagi matnni belgilab qo'ydi — mehmon darhol yangi raqamni yoza boshlaydi. Tugma o'z ishini qilib, yashirindi.

disabled readOnly
Ko'rinishi Xira Oddiy
Fokus oladimi Yo'q Ha
Serverga ketadimi Yo'q Ha
Brauzer tekshiradimi Yo'q Yo'q

Diqqat: "Forma to'liq bo'lmaguncha yuborish tugmasini disabled qilish" — mashhur, lekin yomon usul. Qulay va accessible forma darsida sababini ko'rgan edik: disabled tugma fokus olmaydi, mehmon esa nega bosilmayotganini tushunmaydi. Tugmani faol qoldiring, bosilganda xatolarni ko'rsating. Tugmani faqat yuborish jarayonida vaqtincha o'chirish o'rinli — ikki marta bosilmasligi uchun (FormData darsida).

7. Ko'p uchraydigan xatolar

7.1 Har harfda ayblash

input da darhol tekshirish → mehmon birinchi harfdayoq qizil xatoni ko'radi. Tuzatish: «Kech ayblash, tez kechirish» qoidasi — change da ko'rsatish, input da faqat xatoli maydonni qayta tekshirish.

7.2 maydon.value = ... dan keyin hech narsa yangilanmadi

Kod yozgan qiymat input ham, change ham chiqarmaydi. Tuzatish: qiymatni yozgan joyda kerakli funksiyani o'zingiz chaqiring.

7.3 readonly kichik harf bilan

maydon.readonly = false — jim xato, maydon qulflanganicha qoladi. Tuzatish: readOnly. Atribut bilan ishlasangiz — maydon.removeAttribute("readonly") (atribut nomi kichik harf bilan).

7.4 Xato tuzatilgach, atributlar qolib ketdi

Xabar matni o'chirildi, lekin aria-invalid="true" qoldi. Ekrandagi maydon to'g'ri ko'rinadi, Malika esa "noto'g'ri" degan so'zni eshitishda davom etadi. Tuzatish: xatoni ko'rsatish va olib tashlashni bitta funksiyada qiling (xatoniYangila kabi) — ikkalasi doim birga o'zgarsin.

7.5 change ni darhol kutish

"Ism maydoniga yozdim, change ishlamadi" — u maydondan chiqqanda yoki Enter da keladi. Tuzatish: har harfda kerak bo'lsa — input.

7.6 input ichida qiymatni qayta yozish

Avtomobil raqami maydoni bor, harflar katta bo'lishi kerak. Birinchi fikr — har input da maydon.value = maydon.value.toUpperCase(). Mehmon AB ning o'rtasiga x yozadi va... kursor oxirga sakraydi. Keyingi harf y endi oxiriga tushadi: AXBY chiqadi, AXYB emas. Chrome'da sinab ko'rdik: value ga boshqa satr yozilsa, kursor doim oxirga ko'chadi.

Tuzatish: qiymatni change da o'zgartiring (mehmon yozib bo'lgach, bir marta) yoki faqat ko'rinishni o'zgartiring — CSS'dagi text-transform: uppercase matnni katta harf bilan ko'rsatadi, qiymatga tegmaydi. Server baribir o'zi katta harfga o'tkazadi.

8. Mashqlar

1-mashq (oson): Qaysi hodisa?

Har harakat uchun qaysi hodisa(lar) kelishini yozing: faqat input, faqat change, ikkalasi yoki hech biri.

  1. Matn maydoniga "Osh" yozildi (hali maydonda).
  2. Shu maydondan Tab bilan chiqildi —
  3. Checkbox belgilandi.
  4. Kod maydon.value = "Manti" deb yozdi —
  5. Matn maydoniga sichqoncha bilan matn joylandi (hali maydonda).
Yechim
  1. Uchta input (har harfga bittadan).
  2. change — qiymat o'zgargani uchun.
  3. Ikkalasi, bir vaqtda.
  4. Hech biri — kod yozgan qiymat hodisa chiqarmaydi.
  5. Bitta input (inputType — "insertFromPaste"). change maydondan chiqqanda keladi.

2-mashq (o'rta): Taxminiy hisob

Bron formasida "Necha kishi" (number, 1–20) maydoni bor. Uning ostida <output> elementi (Guruhlash va natija elementlari) har o'zgarishda taxminiy osh narxini ko'rsatsin: "Taxminan 4 × 35 000 = 140000 so'm". Maydon bo'sh yoki chegaradan tashqarida bo'lsa — "Kishi sonini kiriting". Qaysi hodisani tinglaysiz?

Yechim

Narx yozilgan sari yangilanishi kerak — input:

html
<label for="odam">Necha kishi (1–20)</label>
<input id="odam" name="odam" type="number" min="1" max="20">
<output for="odam" id="taxmin">Kishi sonini kiriting</output>
<script>
  const odam = document.querySelector("#odam");
  const taxmin = document.querySelector("#taxmin");

  odam.addEventListener("input", () => {
    const soni = odam.valueAsNumber;
    if (Number.isNaN(soni) || soni < 1 || soni > 20) {
      taxmin.textContent = "Kishi sonini kiriting";
      return;
    }
    taxmin.textContent =
      `Taxminan ${soni} × 35 000 = ${soni * 35000} so'm`;
  });
</script>

4 yozing — "Taxminan 4 × 35 000 = 140000 so'm". Strelka bilan oshirsangiz ham yangilanadi: number strelkalari ham input chiqaradi. Bo'sh maydonda valueAsNumber — NaN, shuning uchun Number.isNaN tekshiruvi kerak (Forma qiymatlarini o'qish dagi tuzoq).

3-mashq (qiyin): Telefon va yordam matni

«To'liq misol» dagi formaga telefon maydonini qo'shing. Maydon ostida doim yordam matni turadi: <span id="telefon-yordam">Masalan: +998 90 000 00 00</span>, maydonda aria-describedby="telefon-yordam".

  1. Tekshiruvchi telefonniTekshir: bo'sh joylarni olib tashlagandan keyin qiymat +998 bilan boshlansin va jami 13 belgi bo'lsin. Ishora: replaceAll(" ", "") va startsWith (Matnni o'zgartirish va tozalash).
  2. Xato bo'lsa aria-describedby — "telefon-yordam telefon-xato", tuzatilsa — yana "telefon-yordam". Yordam matni yo'qolmasin.
Yechim
html
<style>
  form { display: grid; gap: 4px; max-width: 320px; }
  [aria-invalid="true"] { outline: 2px solid #b3261e; }
  [id$="-xato"] { color: #b3261e; }
</style>
<form action="https://example.com/bron" method="post">
  <label for="telefon">Telefon</label>
  <span id="telefon-yordam">Masalan: +998 90 000 00 00</span>
  <input id="telefon" name="telefon" type="tel"
         aria-describedby="telefon-yordam">
</form>
<script>
  const forma = document.querySelector("form");

  function telefonniTekshir(qiymat) {
    const raqam = qiymat.replaceAll(" ", "");
    if (!raqam.startsWith("+998") || raqam.length !== 13) {
      return "Xato: +998 va 9 ta raqam yozing.";
    }
    return "";
  }

  function xatoniYangila(maydon, matn) {
    const yordam = `${maydon.id}-yordam`;
    const id = `${maydon.id}-xato`;
    let xato = document.getElementById(id);
    if (matn === "") {
      xato?.remove();
      maydon.removeAttribute("aria-invalid");
      maydon.setAttribute("aria-describedby", yordam);
      return;
    }
    if (xato === null) {
      xato = document.createElement("span");
      xato.id = id;
      maydon.after(xato);
    }
    xato.textContent = matn;
    maydon.setAttribute("aria-invalid", "true");
    maydon.setAttribute("aria-describedby", `${yordam} ${id}`);
  }

  forma.addEventListener("change", (event) => {
    const m = event.target;
    xatoniYangila(m, telefonniTekshir(m.value));
  });
  forma.addEventListener("input", (event) => {
    const m = event.target;
    if (m.hasAttribute("aria-invalid")) {
      xatoniYangila(m, telefonniTekshir(m.value));
    }
  });
</script>

90 000 00 00 yozib chiqing — xato chiqadi, yordam matni joyida qoladi. Boshiga +998 ni qo'shsangiz, oxirgi raqamdayoq xato yo'qoladi. Bu tekshiruv to'liq emas: +998abcdefghi ham 13 belgi. Raqamlarni aniq tekshirish uchun HTML'dagi pattern qulayroq — uning natijasini JavaScript'dan o'qishni Constraint Validation API darsida o'rganamiz.

4-mashq: Portfolio qadami — xabar hisoblagichi

Aloqa formasidagi "Xabar" maydonida maxlength="1000" bor (Forma qiymatlarini o'qish dagi forma). Mehmon chegaraga qancha qolganini ko'rsin.

  1. aloqa/index.html da textarea ostiga (o'sha p ichiga) <span id="xabar-yordam">0 / 1000</span> qo'shing va textarea ga aria-describedby="xabar-yordam" yozing. Nom kanonik <maydon>-yordam qoidasiga mos.
  2. asosiy.js dagi aloqaFormasiniUla ichida input bilan hisoblagichni yangilang. reset() dan keyin ham 0 / 1000 ga qaytsin — reset ham input chiqarmaydi.
  3. Email maydonidan chiqqanda (change) qiymatdagi chetki probellarni olib tashlang va kichik harfga o'tkazing: Ali@Example.com → ali@example.com.
  4. Commit: Aloqa: xabar hisoblagichi va email tozalash.
Yechim

aloqaFormasiniUla ichiga, submit tinglovchisidan oldin:

js
const xabar = forma.elements.xabar;
const hisob = document.querySelector("#xabar-yordam");

function hisobniYangila() {
  hisob.textContent = `${xabar.value.length} / 1000`;
}
xabar.addEventListener("input", hisobniYangila);

forma.elements.email.addEventListener("change", (event) => {
  const email = event.target;
  email.value = email.value.trim().toLowerCase();
});

submit tinglovchisida forma.reset(); dan keyin bitta qator: hisobniYangila();.

Natijani tekshiring:

html
<form action="https://example.com/aloqa" method="post">
  <p><label for="email">Email</label>
    <input id="email" name="email" type="email" required></p>
  <p><label for="xabar">Xabar</label>
    <textarea id="xabar" name="xabar" rows="3" required
      maxlength="1000"
      aria-describedby="xabar-yordam"></textarea>
    <span id="xabar-yordam">0 / 1000</span></p>
  <button type="submit">Yuborish</button>
</form>
<script>
  const forma = document.querySelector("form");
  const xabar = forma.elements.xabar;
  const hisob = document.querySelector("#xabar-yordam");

  function hisobniYangila() {
    hisob.textContent = `${xabar.value.length} / 1000`;
  }
  xabar.addEventListener("input", hisobniYangila);

  forma.elements.email.addEventListener("change", (event) => {
    const email = event.target;
    email.value = email.value.trim().toLowerCase();
  });
</script>

Emailga Ali@Example.com yozib Tab bosing — ali@example.com bo'ladi. Xabarga yozing — hisoblagich har harfda o'zgaradi. Bu sinov parchasida submit tinglovchisi yo'q, shuning uchun «Yuborish» yashil yozuv beradi; portfolio'dagi aloqaFormasiniUla esa yuborishni o'zi to'xtatadi. Bu yerda change da qiymatni o'zgartirish xavfsiz: kod yozgan qiymat yangi change chiqarmaydi, cheksiz aylanish yo'q.

E'tibor bering: ></textarea> ochuvchi teg bilan bir qatorda, orasiz yozilgan. Teglar orasida bo'sh joy yoki yangi qator qolsa, u textarea ning boshlang'ich qiymati bo'lib qoladi va hisoblagich 0 dan emas, boshqa sondan boshlanadi.

9. Real ishda

  • Belgi hisoblagichi — Telegram kanal tavsifi, X (Twitter) posti, SMS shakli: hammasi input bilan ishlaydi.
  • Jonli tekshirish — ro'yxatdan o'tish formalarida "parol kamida 8 belgi" kabi qatorlar. Katta loyihalarda forma kutubxonalari (masalan React Hook Form — kursda alohida o'rganamiz, hozir bilish shart emas) "qachon tekshirish" ni onChange, onBlur, onSubmit rejimlari bilan sozlaydi. Ostida aynan bugungi ikki hodisa turadi.
  • Qidiruv maydoni har harfda serverga so'rov yubormasligi uchun "yozish to'xtagach" kutish usuli — Fokus, scroll va resize hodisalari darsidagi debounce — ishlatiladi. Uni qidiruvga Dinamik UI'da qulaylik darsida qo'llaymiz.
  • Intervyuda: "input va change farqi?", "Nega keyup emas?", "disabled va readonly farqi?" — uchalasiga javobingiz tayyor.

Xulosa

  • input — qiymatning har o'zgarishi: yozish, o'chirish, joylash, avtoto'ldirish.
  • change — tasdiqlangan qiymat: matn maydonida chiqqanda yoki Enter da, checkbox va select da darhol.
  • Ikkalasi ham ko'tariladi — formaga bitta tinglovchi yetadi; event.target.name maydonni aytadi.
  • Kod yozgan value hech qanday hodisa chiqarmaydi — kerakli funksiyani o'zingiz chaqiring.
  • Jonli tekshirish: change da ayblang, input da kechiring; aria-invalid va xato matni doim birga.
  • disabled — yuborilmaydi va tekshirilmaydi; readOnly (katta O) — yuboriladi, faqat o'zgarmaydi.

Keyingi dars: FormData — butun formani bitta qatorda yig'amiz, qaysi tugma bosilganini bilamiz va formani koddan to'g'ri yuboramiz.

Manbalar

  • MDN: "Element: input event", "HTMLElement: change event", "InputEvent.inputType" — developer.mozilla.org
  • MDN: "HTMLInputElement.readOnly", "HTMLInputElement.select()" — developer.mozilla.org
  • web.dev: "Learn Forms — Help users avoid re-entering data / validation" — web.dev
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
JavaScript input va change hodisalari: formani jonli tekshirish — IlmHamroh