Visning af tilfældigt valgt fra liste





Hvad går det ud på?

Man kan være interesseret i at lave en liste, hvor der bliver vist et tilfældigt billede eller link, eller noget helt tredje, ved en eller anden event. Det kunne f.eks. være film man anbefaler, som jeg har lavet på sitet WeirdSpace.info, hvor der vises et tilfældigt billede og link fra en liste, når siden åbnes eller opdateres. Det er et af den slags små effekter, som kan live lidt op på en side med statisk indhold.

En sådan løsning består af to dele, en liste og en selector til tilfældig udvælgelse. Til små lister, vil man ofte gøre det i ét JavaScript. Er listen meget lang, kan man med fordel lægge den ud som en separat fil, f.eks. en XML-database. Begge dele bliver gennemgået.


Liste og selector i ét

Det første man laver med liste og selector i et er selve listen. Her kalder vi vores punkter på listen images, og disse gives et fortløbende nummer, startende med nul, dvs. første punkt hedder images[0], andet punkt images[1], osv. Til denne demo er hvert punkt en HTML-kode for et link med et billede. Før listen, deklarerer man, at images er en liste med Array(). Grunden til at man starter med images[0] i stedet for images[1] kommer af kommandoen for randomisering, og bliver gennemgået lige om lidt.

Som kode ser listen således ud:

images = new Array();

images[0] = "<A HREF = 'https://weirdspace.info/…/Tangled_2010.htm'><IMG SCR='https://weirdspace.info/…/Tangled_2010.jpg' STYLE='float:none; margin-left:20px'></A>";

images[1] = "<A HREF = 'https://weirdspace.info/…/TheDeep_1977.htm'><IMG SCR='https://weirdspace.info/…/TheDeep_1977.jpg' STYLE='float:none; margin-left:25px'></A>";



images[15] = "<A HREF = 'https://weirdspace.info/…/NightAtTheMuseumIII_2014.htm'><IMG SCR='https://weirdspace.info/…/NightAtTheMuseumIII_2014.jpg' STYLE='float:none; margin-left:25px'></A>";

images[16] = "<A HREF = 'https://weirdspace.info/…/TheyDriveByNight_1940.htm'><IMG SCR='https://weirdspace.info/…/TheyDriveByNight_1940.jpg' STYLE='float:none; margin-left:25px'></A>";


Stierne til link og billeder er forkortede af hensyn til overskueligheden af eksemplet. I den rigtige kode har man selvfølgelig den fulde sti angivet.

JavaScript kan kun lave randomisering af tal med Math.random(), som vælger et tilfældigt tal i intervallet nul til et, hvor 0 er med og 1 er ikke med. Matematisk skriver man det således [0 ; 1[. Nu skal vi imidlertid bruge et valg i intervallet nul til 16, og det gør vi ved at gange det tal der kommer fra Math.random() med antallet af punkter i listen. Fordi vi har defineret images som et array, kan vi finde antallet af punkter på listen med .length, dvs. images.length. Man kan selvfølgelig også skrive tallet, men så skal man også huske at justere koden her, hver gang man tilføjer eller fjerner punkter. Der er mindre bøvl med opdatering af kode med images.length, så den er løsning er klart at anbefale.

Ved det med antallet skal man være lidt opmærksom på hvad man laver. Der er 17 punkter, så ved at gange Math.random() med images.length, dvs. Math.random() * images.length, får man en række tal fra og med nul og til lige under 17. Alle numrene på images er heltal, så det nytter ikke noget med diverse kommatal. Heltal får man ved at runde af. Med JavaScript kan man runde af med floor(), som altid runder ned, ceil() (en forkortelse for ceiling), som altid runder op, og round(), som runder op eller ned afhængig af decimalerne. Her vælger vi floor(), dvs. Math.floor(), fordi så rundes der altid ned. For 17 punkter, vil beregningen så altid give et heltal i intervallet fra og med nul og til og med 16.

Den beregnede værdi kalder vi her for RandomNumber, og beregningen kommer til at se således ud:

RandomNumber = Math.floor(Math.random() * images.length);

Nu skal vi have det tilfældige tal RandomNumber omsat til at at man den HTML-kode der hører til tallet. Det ser således ud:

document.write(images[RandomNumber]);


Den samlede kode bliver så:

images = new Array();

images[0] = "<A HREF = 'https://weirdspace.info/…/Tangled_2010.htm'><IMG SCR='https://weirdspace.info/…/Tangled_2010.jpg' STYLE='float:none; margin-left:20px'></A>";

images[1] = "<A HREF = 'https://weirdspace.info/…/TheDeep_1977.htm'><IMG SCR='https://weirdspace.info/…/TheDeep_1977.jpg' STYLE='float:none; margin-left:25px'></A>";



images[15] = "<A HREF = 'https://weirdspace.info/…/NightAtTheMuseumIII_2014.htm'><IMG SCR='https://weirdspace.info/…/NightAtTheMuseumIII_2014.jpg' STYLE='float:none; margin-left:25px'></A>";

images[16] = "<A HREF = 'https://weirdspace.info/…/TheyDriveByNight_1940.htm'><IMG SCR='https://weirdspace.info/…/TheyDriveByNight_1940.jpg' STYLE='float:none; margin-left:25px'></A>";

RandomNumber = Math.floor(Math.random() * images.length);

document.write(images[RandomNumber]);

Koden som den er lavet her, skal gemmes i en separat fil, vi kalder den MovieRecommendations.js og gemmer den i directoriet JavaScripts. Vi kan nu kalde filen fra der hvor vi vil have billede og link vist på siden. Koden man skriver, der hvor man vil have billede og link, er:

<SCRIPT TYPE="text/javascript" SRC="JavaScripts/MovieRecommendations.js"></SCRIPT>


På skærmen kommer det til at se således ud (prøv at opdatere siden med F5):




Separat liste og selector

Skal man have en separat liste, skal denne have en fast struktur. Til dette eksempel bruger vi en XML-database, men det kunne lige så godt være en Access-database eller en kommasepareret fil.

Vi starter med at lave en XML-database. Filen kalder vi Jokes.xml, og strukturen ser således ud:

<?xml version="1.0" encoding="UTF-8"?>
<Jokes>

<Joke>
<text_string><![CDATA[PÅ POSTHUSET<BR>
- Jeg vil gerne indlevere disse 5000 Valentine's kort.<BR>
- Hvorfor sende så mange?<BR>
- Jeg er skilsmisseadvokat.]]></text_string>
</Joke>

<Joke>
<text_string><![CDATA[I en baggård på Nørrebro, løber lille Peter rundt og leger vildt fægtende med sit lille træsværd. Hans mor kommer forbi og hører ham:<BR>
- Menstruation, menstruation, menstruation!<BR>
- Jamen, Peter, det hedder da ikke menstruation, det hedder revolution.<BR>
- Nå... men jeg er da ligeglad, jeg vil se blod!]]></text_string>
</Joke>



<Joke>
<text_string><![CDATA[INDIANER HOS LÆGEN<BR>
- Er De blevet undersøgt af andre?<BR>
- Ja, af landsbyens medicinmand.<BR>
- Og hvilket tåbeligt råd gav den jubelnar af en heksedoktor Dem så?<BR>
- At jeg skulle konsultere Dem.]]></text_string>
</Joke>

<Joke>
<text_string><![CDATA[Hvad er forskellen mellem en luder, en nymfoman og en blondine?<BR>
- Luderen siger: "Er du ikke snart færdig?"<BR>
- Nymfomanen siger: "Er du allerede færdig?"<BR>
- Blondinen siger: "Beige! Jeg tror, jeg vil male loftet beige!"]]></text_string>
</Joke>

</Jokes>


Det første der skal til for at kunne anvende en ekstern lister, er i sagens natur at få adgang til den. Til dette bruger vi scriptet loadXMLDoc. Hvordan det er konstrueret, kan man se her (Husk at indlæse scriptet i sidens HEAD-tag, som beskrevet). Her ligger filen Jokes.xml i samme directory som HTML-filen, og så kommer første linje til at se således ud:

<SCRIPT TYPE="text/javascript">
xmlDoc=loadXMLDoc("Jokes.xml");

</SCRIPT>


Vi har nu fat i filen, så det næste vi gør er at få fat i de enkelte vittigheder. Dette gør vi med en variabel, Joke_lmnt, hvis værdier hentes med getElementsByTagName(). Her er det tag'en text_string der indeholder de enkelte vittigheder.

Vi får også brug for at kende antallet af vittigheder i filen, så vi ved i hvilket interval vi skal vælge et tilfældigt tal. Man kan selvfølgelig tælle dem op, men så skal man rette i JavaScriptet hver gang man tilføjer eller fjerner noget fra listen. I stedet bruger vi kommandoen .length på antallet af elementer i variablen Joke_lmnt.

Så ser koden således ud:

<SCRIPT TYPE="text/javascript">
xmlDoc=loadXMLDoc("Jokes.xml");

var Joke_lmnt = xmlDoc.getElementsByTagName("text_string");
AntalElementer = Joke_lmnt.length;

</SCRIPT>


Vi skal nu have valgt et tilfældigt tal. Det skal være et heltal, og spændet der vælges i skal være det samme som antallet af punkter på listen, dvs. vittigheder. Kommandoen Math.random() klarer valget for et tilfældigt tal i intervallet [0 ; 1[, og ved at gange med antallet af punkter, som vi har fundet med Joke_lmnt.length (sådan her: Math.random() * Joke_lmnt.length), vil de mulige tilfældige tal ligge i et interval, svarende til antallet af punkter/vittigheder.

Listen, når den laves med getElementsByTagName(), starter med nummer 0, dvs. er der 10 punkter/vittigheder, har de numrene 0 til 9 og ikke 1 til 10. Beregningerne ved Math.random() * Joke_lmnt.length giver kommatal, og vi skal kun bruge heltal, så vi skal afrunde. For at det kommer til at passe, runder vi ned på alle tallene med Math.floor(), så vi starter med 0 og længden svarer til antallet af punkter/vittigheder. Så ser det således ud:

<SCRIPT TYPE="text/javascript">
xmlDoc=loadXMLDoc("Jokes.xml");

var Joke_lmnt = xmlDoc.getElementsByTagName("text_string");
AntalElementer = Joke_lmnt.length;
RandomNumber = Math.floor(Math.random() * Joke_lmnt.length);

</SCRIPT>


Vi skal nu have en rutine der henter vittigheden der har det nummer i rækken, som lige er blevet genereret. Det gør man ved at gå gennem listen, med en for-sætning, der starter ved 0 og går gennem tallene op til det maksimale antal punkter/vittigheder. Når man kommer til det tal i rækken, som er det sammen som det tilfældigt valgte tal, dvs. i==RandomNumber (bemærk at der skal være to lighedstegn), skriver den punktet/vittigheden med en document.write(). I modsat fald, skal den ikke gøre noget.

For ikke at have teksten til at stå og flagre midt i det hele, sætter vi den ind i en DIV med document.write() før og efter. Så ser den færdige kode således ud:

<SCRIPT TYPE="text/javascript">
xmlDoc=loadXMLDoc("Jokes.xml");

var Joke_lmnt = xmlDoc.getElementsByTagName("text_string");
AntalElementer = Joke_lmnt.length;
RandomNumber = Math.floor(Math.random() * Joke_lmnt.length);

document.write("<DIV>");
   for (i = 0; i < AntalElementer; i++)
      if (i==RandomNumber) {
         document.write(Joke_lmnt[i].firstChild.nodeValue);}
      else { }
document.write("</DIV>");
</SCRIPT>


På skærmen kommer det til at se således ud (prøv at opdatere siden med F5):



I dette eksempel er koden lavet til at være skrevet direkte på siden. Vil man i stedet gerne have den som et eksternt script, som i det foregående eksempel, kan man bare gøre dette.


Hvis man skal bruge flere tilfældige værdier

Man kan være i den situation, at man gerne vil have to eller flere tilfældige værdier. Hvis værdierne gerne må være ens, kan man bare lave kopier af variablen RandomNumber og kalde dem noget andet. Det er man imidlertid ikke altid interesseret i, og så må man lægge et loop ind der håndterer dette.

I praksis gør man det, at man starter med at generere to tilfældige tal, som i de foregående afsnit. Her kalder vi dem RandomNumber1 og 2.

Herefter laver vi et loop med while. Vi tester for om RandomNumber1 og 2 er ens (RandomNumber2 == RandomNumber1, bemærk der er 2 lighedstegn). Så længe RandomNumber1 og 2 er ens, skal den gentage genereringen af RandomNumber2.

Så ser kodestykket således ud:

<SCRIPT TYPE="text/javascript">
var Joke_lmnt = xmlDoc.getElementsByTagName("text_string");
RandomNumber1 = Math.floor(Math.random() * Joke_lmnt.length);
RandomNumber2 = Math.floor(Math.random() * Joke_lmnt.length);

while (RandomNumber2 == RandomNumber1) {
   RandomNumber2 = Math.floor(Math.random() * Joke_lmnt.length);
   }

</SCRIPT>


Herfra kan man så hente elementer eller hvad man nu vil bruge de to tal til.