Kirjautuminen

Haku

Tehtävät

Opasarkisto: AJAX: AJAX - Asynchronous JavaScript and XML

Kirjoittaja: MikaBug (2008).

⚠ Huomio! Tämä opas on vanhentunut. Oppaan sisältöön ei voi enää luottaa. Opas on säilytetty vain sen historiallisen arvon vuoksi. ⚠


AJAX on tekniikka, jonka avulla voidaan siirtää tietoa selaimen (client) ja palvelimen (server) välillä ilman, että koko www-sivua täytyy ladata uudelleen. Tällä tavoin sivujen toimintaa pyritään viemään enemmän kohti tavanomaisia tietokoneohjelmia. Käytännössä AJAX on usean vanhemman tekniikan yhteiskäyttöä (JavaScript, (X)HTML, XML, DOM, XMLHTTPRequest). Tässä oppaassa oletetaan, että lukija tuntee perusteet vähintään HTML-kielestä sekä JavaScriptistä. Käytännössä AJAXin käyttö vaatii myös jonkinlaista palvelinpuolen ohjelmointitaitoa, esimerkiksi PHP- tai Perl-kielellä.

XMLHTTPRequest-objekti on keskeinen asia AJAX-tekniikan käytössä, mutta se ei valitettavasti ole standardin mukainen. Tästä syystä objektia käsitellään hieman eri tavoin riippuen, käytetäänkö Internet Exploreria vai jotain muuta selainta (Opera, Mozilla jne.). Nämä erot käyvät ilmi myöhemmin tässä oppaassa.

Tuetut selaimet ovat Internet Explorer 5.0, Mozilla 1.0, Firefox, Opera 8, Netscape 7, Safari 1.2 sekä näitä uudemmat versiot.

AJAXin toimintaidea

Yleensä on totuttu siihen, että nettisivun sisällön muuttaminen vaatii sivun uudelleen lataamisen palvelimelta. Aina tällainen ei ole toivottua, ja monesti on aivan turhaa hakea verkosta koko sivua uudelleen, jos muutokset koskevat vain pientä osaa sivusta. AJAX-tekniikka mahdollistaa datan siirtämisen selaimen ja palvelimen välillä ilman, että käyttäjä huomaa välttämättä koko tapahtumaa. Data siirtyy siis taustalla asynkronisesti häiritsemättä muun sivun toimintaa.

Pieni esimerkki voisi olla vaikkapa videogalleria, jossa käyttäjä pystyy arvostelemaan videoita. Käyttäjä voi arvostella videon (esimerkiksi napsauttamalla painiketta tai valitsemalla listasta haluamansa arvosanan) videon toiston aikana. Tällöin arvio lähetetään AJAXin avulla palvelimelle, jossa tiedon käsittelevä skripti tallentaa sen tietokantaan. Käyttäjä ei huomaa tapahtumaa, eikä videon toisto katkea, kuten kävisi, mikäli koko sivu jouduttaisiin lataamaan uudelleen.

XMLHTTPRequest-objekti

AJAXin toiminta perustuu XMLHTTPRequest-objektin käyttöön. Muiden objektien tavoin XMLHTTPRequest-objektillakin on ominaisuuksia ja metodeja. Mikäli olio-ohjelmointi ja edellä mainitut termit ovat outoja, siitä ei tarvitse tässä vaiheessa välittää. AJAXin käyttö onnistuu tulevien esimerkkien avulla ilman olio-ohjelmointitaitojakin.

Seuraavaksi käydään läpi XMLHTTPRequest-objektin tärkeimmät ominaisuudet ja metodit. Tarkempi toiminta ja tarkoitus selviävät tulevien esimerkkien kautta.

OminaisuusKuvaus
onreadystatechangeTapahtumankäsittelijä, joka kutsuu määriteltyä funktiota pyynnön suorituksen edetessä
readyStateXMLHTTPRequest-objektin tila
responseTextPalvelimelta saapunut data merkkijonona
responseXMLPalvelimelta saapunut data xml-muodossa
statusHTTP-statuskoodi (200 = pyynnön suoritus onnistunut)
statusTextHTTP-statuskoodiin liittyvä teksti, esimerkiksi virheilmoitus

readyState-ominaisuudella on viisi eri tilaa, jotka kertovat, missä vaiheessa suoritusta pyyntö on menossa. Tilat ovat 0 = objektia ei ole vielä alustettu, 1 = odottaa lataamista, 2 = pyyntö lähetetty ja latautuu, 3 = data lähetetty, prosessointi palvelimella kesken sekä 4 = valmis.

MetodiKuvaus
abort()Suoritettavan pyynnön keskeyttäminen
setRequestHeader("name", "value")Pyynnön otsikkotietojen asettaminen
getResponseHeader("name")HTTP-otsakkeen arvon palauttaminen
getAllResponseHeaders()Kaikkien HTTP-otsakkeiden arvojen palauttaminen
open("method", "URL", async)Yhteyden avaaminen (parametrit kerrottu alla tarkemmin)
send(data)Pyynnön lähettäminen palvelimelle (parametrina lähetettävä data, mikäli käytetään POST-metodia)

open-metodilla on muitakin vaihtoehtoisia parametreja, mutta kolme tärkeintä ovat taulukossa mainitut method, jolla valitaan käytettäväksi joko GET- tai POST-tyyppinen datan lähetys palvelimelle, URL, johon kirjoitetaan pyynnön vastaanottavan skriptin osoite, sekä async, jolla asetetaan asynkroninen siirto päälle (true) tai pois päältä (false).

send-metodilla lähetetään pyyntö lopulta palvelimelle. Mikäli käytetään POST-tapaa välittää tieto selaimelta palvelimelle, tulee send-metodin parametriksi lähetettävä data, muutoin null.

POST ja GET

POST ja GET ovat kaksi erilaista tapaa siirtää tietoa selaimelta palvelimelle ja myöskin päinvastoin. Käytettäessä GET-muuttujia, tieto siirtyy URL-osoitteen mukana seuraavanlaiseen tapaan: www.ohjelmointiputka.net/opas.php?tunnus=ajax, eli kysymysmerkin (?) jälkeen tulee ensimmäisen muuttujan nimi ("tunnus"), jota seuraa yhtäsuuruusmerkki (=) ja muuttujan sisältämä arvo ("ajax"). Mikäli osoitteen mukana halutaan siirtää useampia muuttujia, ne erotellaan toisistaan &-merkillä: tunnus=ajax&toinen_muuttuja=toinen_arvo.

POST-muuttujien tapauksessa tieto siirtyy HTTP-otsikkotietojen mukana, jolloin tieto ei näy käyttäjälle, toisin kuin käytettäessä GET-muuttujia. POST-muuttujia kannattaa käyttää myös, mikäli siirrettävän tiedon määrä on suurempi.

Huomaa, että AJAX-tekniikassa pyyntö palvelimelle lähetetään taustalla käyttäjän näkymättömissä, jolloin edes GET-muuttujissa välitettävät tiedot eivät näy ulospäin.

Ensimmäinen AJAX-ohjelma

Seuraavaksi tehdään vaihe vaiheelta yksinkertainen ohjelma, jossa siirretään pieni määrä tietoa selaimen ja palvelimen välillä. Esimerkissä ei ole mukana varsinaisen sivun toteutusta HTML-kielellä, vaan ainoastaan tarvittava toiminnallisuus JavaScriptillä kirjoitettuna. Koodi tulee sivun head-osioon <script type="text/javascript"></script>-tagien väliin.

Ensimmäisenä esitellään globaali muuttuja XMLHTTPRequest-objektille kaikkien funktioiden ulkopuolella, jotta se olisi käytettävissä jokaisessa funktiossa. Tämän jälkeen muuttuja alustetaan selaimelle sopivalla tavalla omassa funktiossaan.

// Esitellään muuttuja XMLHTTPRequest-objektille:
var Pyynto;

// Alustetaan Pyynto-muuttuja sopivalla tavalla riippuen käytettävästä selaimesta:
function alustaPyynto()
{
	// Jos käytettävä selain on Internet Explorer:
	if(window.ActiveXObject)
	{
		Pyynto = new ActiveXObject("Microsoft.XMLHTTP");
	}
	// Jos käytettävä selain on jokin muu, esim. Mozilla, Opera, Safari:
	else if(window.XMLHttpRequest)
	{
		Pyynto = new XMLHttpRequest();
	}
}

Edellä on siis esitelty muuttuja XMLHTTPRequest-objektille ja alustettu se selaimen edellyttämällä tavalla. Tästä eteenpäin AJAX-tekniikan käyttö on samanlaista selaimesta riippumatta. Seuraavaksi määritellään funktio varsinaisen pyynnön suorittamiselle.

// Käytetään GET-muuttujia tiedon välittämiseen palvelimelle
function suoritaPyynto()
{
	// Alustetaan ensin Pyynto-muuttuja kutsumalla edellä toteutettua funktiota:
	alustaPyynto();

	// Määritellään funktio, joka suoritetaan, kun vastaus palvelimelta on saapunut:
	Pyynto.onreadystatechange = kasitteleVastaus;

	// Käytetään GET-muuttujia tiedon lähettämiseen asynkronisesti
	// palvelimelle tarkista.php-nimiselle skriptille:
	Pyynto.open("GET", "tarkista.php?nimi=Mika", true);

	// Lähetetään pyyntö palvelimelle:
	Pyynto.send(null);
}

Huomaa, että vastauksen käsittelevän funktion nimi annetaan onreadystatechange-ominaisuudelle ilman sulkuja. Esimerkissä palvelimelle välitetään URL-osoitteen nimi-nimisessä muuttujassa Mika-merkkijono, jonka tilalla voidaan tietysti käyttää myös muuttujan nimeä: "tarkista.php?nimi=" + nimi.

Pyyntö lähetetään matkaan send-metodilla, jolle annetaan GET-muuttujia käytettäessä parametriksi null. Seuraavaksi saman funktion toteutus POST-muuttujia käytettäessä.

// Käytetään POST-muuttujia tiedon välittämiseen palvelimelle
function suoritaPyynto()
{
	// Alustetaan ensin Pyynto-muuttuja kutsumalla edellä toteutettua funktiota:
	alustaPyynto();

	// Määritellään funktio, joka suoritetaan, kun vastaus palvelimelta on saapunut:
	Pyynto.onreadystatechange = kasitteleVastaus;

	// Käytetään POST-muuttujia tiedon lähettämiseen asynkronisesti
	// palvelimelle tarkista.php-nimiselle skriptille:
	Pyynto.open("POST", "tarkista.php", true);

	// Asetetaan HTTP-otsake kertomaan sisällön tyyppi:
	Pyynto.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

	// Lähetetään pyyntö palvelimelle:
	Pyynto.send("nimi=Mika");
}

Edellisistä suoritaPyynto-funktioista toteutetaan siis vain toinen riippuen siitä, kumpaa tapaa halutaan käyttää tiedon siirtämisessä palvelimelle. POST-muuttujien tapauksessa lähetettävä data annetaan parametriksi send-metodille. Tällöin on myös asetettava HTTP-otsake "Content-Type" kertomaan, minkälaista tietoa on tulossa.

Nyt tarvitsemme vielä jotain, joka käynnistää pyynnön (kutsuu suoritaPyynto-funktiota) sekä käsittelee palvelimelta saapuvan datan. Tässä esimerkissä pyyntö käynnistetään painiketta napsauttamalla.

<input type="button" value="Tarkista nimi" onclick="suoritaPyynto()" />

Kun painiketta klikataan, siirrytään suoritaPyynto-funktioon, jossa kutsutaan XMLHTTPRequest-objektin alustavaa alustaPyynto-funktiota. Tämän jälkeen pyyntö lähetetään palvelimelle ja jäädään odottamaan vastausta. Kun vastaus saapuu, se käsitellään onreadystatechange-ominaisuudessa määritetyllä funktiolla. Funktion toteutus näkyy alla.

function kasitteleVastaus()
{
	// Tarkistetaan, onko pyyntö suoritettu kokonaan:
	if(Pyynto.readyState == 4)
	{
		// Tarkistetaan, onko pyynnön suoritus onnistunut:
		if(Pyynto.status == 200)
		{
			// Jos kaikki on kunnossa, käsitellään saapunut data:
			alert(Pyynto.responseText);
		}
		else
		{
			alert("Pyynnön suorituksessa on tapahtunut virhe!");
		}
	}
}

Funktiossa tarkistetaan ensin, onko pyyntö suoritettu kokonaisuudessaan, jolloin readyState-ominaisuuden arvoksi tulee 4. Tämän jälkeen tutkitaan, onko pyynnön suorittaminen onnistunut vai onko tapahtunut virhe. Onnistunut pyynnön suorittaminen asettaa status-ominaisuuden arvoksi 200. Sen sijaan esimerkiksi virhekoodi 404 kertoo, ettei annetusta osoitteesta löytynyt sivua (skriptiä).

Palvelimen lähettämä data saadaan poimittua esille responseText- tai responseXML-ominaisuudesta. Näistä ensimmäinen sisältää datan tekstimuotoisena, jolloin se voidaan tulostaa vaikka viesti-ikkunaan, kuten ylläolevassa yksinkertaisessa esimerkissä. Jälkimmäinen sisältää datan xml-muodossa, jolloin voidaan ottaa vastaan huomattavasti monimutkaisempia tietorakenteita. XML-datan käsittelystä on tulossa tässä oppaassa vielä oma esimerkki.

Tässä vaiheessa saattaa herätä kysymys, kuinka palvelimella oleva skripti käytännössä lähettää tietoa asiakkaalle. Se tapahtuu esimerkiksi PHP:ssä yksinkertaisesti tulostamalla echo-komennolla:

<?php echo "Tässä lähetetään tekstimuotoista dataa asiakkaalle."; ?>

Nyt responseText-ominaisuuden arvona pyynnön suorittamisen jälkeen on ylläoleva teksti.

Edellisen esimerkin myötä on käyty läpi kaikki asiat (XML-datan käsittelyä lukuunottamatta), joita tarvitaan AJAX-tekniikan hyödyntämiseksi. Kun data on vastaanotettu, sen jatkokäsittely tapahtuu muiden tekniikoiden avulla (JavaScript, DOM). Pyynnön vastaanottava skripti puolestaan toteutetaan jollain palvelinpuolen ohjelmointikielellä (esimerkiksi PHP, Perl, Python).

Voit ladata edellä läpikäydyn skriptin kokonaisuudessaan tekstitiedostona GET-muuttujia käytettäessä ja POST-muuttujia käytettäessä sekä palvelimelle tarvittavan PHP-skriptin.

XML-muotoisen datan käsittely

XML-datan käsittely tapahtuu pääosin DOM-mallin metodeja ja ominaisuuksia hyödyntämällä. Ensimmäisenä kannattaa huomata, että mikäli data otetaan vastaan palvelimelta XML-muotoisena, on palvelimella suoritettavan skriptin alussa kerrottava lähetettävän datan tyyppi. Esimerkiksi PHP-kielessä tämä tapahtuu seuraavasti.

<?php
// Asetetaan HTTP-otsake, jossa kerrotaan palvelimen selaimelle lähettämän tiedon tyyppi:
header("Content-type: text/xml");

// Tähän varsinainen skripti
?>

Lähetettävän datan on oltava XML-standardin mukaista. Alla lyhyt esimerkki XML-muotoisesta tiedosta. Tässä oppaassa ei käydä tarkemmin läpi XML:ää.

<?xml version="1.0" encoding="iso-8859-1"?>
<henkilot>
	<henkilo>
		<nimi>Aku Ankka</nimi>
		<osoite>Ankkalinna 8 A</osoite>
		<puhnro>050-123456</puhnro>
	</henkilo>
	<henkilo>
		<nimi>Iines Ankka</nimi>
		<osoite>Ankkalinna 14 B</osoite>
		<puhnro>044-901234</puhnro>
	</henkilo>
</henkilot>

XML-data muodostaa puurakenteen, jonka elementteihin pääsee käsiksi DOM-mallin metodeilla ja ominaisuuksilla. getElementsByTagName-metodilla voidaan XML-datasta poimia vaikkapa kaikki osoite-elementit taulukkoon. Jokaisella osoite-elementillä on puolestaan omat lapsisolmunsa, joihin päästään käsiksi childNodes-ominaisuuden avulla. Seuraava esimerkki havainnollistaa asiaa.

var osoitteet = Pyynto.responseXML.getElementsByTagName("osoite");
var osoite = osoitteet[0].childNodes[0].nodeValue;

alert(osoite);

Ensin kaikki osoite-nimiset elementit haetaan osoitteet-taulukkoon. Sitten osoitteet-taulukosta otetaan ensimmäinen osoite-elementti (osoitteet[0]), ja sen ensimmäinen lapsisolmu (childNodes[0]). Tämän solmun arvo "Ankkalinna 8 A" löytyy nodeValue-ominaisuudesta.

Loppusanat

AJAX itsessään ei ole kovin monimutkainen tekniikka. Käytännön sovellukset vaativat yleensä aina kuitenkin muidenkin www-tekniikoiden hyödyntämistä. Palvelimella on oltava skripti, joka ottaa pyynnön vastaan ja tekee sen edellyttämät toimenpiteet. Asiakaspuolella saapuva data on käsiteltävä halutulla tavalla - monesti tämä vaatii JavaScriptin lisäksi myös DOM-osaamista.

Lisätietoa XMLHTTPRequest-objektista tarjoaa W3C:n dokumentaatio. Lopuksi vielä linkit hieman suurempaan AJAX-esimerkkiin sekä sen lähdekoodeihin.

Esimerkki: Autokauppa

Lähdekoodit: AutokauppaEtusivu.html | autokauppa.php | luoAutoTaulu.php | lisaaAutoja.php | autot.txt

Kaikki lähdekooditiedostot ovat tekstitiedostoja. Mikäli haluat kokeilla esimerkkiä itse, muuta tiedostojen päätteet yllämainituiksi. Aluksi sinun on luotava tiedoille taulu suorittamalla luoAutoTaulu.php-skripti. Tämän jälkeen voit lisätä autojen tiedot tauluun suorittamalla lisaaAutoja.php-skripti, joka lukee autojen tiedot autot.txt-tiedostosta.

Kommentit

punppis [06.04.2008 00:12:29]

#

Kiitos tästä. Tuli tarpeeseen!

Olisi kyllä voinut kertoa, että tuo looppaa tuota kasitteleVastaus() -funktiota niin kauan, kunnes readyState on 4. Tai näin ainakin omalla testauksella ymmärsin. Ja tuohon voisi lisätä jonkin iffin, että jos ei readyState ole vielä 4, niin antaa siitä jonkun ilmoituksen, esim. "Lataan...".

Muutoin onnistunut opas.

Matso [07.04.2008 12:57:54]

#

punppis kirjoitti:

Ja tuohon voisi lisätä jonkin iffin, että jos ei readyState ole vielä 4, niin antaa siitä jonkun ilmoituksen, esim. "Lataan...".

Muutoin onnistunut opas.

if(Pyynto.readyState == 2){
  //Lataan...
}
if(Pyynto.readyState == 4){
  //Valmis
}

Eli readyState 2 tarkottaa että pyyntö lataa.

MikaBug [07.04.2008 15:35:59]

#

onreadystatechange-ominaisuudessa määriteltyä funktiota kutsutaan siis aina, kun tila muuttuu. Toki tässä funktiossa voidaan sitten tutkia myös näitä välivaiheita, mikäli on tarpeen. Mainitsin ohjeessa vain tuon tilan 4, koska se on pyynnön lähettäminen ja palvelimelta saapuvan datan vastaanottamisen kannalta oleellisin.

Davis [08.04.2008 11:54:22]

#

Hyvä opas! AJAX tosiaan on pohjimmiltaan hyvin yksinkertaista, joka ainakin itselleni tuli taannoin pienenä yllätyksenä.

php-Niko [08.04.2008 15:33:49]

#

Mainio opas! Kaiken ymmärsin oppaasta.

jmp [08.04.2008 20:15:28]

#

Hyvin kirjoitettu, voi olla hyödyllinenkin tulevaisuudessa.

Puhveli [15.04.2008 13:19:43]

#

Opettavainen ja hienosti kirjoitettu tarina, jolla oli onnellinen loppu. Liikutuin. :')

walkout_ [18.04.2008 23:02:12]

#

Hei! Viitaten uutiseen AJAX-asiaa ja miten hyödyntää esim. omilla nettisivuilla AJAXia niin katsokaa mun AJAX-nettisivut: http://mattikiviharju.name/ (nämä on koodattu kokonaan JavaScriptillä ja palvelin puoli on PHP ja MySQL).
AJAXilla on monta hyödynnystapaa mutta niiden kanssa pitää olla järkevä koska voidaan mennä metsään helpostikin koska jollain Drag & Drop -toiminolla omilla sivuilla ei ole paljon hyötyä jos asia ei ole tehty oikein.. katso Jacob Nilsenin artikkeli asiasta jossa AJAXia ei tyrmätä vaan kehotetaan käyttämään sitä oikein..

walkout_ [18.04.2008 23:11:18]

#

MikaBug kirjoitti:

"Tällä tavoin sivujen toimintaa pyritään viemään enemmän kohti tavanomaisia tietokoneohjelmia."

Joo.. siis työpöytäohjelmia koitetaan matkia ja siihen ei riitä AJAX.. vaan pitää tehdä JavaScriptillä käyttöliittymiä jotka muistuttaa perinteisiä tietokone ohjelmia. AJAX on vain väline millä haetaan data käyttöliittymään ja ilman AJAXia ollaan heikoilla..

walkout_ [18.04.2008 23:24:19]

#

Mitä tulee AJAX-ohjelmien tietoturvaan?? No jos ohjelma on koodattu kokonaan JavaScriptillä niin kun uloskirjautumisen jälkeen painaa backnappia niin sama ladattu data näkyy mutta ei ehkä toimi pidemmälle..
Normaaleissa perus WWW-ohjelmissa on helppoa koodata systemi niin että backnapilla ei pääse enää uloskirjautumisen jälkeen dataan joka on nähtävissä vain käyttäjätunnuksilla ja salasanalla..
En tiedä miten ongelma korjataan AJAX-ohjelmissa..

makas [22.05.2008 00:08:12]

#

Itekkö oot koodannu tuon kotisivusi käyttöliittymän walkout? Tosi hieno on kyl..

oipat [16.07.2008 19:47:00]

#

Autokauppa esimerkissä pieni bugi. Autokauppa.php:n kyselyssä haetaan tietoa hkl_lkm sarakkeesta, mutta luoAutoTaulu.php:ssä ei luoda tämän nimistä saraketta.

Pollapoju [19.07.2008 12:46:03]

#

Puhveli kirjoitti:

Opettavainen ja hienosti kirjoitettu tarina, jolla oli onnellinen loppu. Liikutuin. :')

XD

MikaBug [20.07.2008 14:22:27]

#

Nyt hkl_lkm-sarake on poistettu kyselystä. Oli jäänyt aiemmasta versiosta kummittelemaan.

Alpo-setä Utajärveltä [30.07.2008 20:55:04]

#

"Mikäli osoitteen mukana halutaan siirtää useampia muuttujia, ne erotellaan toisistaan &-merkillä: tunnus=ajax&toinen_muuttuja=toinen_arvo."

Tuo ei toimi ihan sellaisenaan vaan lähettää vain ensimmäisen muuttujan arvon ainakin jos lähetettävän tiedon arvo on muuttujassa (alla esimerkissä ne jäljemmät myvalue1 ja myvalue2.)

Huomasin kokeiltuani, että merkkaus kuuluu tehdä näin:

tietohommeli.send("myvalue1="+myvalue1+"&myvalue2="+myvalue2);

Huomaa siis lainausmerkkien, =, + ja & -merkkien järjestys.

Sitten tulee vielä se merkistöongelma tietoa kirjoitettaessa ja lukiessa. Näkyy olevan, että ajaxilla (tiedostosta) tuotu teksti ei muutu mutta ainakin lomakkeelta lähetettäessä se muuttuu UTF:ksi. Javascriptin merkistö ei ole syypää eli sen säätäminen ei auta.

Ps. Muuten opas oli hyvä ja hyödyllinen ja pääsin ajaxiin kiinni saman tien.

Alpo-setä Utajärveltä [30.07.2008 21:41:10]

#

ValkoNaama [21.06.2009 13:43:30]

#

Hyvä opas.

Minulle jäi hieman epäselväksi miten tuo xml:llän käyttö onnistuu.

Täytyykö xml tiedosto ladata, vai miten se otetaan esille palvelimella olevassa php:ssä?

Ja ilmeisesti nuo .responseText pitää muuttaa .responseXML komennoiksi?

MikaBug [21.06.2009 14:08:37]

#

Hyviä huomioita, voisi olla paikallaan vähän täydentää opasta. Kiva, jos siitä on kuitenkin ollut hyötyä. :)

XML-muotoista dataa voi lähettää php:stä esimerkiksi seuraavasti:

echo "<kirjat><kirja><nimi>PHP:n perusteet</nimi><vuosi>2008</vuosi></kirja></kirjat>";

Kun asiakasohjelma eli selain ottaa tuon vastaan, se pitää tosiaan lukea responseXML-ominaisuudesta responseText-ominaisuuden sijaan. Tämän jälkeen dataa voidaan käsitellä JavaScriptillä DOM-mallin mukaisesti, esim. getElementsByTagName()-metodilla, jolla saadaan poimittua vaikkapa kaikki <kirja>-elementit taulukkoon.

Kuten oppaassakin mainitaan, on lähetettävän datan tyyppi mainittava, joka php:ssä tapahtuu seuraavasti:

header("Content-type: text/xml");

Eli tuollainen koodirivi ennen varsinaisen xml-datan "tulostamista" echolla. Tietysti php:ssä voi xml-tiedon lukea vaikkapa jostain ulkopuolisesta xml-tiedostosta ja tulostaa tämän echo-komennolla, jolloin se löytyy responseXML-ominaisuudesta.

ValkoNaama [23.06.2009 21:23:10]

#

Jep mä ainakin olisin kovin tyytyväinen jos joku viitsisi tehdä lisäyksiä XMLää ajatellen.

Hieman olen nyt tapellut tuon kanssa. Mitenkä jos on isoja määriä XML tageja kannattaako ne liittää for lauseella sivuille?

MikaBug [24.06.2009 11:58:13]

#

Silmukallahan niitä suurempia xml-määriä kannattaa generoida. Jos on vaikkapa kaksiulotteinen taulukko, johon on sijoitettu henkilöiden tietoja (tiedot tulleet esim. tietokannasta), voi niistä muodostaa xml-rakenteen seuraavankaltaisella tavalla:

/* Kaksiulotteinen taulukko, joka sisältää useiden henkilöiden tietoja muodossa $henkilot[0]['etunimi'] = ensimmäisen taulukkoon tallennetun henkilön etunimi.*/
$henkilot;

// Tulostetaan xml-rakenteen aloittava elementti:
echo "<henkilot>";

// Käydään läpi henkilot-taulukon jokainen henkilö:
foreach($henkilot as $henkilo)
{
echo "<henkilo>"
echo "<etunimi>" . $henkilo['etunimi'] . "</etunimi>";
echo "<sukunimi>" . $henkilo['sukunimi'] . "</sukunimi>";
echo "<ika>" . $henkilo['ika'] . "</ika>";
echo "</henkilo>";
}

echo "</henkilot>";

Tässä esimerkissä ei siis näytetä, kuinka henkilöiden tiedot $henkilot-taulukkoon haetaan, vaan oletetaan, että sieltä löytyy tiedot ylläolevan mallin mukaisesti. Ensimmäisen taulukon solut (joihin viitataan kokonaislukuindeksillä) sisältävät assosiatiivisen taulukon, jossa avaimina ovat esim. 'etunimi', 'sukunimi' ja 'ika'. Nämä avaimet taas viittaavat varsinaisiin tietoihin. Tämä on tapa jota itse käytän, jos vaikkapa on luokka "Kayttajat", jolla on palvelu "HaeKayttajat()", joka suorittaa tietokantakyselyn ja palauttaa sitten kyselyn tuloksen tuollaisessa kaksiulotteisessa taulukossa. Taulukon voi sitten käydä läpi kutsuneessa ohjelmassa ja vaikkapa tulostaa sivulle tai muodostaa siitä xml-rakenteen kuten edellä. Ei varmastikaan paras tapa mutta toimiva.

Toinen vaihtoehto olisi palauttaa esim. Henkilo-olioita sisältävä taulukko, jossa oliot sisältäisivät yksittäisen henkilön tiedot. Tämä tosin vaatii jo ainakin jonkinlaiset olio-ohjelmointitaidot.

ValkoNaama [24.06.2009 18:57:27]

#

Eli siis tässä tapauksessa vastaus tulee teksti muodossa? Ja silloin JavaScriptin ei tarvitse sitä käsitellä?

Mitenkä nämä saadaan sijoittumaan vaikka taulukon sisälle? Eikös taulukkokin pitäisi tehdä siinä samalla? Jolloin ajattelisin että lähetetään vastauksena html:ää tekstinä?

Vielä miten se XML kannattaa sinne lukea? Kannattaako se lukea DOM kirjaston avulla vai ihan load käskyllä? Onko sillä aroa?

Erittäin hyviä vastauksia olen sinulta saanut. Näistä saan varmasti rankenneltua hienon koodin. Muita ajatellen olisi näpsäkkää raknetaa näistä vaikka oma oppaansa? Voisi se minullekkin aukaista vielä jotain uutta.

MikaBug [24.06.2009 20:47:53]

#

Tuon ylläolevan esimerkin tapauksessa tieto on nimenomaan xml-muodossa, ja se otetaan selaimessa vastaan responseXML-ominaisuudesta. :) Tokihan se löytyy myös responseText-ominaisuudesta, mutta jos sitä aikoo käsitellä JavaScriptillä DOM-metodeita käyttäen, on käytettävä tuota ensimmäistä ominaisuutta. PHP-skriptin alkuun on myös muistettava laittaa koodirivi, joka kertoo selaimelle saapuvan datan tyypin:

header("Content-type: text/xml");

Eli tuo vaikkapa ensimmäiseksi riviksi php-skriptiin ennen echotuksia. Kun XML-data saapuu selaimeen, löytyy se siis responseXML-ominaisuudesta. Tästä datasta sitten voi hakea vaikkapa ensimmäisen henkilön etu- ja sukunimen ja iän käyttämällä JavaScriptin DOM-mallin käsittelyyn tarkoitettuja metodeita. DOM-mallin käytöstä on oma oppaansa täällä Ohjelmointiputkassa. Jos palvelimelta vastaanotetuista tiedoista haluaa nettisivulle esim. taulukon, on taulukko luotava käytännössä dynaamisesti DOMin avulla. Eli createElement() ym. metodeita käyttäen.

Yksi AJAX-tekniikan käytön vaikeuksista on juuri se, että jotta tekniikkaa voisi kunnolla hyödyntää, on melkein pakko osata jonkin verran myös DOM-mallin muokkausta JS:n avulla, jotta nettisivua pystyy dynaamisesti muuttamaan palvelimelta saapuneen datan mukaan.

Minullekaan DOM ei ole vielä kovin tuttua, joten viisaammat saavat ilomielin antaa parempia vinkkejä tähän. :D

B_R_H [13.07.2009 10:47:35]

#

Kiitokset hienosta artikkelista ja hyvistä esimerkeistä. Luulinkin AJAXin olevan jotakin "uutta ja hankalaa", mutta ei!

Wabbit [25.10.2009 22:02:15]

#

Hyvin kirjoitettu!!!!

Mää useasti teen näin:

itse javascript:

function Ahah(url, target, busy,noReturnValue)
{
    inProcessMode = setTimeout("AhahWorking('"+busy+"')",500);
    var self=this;
    // Mozilla/Safari
    if (window.XMLHttpRequest) {
        self.xmlHttpReq = new XMLHttpRequest();
    }
    // IE
    else if (window.ActiveXObject) {
        self.xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
    }
    var url = url;

    self.xmlHttpReq.onreadystatechange = function() {
        if (self.xmlHttpReq.readyState == 4) {
            clearTimeout(inProcessMode);
            if (!noReturnValue) {
                target.innerHTML = self.xmlHttpReq.responseText;
            }
            else {
                target.innerHTML = '';
            }

            document.body.style.cursor = "";
            var element = document.getElementById(busy);
            element.style.display = "none";
            clearTimeout(inProcessMode);
        }
    }
    self.xmlHttpReq.open('GET', url, true);
    self.xmlHttpReq.send("");

    var element = document.getElementById(busy);
    doPopupResize();
}

function Ajax(url, target, busy)
{
    inProcessMode = setTimeout("AhahWorking('"+busy+"')",1500);

    var self=this;
    // Mozilla/Safari
    if (window.XMLHttpRequest) {
        self.xmlHttpReq = new XMLHttpRequest();
    }
    // IE
    else if (window.ActiveXObject) {
        self.xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
    }
    var url = url;

    self.xmlHttpReq.open('GET', url, false);
    self.xmlHttpReq.send("");

    if(self.xmlHttpReq.responseText != 'false')
    {
        clearTimeout(inProcessMode);
        var element = document.getElementById(busy);
        element.style.display="none";
    //    target.innerHTML = self.xmlHttpReq.responseText;
    }
    doPopupResize();
}


function AjaxPost(url, data, busy)
{
    inProcessMode = setTimeout("AhahWorking('"+busy+"')",1500);

    var self=this;
    // Mozilla/Safari
    if (window.XMLHttpRequest) {
        self.xmlHttpReq = new XMLHttpRequest();
    }
    // IE
    else if (window.ActiveXObject) {
        self.xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
    }
    var url = url;

    self.xmlHttpReq.open('POST', url, false);
    self.xmlHttpReq.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8");//;charset=iso-8859-1");
    self.xmlHttpReq.setRequestHeader("Content-length", data.length);
    self.xmlHttpReq.send(data);

    if(self.xmlHttpReq.responseText != 'false')
    {
        clearTimeout(inProcessMode);
        var element = document.getElementById(busy);
        element.style.display="none";
    //    target.innerHTML = self.xmlHttpReq.responseText;
    }
}

function AhahWorking(busy){
    var element = document.getElementById(busy);
    element.style.display = 'block';
}

eli saa semmoisen hyrrän joka pyörii

Wabbit [25.10.2009 22:05:36]

#

Walkout, vaikka painat back - nappia niin et enään saa kiini siihen scriptiin eli pääsivu--- AJAX ikkuna -- tee jotain kivaa (pää scrippti) jos teet sen oikein

Tuoppia [27.11.2010 20:58:41]

#

Loistavaa, kiitokset oppaasta!

HTML5 [11.05.2013 22:01:17]

#

Kiitos oppaasta!
Tämähän on ihan mahdottoman helppoa ja avaa paljon lisää mahdollisuuksia sivujen toteutukseen.

HTML5 [12.05.2013 23:20:16]

#

lainaus:

XMLHTTPRequest-objekti on keskeinen asia AJAX-tekniikan käytössä, mutta se ei valitettavasti ole standardin mukainen.

XMLHttpRequest on nykyään W3C:n standardi: http://www.w3.org/TR/XMLHttpRequest/
Siitä on olemassa myös toinen versio: http://www.w3.org/TR/XMLHttpRequest2/

Kirjoita kommentti

Huomio! Kommentoi tässä ainoastaan tämän oppaan hyviä ja huonoja puolia. Älä kirjoita muita kysymyksiä tähän. Jos koodisi ei toimi tai tarvitset muuten vain apua ohjelmoinnissa, lähetä viesti keskusteluun.

Muista lukea kirjoitusohjeet.
Tietoa sivustosta