Zivanovy stránky - Vývoj - JS: Náhrada fce getElementById 

Altap Salamander
© Zivan

Náhrada fce getElementById()

14.4.2006

Nadávno jsem zjistil, že v PDA nefungují javascripty na mých stránkách. Pří testování jsem přišel na to, že neexistuje funkce getElementById(), tak jsem zjišťoval jak ji nahradit.

Narazil jsem na tyto situace:

prohlížečprvek s id "id1"
IE starší než 5.0document.all["id1"]
Netscape 4 a staršídocument.layers["id1"]
-||-document.ids["id1"]
Pocket IE 4.01 (WM2003)document["id1"]

Našel jsem dva různé způsoby řešení.

1. nalezené řešení - zdroj

- spočívalo v tom, že si vytvořím vlastní funkci, která mi bude vracet požadovaný objekt

function objGet(id)
{
  var d=document;
  if (d.getElementById)
    return d.getElementById(id);
  else
    if (d.all)
      return d.all[id];
    else
      if (d.layers)
        return d.layers[id];
      else
        if (d[id])
          return d[id];
  return null;
}

Řešení je funkční, ale vadilo mi používání jiné funkce, to znamenalo projít celý kód a nahradit všechna volání getElementById(). Navíc je zbytečné testovat typ přístupu k prvkům při každém volání, protože se na jedné stránce nemění.

2. nalezené řešení - zdroj

- při neexistenci funkce getElementById() se vytvoří vlastní funkce stejného jména pomocí new Function().

Zajímavým poznatkem v tomto řešení bylo to, že v případě existence více prvků se stejnou hodnotou id vrací document.all[] pole objektů. Podle specifikace DOM by měla v tomto případě funkce getElementById() vracet první prvek nebo null.

if (!document.getElementById)
  document.getElementById = new Function("idname",
    "kp = document.all(idname);" +
    "if (kp == null) return null;" +
    "if (kp.length) return document.all(idname)[0];" +
    "return document.all(idname);");

Toto řešení má důležitou chybu. Předpokladá, že jestliže má prvek hodnotu length, tak je to pole prvků se stejnou hodnotou ID (příp. NAME v IE). Ale tuto hodnotu mají i prvky SELECT a FORM, místo nich tedy dostanu jejich první položku. V tomto řešení už není potřeba upravovat stávající kód, ale zůstalo zbytečné testování při každém volání. Dalším problémem na který jsem narazil byla nefunkčnost konstrukce new Function() v IE pro WM2003.

3. vlastní řešení

Nakonec jsem si vytvořil vlastní. Nejprve otestuji vlastnosti prohližeče a podle toho sestavím tělo funkce do řetězce. Ten potom vyhodnotím funkcí eval. Pro odlišení pole prvků a html prvků s hodnotou length využívám toho, že pole nemá hodnotu NAME.

if (!document.getElementById)
{
  var fce = "function getElementById(id){var e=document";
  if (document.all)
    fce = fce + ".all[id];";
  else
    if (document.ids)
      fce = fce + "ids[id];";
    else
      if (document.layers)
        fce = fce + ".layers[id];";
      else
        fce = fce + "[id];";
  fce = fce + "return (e.length && (e.name==null)) ? e[0] : e;}";

  eval(fce);
}

Toto řešení jsem zatím s úspěchem otestoval v: