Autor Zpráva
Alťák
Profil
Zdravím, řeším teď jeden bolák a byl bych rád, kdyby mi někdo poradil. Řekněme, že mám následující kód, který vloží do stránky div.

var div = document.createElement("div");
div.id = "div_id";
document.body.appendChild(div);

Reference na tento element samozřejmě zůstává v proměnné div. A také jsou na tento element (a i na jeho potomky, které pro jednoduchost vynechávám) vázány různé události. Vše funguje. Nyní si představte, že nějaký skript provede následující:

document.body.innerHTML += "<p>Byl jsem připojen abych ti znepříjemnil život! HAHA</p>";

Samozřejmě, co se nestane, veškeré reference proměnných na elementy se zruší (více např. ZDE) a to samé se stane s událostmi vázanými na element.

Má otázka zní:
Jak je možné zachovat (nějak efektivně obnovit) všechny reference a události, které byly na element vázány?
Nebo nějak detekovat, že bylo použito innerHTML na element body?

PS: Odpovědi jako "použij appendChild místo innerHTML" jsou k ničemu. Protože ten "zákeřný" kousek kódu nemám moc změnit (může to být skript od jiného developera).
Chamurappi
Profil
Reaguji na Alťáka:
Některé prohlížeče znají metodu insertAdjacentHTML, která umí přilepit kus HTML před začátek, za začátek, před konec a za konec, aniž by se přeparsoval celý vnitřní HTML kód. Na podporu bych raději moc nespoléhal, zejména když existuje jednodušší řešení s appendChild.

Protože ten "zákeřný" kousek kódu nemám moc změnit
Jestli máš možnost změnit, do čeho se to HTML dává, můžeš vyrobit <div>, tomu nastavit innerHTML a pak provádět appendChild (buď klidně celého <div>u, nebo postupně jeho firstChildů, dokud jsou).

(může to být skript od jiného developera)
Jestli je nastavování document.body.innerHTML v části, kterou nemůžeš ovlivnit, nakrm tím jiným vývojářem tygry.

Samozřejmě, co se nestane, veškeré reference proměnných na elementy se zruší
Ony zanikají i ty původní elementy (respektive vyhodí se z documentu, v paměti teoreticky zůstat můžou). Při += se ze starých elementů sestaví innerHTML (nepřesně), k tomuto innerHTML přilepíš krátký kousíček a celý kód se pak opět parsuje a vznikají nové elementy. Není to jen ztrátové, ale i dost neefektivní.

a to samé se stane s událostmi vázanými na element
… nejsou-li zapsané přímo v atributech.

Jak je možné zachovat (nějak efektivně obnovit) všechny reference a události, které byly na element vázány?
Nijak, protože věci, na které se vážou, už nejsou v documentu, jsou v něm jen jejich kopie. Některé události probublávají, ty lze navázat na společného rodiče (samotný <body>) a při jejich zpracování teprve zjišťovat, co je vyvolalo. Ale ne vždy je to dobrý nápad.
I kdybys po „přerodu“ celého <body> dodrátoval vše do původní podoby, některá data budou nenávratně ztracena — třeba pokud už byl ve stránce vyplněný <input type=file>.

Nebo nějak detekovat, že bylo použito innerHTML na element body?
Ne. Žádná událost se nevyvolává.
Alťák
Profil
Hmm, takže všechno co už vím, žádný překvápko, mám smůlu :(
Nejefektivnější by asi byl ten návrh s tygry, ale to taky nepůjde, protože pokaždý je ten vývojář někdo jiný.

Opravdu tedy neexistuje způsob? Ani JS knihovny jako jQuery toto neřeší?

Jinak díky za odpověď. Když už si ani Chamurappi neví rady, tak to vypadá dost špatně...
Kcko
Profil
Alťák:
Pokud umíš anglicky, tak se připoj na IRC na kanál #javascript, #jquery (je tam kupa lidí) a to by bylo aby Ti tam někdo neporadil.
Alťák
Profil
No můžu to vyzkoušet, nějaký doporučený program na IRC?

Jinak stejně to se získáním řešení vidím celkem černě. Na většinu svých problémů najdu řešení hledáním na Googlu. Ale jediný co jsem našel teď (i přes hodně dlouhé hledání) je jedno jediný téma na stackoverflow, na které už jsem odkázal v prvním příspěvku.
Chamurappi
Profil
Reaguji na Alťáka:
Ani JS knihovny jako jQuery toto neřeší?
Připisování do innerHTML řeší způsobem, který jsem popsal, tedy vyrobí provizorní element, do něj dají innerHTML a z něj vše přesunou na cílové místo. Žádná velká věda v tom není.
Události při těchto extrémních situacích se v jQuery nastavují přes .on (dříve přes .live), což je zase to probublávání, o kterém jsem psal.
Zřejmě by šlo vyrobit <iframe> a ten cizí skript spouštět ve stránce v něm (pokud nepotřebuje přístup ke zbytku stránky).

Nicméně psát všechno preventivně tak, aby to fungovalo i při přeparsování celého <body>, je šílené. Samotné to přeparsování je chyba. Začátečnická. Na tvém místě bych vynaložil maximální úsilí k její nápravě ze strany autora toho cizího kódu. Skript, který nabourává chod stránky, je víc vadný, než kdyby v něm byla syntaktická chyba.

Nejefektivnější by asi byl ten návrh s tygry, ale to taky nepůjde, protože pokaždý je ten vývojář někdo jiný.
To nevadí, dospělý tygr musí sníst dva až tři vývojáře měsíčně, aby na trhu informačních technologií přežil.
Alťák
Profil
Dobrá, díky, já už si nějak poradím :)

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:

0