Cum să actualizați filtrele de sortare Angular

Introducere

AngularJS, Una dintre cele mai utile caracteristici ale ofertei inițiale a AngularJS a fost capacitatea de a filtra și sorta datele din pagină folosind doar variabile de șablon și filtre. Legătura de date bidirecțională a cucerit mulți convertiți la AngularJS.

Astăzi, însă, mulți dezvoltatori front-end preferă legarea de date unidirecțională, iar acele filtre orderBy și filter au apus odată cu apariția Angular. (Notă: pe parcursul acestui articol voi folosi „AngularJS” pentru a mă referi la 1.x și doar „Angular” pentru a mă referi la 2+.)

Dar cum ar trebui să obținem același efect? Răspunsul se află în componentele noastre, așa că haideți să ne uităm la un proiect ngUpgrade și să învățăm cum să facem acest lucru!

Pasul 1 – Extrageți codul din Git

Vom parcurge pas cu pas actualizarea șablonului unei componente proaspăt rescrise. Apoi, vom adăuga sortare și filtrare pentru a restabili toate funcționalitățile pe care le avea în AngularJS. Aceasta este o abilitate cheie care trebuie dezvoltată pentru procesul ngUpgrade.

Pentru a începe, luați un moment pentru a clona exemplul de proiect pe care îl vom folosi (nu uitați să rulați npm install în ambele dosare public și server). Consultați acest commit pentru punctul nostru de plecare:

git checkout 9daf9ab1e21dc5b20d15330e202f158b4c065bc3

Acest proiect de probă este un proiect hibrid ngUpgrade care utilizează atât AngularJS 1.6, cât și Angular 4. Are un API Express funcțional și un Webpack builds atât pentru dezvoltare cât și pentru producție. Simțiți-vă liber să explorați, să o bifurcați și să folosiți modelele în propriile proiecte. Dacă doriți să vă uitați la o versiune a acestui proiect care utilizează Angular 5, consultați acest repo. În scopul acestui tutorial, diferențele dintre cele două versiuni nu vor conta (voi sublinia orice lucru minor).

Pasul 2 – Înlocuiți sintaxa AngularJS

În această etapă a aplicației noastre, componenta noastră de comenzi este rescrisă în Angular, cu toate dependențele sale injectate și rezolvate. Totuși, dacă am încerca să rulăm aplicația noastră, am vedea erori în consolă care indică probleme cu șablonul nostru. Asta este ceea ce trebuie să rezolvăm mai întâi. Vom înlocui sintaxa AngularJS în șablonul de comenzi (orders/orders.html), astfel încât să putem obține încărcarea traseului și afișarea comenzilor pe pagină. Vom rezolva în continuare filtrarea și sortarea.

Primul lucru pe care trebuie să-l facem este să scăpăm de toate instanțele de $ctrl din acest șablon. Ele nu mai sunt necesare în Angular. Putem face doar o căutare și înlocuire pentru a găsi $ctrl. (observați punctul) și să îl înlocuim cu nimic.

Acum să înlocuim data-ng-click în butonul nostru de la linia 13. În Angular, în loc de ng-click, folosim doar evenimentul click, cu paranteze pentru a indica faptul că este un eveniment. Parantezele indică o intrare, iar parantezele indică o ieșire sau un eveniment.

<button type="button" (click)="goToCreateOrder()" class="btn btn-info">Create Order</button>

Noi spunem aici că la evenimentul click, declanșăm funcția goToCreateOrder pe componenta noastră de comenzi.

Înainte de a continua, haideți să luăm un minut pentru a dovedi că componenta noastră se încarcă efectiv. Comentați întregul div care încarcă comenzile noastre (de la linia 17 încolo). Pentru a rula aplicația, deschideți un terminal și rulați următoarele comenzi:

cd servernpm start

Aceasta va porni serverul Express. Pentru a rula serverul Webpack dev, deschideți un alt terminal și rulați:

cd publicnpm run dev

(Puteți păstra aceste procese în funcțiune pentru restul acestui tutorial.)

Ar trebui să vedeți că aplicația noastră se încarcă din nou. Dacă mergeți la ruta comenzi, veți vedea că componenta comenzi se afișează corect.

Captură de ecran a aplicației

De asemenea, putem face clic pe butonul Create Order și ne va trimite corect la ruta și formularul nostru Create Order.

Bine, să ne întoarcem la HTML. Decomentați acel div (aplicația noastră va fi din nou stricată).

Să înlocuim tot restul instanțelor data-ng-click cu gestionarul de evenimente (click). Puteți folosi Find Replace sau pur și simplu folosiți comanda rapidă a editorului dvs. pentru a selecta toate ocurențele (în VS Code pentru Windows, aceasta este Ctrl+Shift+L).

În continuare, înlocuiți toate ocurențele lui data-ng-show cu *ngIf. De fapt, nu există un echivalent direct pentru ng-show în Angular, dar asta este în regulă. Este preferabil să folosiți *ngIf, deoarece în acest fel adăugați și eliminați efectiv elemente din DOM în loc să le ascundeți și să le arătați pur și simplu. Așadar, tot ce trebuie să facem este să găsim data-ng-show-urile noastre și să le înlocuim cu *ngIf.

În cele din urmă, trebuie să facem două lucruri pentru a repara corpul tabelului nostru. În primul rând, să înlocuim data-ng-repeat cu *ngFor="let order of orders". Rețineți că eliminăm, de asemenea, filtrele orderBy și filter din acea linie, astfel încât întregul tr să arate astfel:

<tr *ngFor="let order of orders">

În al doilea rând, putem șterge prefixul data-ng de dinaintea legăturii href către traseul detaliat al comenzii. AngularJS se ocupă în continuare de rutare aici, dar nu mai trebuie să folosim acel prefix, deoarece acesta este acum un șablon Angular.

Dacă ne uităm din nou la aplicație, puteți vedea că comenzile se încarcă corect pe ecran:

Comenzi din aplicație captură de ecran

Există câteva lucruri în neregulă cu aceasta, bineînțeles. Legăturile de sortare nu mai funcționează, iar acum moneda noastră este oarecum încurcată, deoarece conducta de monedă din Angular este ușor diferită de omologul său AngularJS. Vom ajunge la asta. Pentru moment, acesta este un semn grozav, deoarece înseamnă că datele noastre ajung la componentă și se încarcă pe pagină. Așadar, avem elementele de bază ale acestui șablon convertite în Angular. Acum suntem gata să ne ocupăm de sortare și filtrare!

Etapa 3 – Adăugarea sortării

Avem comenzile noastre care se încarcă pe ecran, dar nu avem încă o modalitate de a le ordona sau sorta. În AngularJS, era foarte obișnuit să folosim filtrul încorporat orderBy pentru a sorta datele din pagină. Angular nu mai are un filtru orderBy. Acest lucru se datorează faptului că acum este puternic încurajată mutarea acestui tip de logică de afaceri în componentă în loc de a o avea pe șablon. Așadar, asta este ceea ce vom face aici. (Notă: vom folosi aici funcțiile și evenimentele vechi și simple, nu o abordare reactivă a formularului. Acest lucru se datorează faptului că încercăm doar să facem pași mici în înțelegerea acestor lucruri. Odată ce ați asimilat elementele de bază, nu ezitați să mergeți mai departe cu observabile!)

Sortare în componentă

Am eliminat deja filtrul orderBy din ng-repeat atunci când l-am schimbat în *ngFor. Acum vom realiza o funcție de sortare în componenta comenzi. Putem folosi evenimentele de clic de pe antetele tabelului nostru pentru a apela această funcție și pentru a trece proprietatea după care dorim să sortăm. De asemenea, vom face ca această funcție să comute înainte și înapoi între ascendent și descendent.

Să deschidem componenta comenzi (./orders/orders.component.ts) și să adăugăm două proprietăți publice la clasă. Acestea se vor potrivi cu cele două proprietăți la care șablonul nostru face deja referire. Prima dintre ele va fi sortType de tip string. Cea de-a doua va fi sortReverse de tip boolean și vom seta valoarea implicită la false. Proprietatea sortReverse ține doar evidența dacă trebuie inversată ordinea – nu vă gândiți la ea ca la un sinonim pentru ascendent sau descendent.

Acum ar trebui să aveți acest lucru după declararea titlului în clasă:

sortType: string;sortReverse: boolean = false;

În continuare, vom adăuga funcția pe care o vom folosi cu funcția prototip Array.sort în JavaScript. Adăugați acest lucru după funcția goToCreateOrder (dar tot în cadrul clasei):

dynamicSort(property) { return function (a, b) { let result = (a < b) ? -1 : (a > b) ? 1 : 0; return result; } }

Acestă funcție de sortare dinamică va compara valoarea proprietăților obiectelor dintr-un array. Funcția ternară imbricata poate fi un pic mai complicată de înțeles la prima vedere, dar practic spune doar că dacă valoarea proprietății noastre din A este mai mică decât B, returnează -1. În caz contrar, dacă este mai mare, returnăm 1. Dacă cele două sunt egale, returnează 0.

Acum, aceasta nu este o comparație super sofisticată sau profundă. Există funcții de ajutor mult mai sofisticate pe care le-ați putea scrie pentru a sorta pentru dvs. și nu ezitați să experimentați cum o puteți rupe pe aceasta. Totuși, va fi suficient pentru scopurile noastre și puteți schimba această logică cu orice logică de sortare personalizată pe care o doriți.

Așa că aceasta este funcția noastră ajutătoare. Funcției de sortare de pe prototipul Array i se poate trece o funcție pe care o poate folosi apoi pentru a compara elementele dintr-o matrice. Haideți să facem o funcție numită sortOrders în clasa noastră care să profite de acest lucru cu noua funcție dynamicSort:

sortOrders(property) { }

Primul lucru pe care trebuie să-l facem este să setăm proprietatea sortType din clasa noastră egală cu proprietatea care este transmisă. Apoi dorim să schimbăm proprietatea sortReverse. Vom avea acest lucru:

sortOrders(property) { this.sortType = property; this.sortReverse = !this.sortReverse;}

Acum putem apela funcția sort pe this.orders, dar trecem în funcția noastră de sortare dinamică cu proprietatea noastră:

sortOrders(property) { this.sortType = property; this.sortReverse = !this.sortReverse; this.orders.sort(this.dynamicSort(property));}

Și mai este un ultim lucru pe care trebuie să-l facem. Trebuie să modificăm puțin funcția noastră dynamicSort pentru a putea inversa ordinea array-ului în sens crescător sau descrescător. Pentru a face acest lucru, vom lega rezultatul funcției dynamicSort de proprietatea sortReverse a clasei.

Primul lucru pe care îl vom face este să declarăm o variabilă:

let sortOrder = -1;

Apoi, putem verifica dacă proprietatea sortReverse de pe clasa noastră este adevărată sau falsă. Dacă este adevărată, vom seta variabila noastră de ordine de sortare egală cu 1:

if (this.sortReverse) { sortOrder = 1; }

Ne legăm funcțiile noastre împreună în acest fel deoarece facem o comutare în funcția noastră de sortare de dragul demonstrației. Pentru a fi mai minuțioși, o altă abordare ar fi să avem o variabilă numită sortDescending în loc de sortReverse care este controlată printr-o funcție separată. Dacă mergeți pe această cale, veți face opusul – sortOrder ar fi 1 dacă sortDescending nu este adevărată.

Am putea, de asemenea, să combinăm aceste ultime două lucruri într-o expresie ternară, dar, de dragul clarității, o voi lăsa un pic mai verosimilă. Și apoi, doar pentru a face ca rezultatul nostru să fie opusul a ceea ce ar fi fost în mod normal, pot înmulți result cu sortOrder al nostru. Așadar, funcția noastră dynamicSort arată acum așa:

 dynamicSort(property) { let sortOrder = -1; if (this.sortReverse) { sortOrder = 1; } return function(a, b) { let result = a < b ? -1 : a > b ? 1 : 0; return result * sortOrder; }; }

Din nou, aceasta este o implementare demonstrativă a sortării, astfel încât să înțelegeți conceptele cheie ale utilizării unei funcții de sortare personalizate pe componenta dumneavoastră.

Să vedem dacă sortarea funcționează

Până acum, am adăugat o funcție de ajutor dynamicSort și o funcție sortOrders la clasa noastră, astfel încât să putem sorta pe componenta noastră în loc de șablonul nostru.

Pentru a vedea dacă aceste funcții funcționează, să adăugăm o sortare implicită la funcția noastră ngOnInit.

În interiorul abonamentului nostru forkJoin, după forEach în care adăugăm proprietatea nume client, să apelăm this.sortOrders și să trecem proprietatea total articole:

this.sortOrders('totalItems');

Când ecranul se reîmprospătează, ar trebui să vedeți că comenzile sunt sortate după numărul total de articole.

Acum trebuie doar să implementăm această sortare în șablonul nostru prin apelarea funcției sortOrders în legăturile din antetul tabelului.

Adaugați sortarea în șablon

Avem funcția sortOrders care funcționează corect pe componenta noastră de comenzi, ceea ce înseamnă că acum suntem pregătiți să o adăugăm în șablonul nostru, astfel încât capetele de tabel să poată fi din nou accesate.

Înainte de a face asta, haideți să schimbăm sortarea implicită din funcția noastră ngOnInit pentru a fi doar ID:

this.sortOrders('id');

Este puțin mai normal decât să folosim totalul articolelor.

Acum putem lucra la șablonul nostru. Primul lucru pe care vrem să-l facem este să apelăm funcția sortOrders în toate evenimentele noastre de clic. Puteți selecta instanțele de sortType = și să le înlocuiți cu sortOrders(. Apoi, puteți înlocui instanțele de ; sortReverse = !sortReverse cu ).

De asemenea, trebuie să corectăm două dintre numele proprietăților pe care le trecem aici, precum și în instanțele *ngIf. Înlocuiți cele 3 instanțe de orderId cu id și cele 3 instanțe de customername cu customerName.

Ultimul lucru pe care trebuie să îl fac este să înfășor fiecare dintre tag-urile href din anteturi în paranteze, astfel încât Angular să preia controlul și aceste link-uri să nu ajungă nicăieri. Evenimentul click va fi lucrul care va fi declanșat. Așadar, anteturile ar trebui să urmeze acest model:

<th> <a ="" (click)="sortOrders('id')"> Order Id <span *ngIf="sortType == 'id' && !sortReverse" class="fa fa-caret-down"></span> <span *ngIf="sortType == 'id' && sortReverse" class="fa fa-caret-up"></span> </a></th>

Plecăm în browser și testăm toate legăturile din anteturile de tabel. Ar trebui să vedeți că fiecare dintre proprietățile noastre se sortează acum, atât în ordine crescătoare, cât și descrescătoare. Minunat!

Este grozav, dar am pierdut un lucru – cursorul nostru este un selector, nu un pointer. Să reparăm asta cu niște CSS.

Reparați cursorul

Am reușit să facem ca sortarea noastră să funcționeze corect pe pagina noastră de comenzi, dar cursorul nostru este acum un selector în loc de un pointer, iar asta este enervant.

Există câteva moduri diferite în care am putea folosi CSS pentru a rezolva acest lucru:

  • Am putea face o clasă în fișierul SCSS al aplicației noastre principale.
  • Am putea scrie CSS în linie, deși acest lucru nu este aproape niciodată preferabil.
  • Am putea să profităm de CSS-ul de amploare al Angular folosind opțiunea styles din decoratorul de componente

Vom alege ultima opțiune, deoarece tot ce trebuie să facem este să adăugăm o regulă la stilurile noastre pentru această componentă particulară.

Deschideți din nou clasa componentei comenzi. În decoratorul componentei, putem adăuga o nouă proprietate numită styles. Styles este o matrice de șiruri de caractere, dar șirurile sunt reguli CSS. Pentru a repara cursorul nostru, tot ce trebuie să facem este să scriem o regulă care spune că, într-un rând de tabel, dacă avem un link, atunci schimbăm proprietatea cursor în pointer. Decoratorul nostru va arăta acum astfel:

@Component({ selector: 'orders', template: template, styles: })

Acum, când trecem peste anteturile rândurilor noastre, vedeți că avem cursorul pointer. Ceea ce este grozav la această abordare este că această regulă CSS nu va afecta nicio altă componentă. Se va aplica doar la componenta noastră de comenzi!

Acum, să vedem dacă putem face ceva în legătură cu filtrarea noastră. Acel „filtru de filtrare” a fost eliminat din Angular, așa că va trebui să fim creativi și să găsim o modalitate de a-l implementa pe componenta noastră.

Pasul 4 – Adăugați filtrarea

Suntem gata să înlocuim caseta noastră de filtrare care folosea filtrul AngularJS pentru a căuta în colecția de comenzi pe baza unui șir de caractere pe care îl căutam. Filtrul AngularJS trăia pe șablonul nostru și nu necesita niciun cod în controlerul sau componenta noastră. În zilele noastre, acest tip de logică în șablon este descurajat. Este de preferat să facem acest tip de sortare și filtrare pe clasa noastră de componente.

Adaugați o funcție de filtrare

Înapoi în componenta noastră, vom crea o nouă matrice de comenzi numită filteredOrders. Apoi, vom trece matricea noastră orders într-o funcție de filtrare care setează matricea filteredOrders. În cele din urmă, vom folosi filteredOrders pe șablonul nostru în *ngFor în locul matricei noastre originale. În acest fel, nu modificăm niciodată datele care se întorc de la server, ci doar folosim un subansamblu din ele.

Primul lucru pe care îl vom face este să declarăm noua proprietate în clasa noastră :

filteredOrders: Order;

Apoi, în forkJoin care setează matricea noastră originală de comenzi, putem seta starea inițială a filteredOrders la matricea noastră de comenzi:

this.filteredOrders = this.orders;

Acum suntem gata să adăugăm funcția noastră care va face de fapt filtrarea pentru noi. Lipiți această funcție imediat după funcțiile noastre de sortare din partea de jos a componentei noastre:

filterOrders(search: string) { this.filteredOrders = this.orders.filter(o => Object.keys(o).some(k => { if (typeof o === 'string') return o.toLowerCase().includes(search.toLowerCase()); }) ); }

Să vorbim despre ceea ce se întâmplă în această funcție. În primul rând, îi dăm funcției o proprietate string de search. Apoi, facem o buclă prin comenzile noastre și găsim toate cheile obiectelor. Pentru toate cheile, vom vedea dacă există valori some ale acelor proprietăți care se potrivesc cu termenul nostru de căutare. Această bucată de JavaScript poate părea puțin confuză la început, dar, în principiu, asta se întâmplă.

Rețineți că, în declarația noastră if, testăm în mod explicit pentru șiruri de caractere. În exemplul nostru de acum, vom limita interogarea noastră doar la șiruri de caractere. Nu vom încerca să ne ocupăm de proprietățile imbricate, de proprietățile numerice sau de orice altceva asemănător. Termenul nostru de căutare se va potrivi cu proprietatea „nume client”, iar dacă vom alege vreodată să afișăm adresa sau orice altă proprietate de tip șir de caractere, va căuta și prin acestea.

Desigur, am putea modifica această funcție pentru a testa numere sau pentru a căuta printr-un alt nivel de obiecte imbricate, iar acest lucru depinde în totalitate de dumneavoastră. La fel ca și în cazul sortării noastre, vom începe cu o implementare demonstrativă și vă vom lăsa să vă folosiți imaginația pentru a o face mai complexă.

Vorbind despre funcția sortOrders, înainte de a merge mai departe, trebuie să mai facem un ultim lucru pe componentă. Trebuie doar să modificăm sortOrders pentru a folosi acum filteredOrders și nu orders originalul nostru, deoarece dorim ca filtrul să aibă prioritate față de sortare. Trebuie doar să o modificăm astfel:

sortOrders(property) { this.sortType = property; this.sortReverse = !this.sortReverse; this.filteredOrders.sort(this.dynamicSort(property));}

Acum suntem gata să implementăm această filtrare pe șablon.

Adaugați filtrarea la șablon

Să ne întoarcem la șablonul nostru și să îl reparăm pentru a folosi filtrarea noastră.

Primul lucru pe care trebuie să-l facem este să înlocuim data-ng-model. În locul acestuia, vom folosi evenimentul keyup, așa că vom scrie, „keyup” și îl vom înconjura cu paranteze ((keyup)). Acesta este un eveniment încorporat în Angular care ne permite să executăm o funcție la apăsarea tastei unui input. Din moment ce am numit funcția noastră filterOrders, care era numele proprietății pe care o treceam în filtrul AngularJS, trebuie doar să adăugăm paranteze lângă ea. Intrarea noastră arată astfel până acum:

<input type="text" class="form-control" placeholder="Filter Orders (keyup)="filterOrders()">

Dar ce trecem în funcția de ordine a filtrului? Ei bine, în mod implicit, evenimentele trec ceva numit $event. Acesta conține ceva numit target, care conține apoi valoarea intrării. Există o problemă cu utilizarea $event. Este foarte dificil să țineți evidența acestor tipuri nebuloase, deoarece target.value ar putea fi într-adevăr orice. Acest lucru face dificilă depanarea sau cunoașterea tipului de valoare așteptat. În schimb, Angular are un lucru foarte ingenios pe care îl putem face, și anume să atribuim o variabilă de șablon la această intrare.

Din fericire, Angular ne oferă o metodă pentru a face acest lucru. După tag-ul nostru de intrare, putem adăuga semnul hash (#) și apoi numele modelului nostru dorit. Să-l numim #ordersFilter. Chiar nu contează în ce parte a tag-ului puneți acest lucru sau cum îl numiți, dar mie îmi place să îl pun după input, astfel încât să prind ce model este asociat cu ce input dacă arunc doar o privire în josul paginii.

Acum pot trece acea variabilă în funcția noastră filterOrders de pe evenimentul keyup. Nu avem nevoie de simbolul hash înainte, dar trebuie să adăugăm .value. Acest lucru va trece valoarea reală a modelului și nu întregul model în sine. Intrarea noastră finalizată arată astfel:

<input #ordersFilter type="text" class="form-control" placeholder="Filter Orders" (keyup)="filterOrders(ordersFilter.value)">

În cele din urmă, trebuie să modificăm *ngFor pentru a folosi matricea filteredOrders în loc de matricea obișnuită orders:

<tr *ngFor="let order of filteredOrders">

Inspect the Product

Puteți vedea cât de mult mai curat este șablonul nostru acum că filtrarea și sortarea noastră se află în componentă.

Acum să verificăm acest lucru în browser. Dacă introduceți un text în căsuță, cum ar fi „sally”, ar trebui să vedeți că ordinele noastre se schimbă și că sortarea funcționează pe deasupra:
Animare a aplicației care funcționează
Frumos, am înlocuit o altă caracteristică AngularJS!

Acum mai avem doar un ultim lucru pe care trebuie să îl facem la această componentă – să reparăm conducta de valută.

Pasul 5 – Repararea conductei de valută

Acesta este ultimul nostru pas este să actualizăm fostul filtru de valută, care se numește acum conducta de valută în Angular. Trebuie doar să adăugăm câțiva parametri la pipe în șablon, pe care nu a trebuit să îi specificăm în AngularJS. Această parte diferă dacă folosiți Angular 4 sau Angular 5:

În Angular 4, faceți acest lucru:
<td>{{order.totalSale | currency:'USD':true}}</td>

În Angular 5+, faceți acest lucru:
<td>{{order.totalSale | currency:'USD':'symbol'}}</td>

Prima opțiune este codul monedei (sunt multe, nu vă limitați la dolari americani!). A doua este afișarea simbolului. În Angular 4, acesta este un boolean care indică dacă se utilizează simbolul valutar sau codul. În Angular 5+, opțiunile sunt symbol, code sau symbol-narrow ca șiruri de caractere.

Ar trebui să vedeți acum simbolul așteptat:
Captură de ecran a coloanei Total Sale din aplicație

Și am terminat! Pentru a vedea codul finalizat, verificați acest commit.

Concluzie

Ați făcut o treabă excelentă rămânând cu acest lucru până la sfârșit! Iată ce am realizat în acest ghid:

  1. Înlocuirea sintaxei șabloanelor AngularJS cu sintaxa Angular
  2. Mutarea sortării în componentă
  3. Utilizarea stilurilor CSS cu domeniu de cuprindere
  4. Mutarea filtrării în componentă
  5. Înlocuirea filtrului de valută AngularJS cu pipe-ul de valută Angular

Unde ar trebui să mergeți de aici? Există o mulțime de lucruri pe care le puteți face:

  • Faceți sortarea mai sofisticată (de exemplu: ar trebui ca ordonarea să se reseteze sau să rămână aceeași atunci când utilizatorul face clic pe un nou antet?)
  • Faceți filtrarea mai sofisticată (căutați numere sau proprietăți imbricate)
  • Căutați o abordare reactivă. Ați putea asculta un observabil al modificărilor de valoare în locul funcției keyup și să faceți sortarea și filtrarea acolo. Utilizarea observabilelor v-ar permite, de asemenea, să faceți lucruri foarte interesante, cum ar fi debounce-ul intrării!