jQuery:n käyttö dynaamisesti ladatun sisällön kanssa

 

jquery-selectorsEri selaimien ja selainversioiden kanssa tapellessa jQuery helpottaa Front-end-koodarin elämää valtavasti. jQuery on suuri tuskan poistaja esimerkiksi Ajax:in kanssa temppuillessa, mutta silti on vielä joitakin sudenkuoppia, mitä sivunrakentajan on syytä varoa.

Tämä opas on henkinen jatko-osa jutulle nimeltään Ajax:in alkeet jQueryn avulla. Demosivu muistuttaa pitkälti edelliskertaista sivua, mutta joitakin muutoksia on tullut:

 

01.<!DOCTYPE html>
02.<html lang="fi">
03. 
04.<head>
05.<meta charset=utf-8>
06.<title>Otsikko</title>
07. 
08.<script src="http://www.google.com/jsapi"></script>
09.</head>
10. 
11.<body>
12. 
13.<h1>Otsikko</h1>
14. 
15.<ul id="navigointi">
16.<li><a id="etusivu" href="#">Etusivu</a></li>
17.<li><a id="uutiset" href="#">Uutiset</a></li>
18.<li><a id="yhteystiedot" href="#">Yhteystiedot</a></li>
19.</ul>
20. 
21.<div id="sisalto">
22. 
23.</div>
24. 
25.</body>
26.</html>

Nyt navigointilinkit eivät johda mihinkään ja sivun varsinainen sisältö on poistettu, sillä tulemme hoitamaan tämän kaiken jQueryn ja Ajaxin avulla. Näinhän ei tietenkään oikealla sivulla koskaan tulisi toimia, mutta jotta juttumme pääasia tulisi mahdollisimman selväksi, oiotaan mutkia tältä osin hiukan.

Kaikki sisältö on siirretty yhteen dokumenttiin nimeltään ajax.html, jotta jatkossa osioiden käsittely jQueryllä olisi hiukan helpompaa. Heitetään soppaan vielä mukaan pieni kuvagalleria jokaiselle osiolle:

ajax.html:

01.<div id="etusivu">
02.<h2>Etusivun jutut</h2>
03. 
04.<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua...</p>
05. 
06.<ul id="kuvalinkit">
07.<li><a href="#" class="kuva1">Kuva 1</a></li>
08.<li><a href="#" class="kuva2">Kuva 2</a></li>
09.<li><a href="#" class="kuva3">Kuva 3</a></li>
10.</ul>
11. 
12.<div id="galleria">
13.<div class="kuva1"></div>
14.<div class="kuva2"></div>
15.<div class="kuva3"></div>
16.</div>
17.</div>
18. 
19.<div id="uutiset">
20.<h2>Uutiset</h2>
21. 
22.<p>Päivän tärkeimmät tapahtumat.</p>
23. 
24.<ul id="kuvalinkit">
25.<li><a href="#" class="kuva1">Kuva 1</a></li>
26.<li><a href="#" class="kuva2">Kuva 2</a></li>
27.<li><a href="#" class="kuva3">Kuva 3</a></li>
28.</ul>
29. 
30.<div id="galleria">
31.<div class="kuva1"></div>
32.<div class="kuva2"></div>
33.<div class="kuva3"></div>
34.</div>
35.</div>
36. 
37.<div id="yhteystiedot">
38.<h2>Yhteystiedot</h2>
39. 
40.<p>Osoite, puhelinnumero yms...</p>
41. 
42.<ul id="kuvalinkit">
43.<li><a href="#" class="kuva1">Kuva 1</a></li>
44.<li><a href="#" class="kuva2">Kuva 2</a></li>
45.<li><a href="#" class="kuva3">Kuva 3</a></li>
46.</ul>
47. 
48.<div id="galleria">
49.<div class="kuva1"></div>
50.<div class="kuva2"></div>
51.<div class="kuva3"></div>
52.</div>
53.</div>

Galleriat sisältävät kolme ”kuvaa” jotka tulevat päivittymään #sisalto-divin sisällä dynaamisesti käyttäjän klikkaillessa kuvalinkkejä. Tässä esimerkissä simuloimme kuvia tyhjillä diveillä. Kuvat on oletuksena piilotettu näkyvistä display: none; -määreellä.

Kirjoitetaan navigoinnista vastaava jQuery uusiksi:

01.google.load("jquery", "1.4.2");
02.google.setOnLoadCallback(function() {
03. 
04.// Ladataan etusivun sisällöt näkyviin
05.$('#sisalto').load('ajax.html #etusivu');
06. 
07.// Vaihdetaan näkymää klikatun linkin mukaan
08.$('#navigointi a').click( function() {
09. 
10.$('#sisalto').load('ajax.html #' + $(this).attr('id'));
11. 
12.return false;
13. 
14.});
15. 
16.});

Ensimmäinen jQuery-loitsu on varmaankin aika selvä. Toisessa pätkässä lataamme klikatun linkin id:tä vastaavan div:in ajax.html:stä.

Seuraavaksi voimmekin jatkaa edellisen perään galleriamme toiminnallisuus. Logiikka on pitkälti sama, kuin aiemminkin:

01.google.load("jquery", "1.4.2");
02.google.setOnLoadCallback(function() {
03. 
04.// Ladataan etusivun sisällöt näkyviin
05.$('#sisalto').load('ajax.html #etusivu');
06. 
07.// Vaihdetaan näkymää klikatun linkin mukaan
08.$('#navigointi a').click( function() {
09.$('#sisalto').load('ajax.html #' + $(this).attr('id'));
10.return false;
11.});
12. 
13.// Avaa klikattu kuva ja piilota edellinen
14.$('#kuvalinkit a').click( function() {
15. 
16.$('#galleria .' + $(this).attr('class')).show('slow')
17..siblings()
18..hide('slow');
19. 
20.return false;
21. 
22.});
23.});

Kaiken järjen mukaan edellisen koodin pitäisi toimia aivan kuten navigoinninkin, mutta klikatessa kuvalinkkejä kuvat eivät kuitenkaan aukea. Mitä oikein tapahtui?

Ken vanhoja muistaa, sitä tikulla silmään

Kun selain on saanut ladattua sivun rakenteen, DOM:in, jQuery käy sen läpi ja lisää mm. klikkausten tapahtumakäsittelijät (click event handlers) vaadituille elementeille, meidän tapauksessamme kuvalinkeille. Kun lataamme Ajax-kutsulla #sisalto-diviin jonkin sisältönäkymistä, muokkaamme tätä rakennetta jälkeenpäin. jQuery ja JavaScript ovat tällä hetkellä hieman ulalla, sillä kukaan ei ole kertonut heille, että sivuilla on jotain tapahtunut. Meidän täytyy siis kertoa JavaScriptille jotenkin, että sivu on päivittynyt ja sen täytyy ottaa huomioon myös uusi sisältö.

Kun ei homma itseltä onnistu, delegoidaan

jQueryn tuorein päivitys, 1.4.2, toi mukanaan uuden .delegate()-metodin, jolla saamme ongelmamme ratkaistua. Delegate-metodin toimintaperiaate ei välttämättä aukea aivan heti kaikille joten otetaanpa alkuun pieni annos JavaScriptin teoriaa:

Tapahtumien kupliminen, tai event bubbling, on olennainen osa koko JavaScriptin filosofiaa. Kun käyttäjä klikkaa elementtiä sivuilla, alkaa taustalla erikoinen tapahtumaketju. Katsotaan vaikka esimerkiksi demosivumme linkkilistaa: Klikatessa linkkiä listassa, laukeaa klikkaustapahtuma tässä kyseisessä HTML-elementissä. Tämän jälkeen linkkielementti ”mainostaa” tätä tapahtumaa isäntänään olevalle LI-elementille. LI-elementti taas heittää tämän viestin ylöspäin UL-elementille ja näin jatketaan ylöspäin aina dokumenttipuun alkuun asti, ellei kuplimista jostain syystä erityisesti haluta katkaista.

Delegate-metodin temppuna on hakea jokin ylempi elementti sivuilta ja sitoa kuplimisen kautta jonkin alempana dokumenttipuussa olevan elementin tapahtuma, tässä tapauksessa klikkaus, siihen. Jotta saisimme delegate-metodin käyttöömme, pitää meidän valita sivuilta jokin kaikille linkeille yhteinen elementti, jota ei päivitetä Ajax-kutsuja tehdessä. Body on useasti aika varma valinta. Käytämme body:a hyväksemme kierrättämällä klikkaustapahtumat sen kautta ja delegoimme tapahtumat alaspäin uusille, Ajax:lla tuoduille elementeille.

Muutetaan alkuperäisiä kuvanvaihtolinkkiemme tapahtumakäsittelijöitä hiukan niin, että otamme delegate-metodin mukaan leikkeihin:

1.// Avaa klikattu kuva ja piilota edellinen
2.$('body').delegate('#kuvalinkit a', 'click', function() {
3.$('#galleria .' + $(this).attr('class')).show('slow')
4..siblings()
5..hide('slow');
6.return false;
7.});

Nyt kuvalinkit pelaavat kaikissa alinäkymissä kauniisti. Olisimme voineet sitoa delegoinnin myös lähemmäksi kuvalinkkejä demosivullamme, esimerkiksi #sisalto-diviin, mutta suorituskyvyllisesti tällä ei näin pienessä demossa ole merkitystä.

Mitä suuremmaksi Ajax-projektit kasvavat, sitä arvokkaammaksi suorituskyvyn parantajaksi delegate nousee. Vanhemmissa jQuery-versioissa käytetty live()-metodin perusidea on pitkälle sama, kuin delegatella, mutta se sitoo tapahtumakäsittelijät aina dokumentin alkuun. Delegatella voimme sitoa klikkausten seurannan mahdollisimman lähelle klikkauksen alkujuuria ja näin vähentää selaimen taakkaa JavaScriptin käsittelyssä.

Leave a Reply

Your email address will not be published. Required fields are marked *