centi.sk odborne bez komentára

"Ajaxové" formuláre pomocou Iframe

AJAX sem, AJAX tam. Dnes už každá pidi-webová aplikácia asynchrónnu javascriptovú komunikáciu na niečo používa. Pomocou AJAXu je možné odoslať takmer všetko, dokonca i formuláre. Tie však majú pár obmedzení.

Ajaxový formulár

  • serializácia formulárových prvkov
  • upload

Jedným z problémov je fakt, že v prípade AJAXu si musíme parametre requestu poskladať sami v textovej podobe. To znamená, že si musíme prvky formulára zoserializovat, čo pri množstve rôznych typov prvkov (textový input a textarea, checkbox, radio button, select box, …) nie je jednoduché.

Druhý a väčší problém sú formuláre s uploadom. Javascript nemá prístup k dátam vybraného súboru (HTML5 už prácu so súbormi definuje a napríklad Firefox3.6 dokáže so súbormi už celkom pekne pracovať) a preto si jeho obsah do requestu nemôžeme pridať sami. Tento problém sa často rieši pomocou rôznych Flashových nadstavieb (napr. posielanie príloh v Gmaili).

Iframe to the rescue

Formulár však najspolahlivejšie odošle sám prehliadač, tak prečo ho z tohto procesu vytláčať? Formuláre (podobne ako odkazy) majú k dispozícii atribút target, ktorý môže obsahovať meno okna, do ktorého sa formulár má odoslať. Nemusí to však byť nové okno, či tab. Môže to byť i iframe, čo s výhodou využijeme.

Na formulár zavesíme vlastný submit handler, v ktorom:

  • vytvoríme nový iframe
  • previažeme ho s formulárom pomocou atribútov nametarget
  • a na takto vytvorený iframe zavesíme load handler, v ktorom si počkáme na „ajaxovú“ odpoveď servra
function formSubmit( e ) {
    var e = evt.fix( e );
    var form = e.target;

    form.target = form.id + '-iframe';
    var iframe = document.createElement( 'iframe' );
        iframe.name = form.target;

    document.body.appendChild( iframe );
    evt.add( iframe, 'load', getXmlResponse );
}

evt.add( document.getElementById( 'form' ), 'submit', formSubmit );

Odpoveď môže prísť v rôznych formách (textová, JSON, XML). Ja som nedávno začal v AJAXovej komunikácii používať práve XML a tu som narazil na pár drobností, ktoré IE rieši trochu inak. Ide o získanie XML dokumentu z načítaného iframu a o získanie obsahu konkrétneho XML tagu.

Iframe, XML a Internet Explorer

XML odpoveď z iframu získame pomerne jednoducho načítaním dokumentu okna iframu: iframe.contentWindow.document. Internet Explorer bohužial v tomto kuse kódu vráti HTML dokument, ktorý obsahuje farebne zvýraznené XML (zobrazte si nejaké XML priamo v IE a uvidíte o čom hovorím). Našťastie však po XML dokument nemusíme chodiť ďaleko:

var xmlDocument = iframe.contentWindow.document;
var xmlDocumentIE = iframe.contentWindow.document.XMLDocument;

Na podobný drobný rozdiel narazíme i pri pokuse o získanie textového obsahu XML tagu:

var xmlTag = xmlDocument.getElementsByTagName("person")[0];

var value = xmlTag.textContent;
var valueIE = xmlTag.text;

Po vyriešení oboch drobností môže naše spracovanie XML z iframu vyzerať napríklad takto:

function getXmlResponse( e ) {
    var e = evt.fix( e ),
        iframe = e.target,
        xmlDocument = iframe.contentWindow.document.XMLDocument || iframe.contentWindow.document;

        setTimeout( function() {
            iframe.parentNode.removeChild( iframe );
        }, 0 );

    // example
    var person = xmlDocument.getElementsByTagName( 'person' )[0];
    document.getElementById('example-output').innerHTML = person.textContent || person.text;
}

Celý kód si môžete prezrieť v akcii v malej ukážke. V príklade na prácu s eventami používam narýchlo zbastlený objektík evt. V praxi však s najväčšou pravdepodobnosťou šiahneme po obľúbenom JS frameworku.

Niektoré JS frameworky obsahujú i podporu pre odosielanie formulárov pomocou Iframe, napríklad io-upload-iframe modul z YUI3. Práve u tohto som však narazil na problém zo získaním XML dokumentu v IE, pretože aktuálna verzia obsahuje chybu.