Autor Zpráva
hypot
Profil
Situace je zachycena zde: codepen.io/pigner/pen/bYZEWW

Uživatel může kliknout na křížek a tak smazat položku nečíslovaného seznamu (řádek). Po kliknutí na křížek se ještě objeví červeně podbarvený titulek, na který je třeba kliknout, aby se smazání položky uskutečnilo (jde tedy o jakési potvrzení úmyslu mazání). Funguje to dobře, pokud uživatel skutečně úmysl mazání provede. Pokud si však smazání rozmyslí (klávesou Escape nechá titulek zmizet) a pak klikne na jiný křížek a skutečně smaže jinou položku, nedojde ke smazání jen oné druhé položky, kterou si skutečně smazat přál, nýbrž i té předchozí, jejíž smazání si naopak na poslední chvíli rozmyslel - což je nežádoucí chování.

Příčina je mi známa: červeně podbarvený titulek se nachází v dokumentu v jednom exempláři, ve výchozím stavu je skrytý a podle požadavku se objevuje tam, kde se kliklo. Teprve až v okamžiku, kdy se tento prvek zviditelní, je mu přidán EventListener s funkcí, která způsobí smazání (ve skutečnosti skrytí) položky seznamu (řádku). Když se funkce, která smaže (skryje) položku, spustí, vykoná se i metoda removeEventListener() (řádek 14). Jak ukazuje průzkumník DOM, toto skutečně funguje a EventListener se z prvku obsahujícího červeně podbarvený titulek odstraní. Pokud však uživatel smazání nepotvrdí, mazací funkce se nespustí a titulek se jen skryje, EventListener na něm se neodregistruje a zůstává na něm i při příštím objevení se. Proto jsem přidal metodu removeEventListener() i do okamžiku bezprostředně po objevení titulku (řádek 6), aby se odstranil EventListener, pokud by předtím na prvku s titulkem byl v důsledku nepotvrzení mazání (skrytí). Avšak removeEventListener() na řádku 6 svůj úkol nesplní (jak jsem se přesvědčil, když jsem skript za šestým řádkem zastavil). V důsledku toho se prvku s titulkem s jedním už přiřazeným "hlídačem událostí" přiřadí další EventListener a mazací se funkce se proto provede víckrát. Jinak řečeno: metoda removeEventListener() na řádku 14 funguje, na řádku 6 nikoli.

Na tento problém jsem sice našel řešení (prvek s titulkem po každém kliknutí vytvořím zcela nově a po stisku klávesy Escape či smazání položky jej úplně odstraním z DOM, čímž zanikne i EventListener s ním spojený a nemusím se trápit s jeho odstraňováním), ale přesto mě zajímá, proč nefunguje to, co jsem vytvořil jako první (jinými slovy, proč nefunguje removeEventListener() na řádku 6).
Děkuji.
Keeehi
Profil
Jelikož nejsem v javascriptu úplně doma tak to nemůžu tvrdit na sto procent, ale myslím že je to proto, že ta funkce odstrclick není ještě definovaná v době kdy je kód na řádku 6. Když to u řádku 6 zastavíš a do konzole dáš typeof odstrclick tak bych čekal že výsledek bude "undefined" místo "function".

Já osobně bych to celé ale poskládal jinak, přijde mi to nepřehledné. Nicméně, i v tom tvém případě nemá removeEventListener na řádku 6 co dělat, ale má být v obsluze klávesy escape. Tam přece má své místo. Tam se schovává element a měl by se mu odebrat i ten EventListener.
hypot
Profil
Keeehi:
je to proto, že ta funkce odstrclick není ještě definovaná v době kdy je kód na řádku 6

Pravda. (Potom je ovšem pro mě další záhada, proč mě na to konzole žádného prohlížeče neupozornila - kromě Pale Moonu (= +- Firefox 52), který jsem použil až teď).


Keeehi:
Nicméně, i v tom tvém případě nemá removeEventListener na řádku 6 co dělat, ale má být v obsluze klávesy escape. Tam přece má své místo. Tam se schovává element a měl by se mu odebrat i ten EventListener.

To mě jako nejlogičtější taky napadlo jako první, jenže to při daném uspořádání nejde (na daném místě je funkce odstrclick neviditelná (undefined)), proto jsem se to pokusil udělat, jak zde popsáno.

Keehi:
Já osobně bych to celé ale poskládal jinak, přijde mi to nepřehledné.

Chybami se člověk učí, tak kdyby aspoň velmi stručně šlo naznačit, jak to udělat lépe.
Děkuji ještě jednou.
Keeehi
Profil
hypot:
Není to ideální ale a z mého pohledu je to hezčí řešení. Živá ukázka

Událost se žádnému elementu nemusí odebírat. Když není zobrazený, nejde na něj ani kliknout.

Vaše odpověď

Mohlo by se hodit

Neumíte-li správně určit příčinu chyby, vkládejte odkazy na živé ukázky.
Užíváte-li nějakou cizí knihovnu, ukažte odpovídajícím, kde jste ji vzali.

Užitečné odkazy:

Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: