Javascript deel 3 Document Object Model Objecten
Document Object Model (DOM) Doel: via javascript willen we graag heel flexibel de htmlpagina kunnen aanpassen. HTML DOM is een standaard waarmee we html-elementen uit de webpagina kunnen opvragen, wijzigen, toevoegen of verwijderen. TODO 1. Elke HTML-pagina kan je zien als een boomstructuur. We leren die eerst grondig kennen (+ terminologie) 2. Manipuleren van deze boomstructuur via javascript 2
Document Object Model (DOM) Zie: http://w3schools.com/htmldom/default.asp 3
Document Object Model (DOM) Elke html-pagina is een collectie (=verzameling) van DOM nodes Een node kan zijn: Document: de top-node in de DOM-boom. Stelt het volledige document voor, je tekent het net boven het html-element. Element: elk html-tag is een element in de boom Text: de tekst-inhoud van een bepaald element is een text-node (voorgesteld als kind-element van het welbepaalde element) Let op: witruimte tussen elementen wordt ook voorgesteld als een textnode. Attribuut: een attribuut van een node is bereikbaar via het element, maar wordt niet getekend in de boomstructuur 4
Document Object Model DOM: visualiseren via DOM-inspector Firefox Firebug toont alle geneste html-tags. DOM-inspector toont het objectmodel van je html-pagina 5
Document Object Model Methodes van het DOCUMENT-object getelementbyid( idname ) var idnaam = document.getelementbyid( idname ); deze operatie geeft dus 1 element terug. getelementsbytagname( tagname ) var imgs = document.getelementbytagname( img ); imgs[3].src =.. ; deze operatie geeft een array van gelijkaardige elementen terug in de volgorde zoals ze in het document voorkomen. 6
Document Object Model Eigenschappen van een node nodevalue Je krijgt de value terug. Kan enkel gebruikt worden voor textnode en attribuutnode nodetype Je krijgt het type terug (numeriek getal). 1 ELEMENT_NODE 2 ATTRIBUTE_NODE 3 TEXT_NODE 9 DOCUMENT_NODE 7
Document Object Model Eigenschappen van een node childnodes Je krijgt de verzameling van alle kind-nodes terug. firstchild Je krijgt de eerste kind-node terug. lastchild Je krijgt de laatste kind-node terug. attributes je krijgt de attributes nodes van de node terug classname (eigenschap van een element) Je krijgt de class-naam terug van dit element (of je kan het zelf op een waarde instellen). 8
Document Object Model Eigenschappen van een node Voorbeelden: var n = document.getelementbyid( mynode) ; var p = n.parentnode // de tag die het element bevat var c0 = n.firstcild // Eerste kind van n var c1 = c0.nextsibling // Tweede kind van n var c2 = n.childnodes[2] // Derde kind van n var last = n.lastchild; //Laatste kind van n 9
Document Object Model Eigenschappen van een node <p id= story >You are alone.</p> document.getelementbyid( story ).firstchild.nodevalue= OK. Maybe you are alone! ; OK. Maybe you are alone! <p id= story >You are <strong>not</strong> alone.</p> document.getelementbyid( story ).firstchild.nodevalue= OK. Maybe you are alone! ; OK. Maybe you are alone! not alone 10
Document Object Model Wijzigen van een textnode 1) Verwijderen van alle kind-nodes. 2) Nieuwe tekstnode creëren. 3) Deze tekstnode toevoegen als kind-node var node = document.getelementbyid( story ); while (node.firstchild) node.removechild(node.firstchild); node.appendchild(document.createtextnode( OK. Maybe you are alone! )); 11
Document Object Model Wijzigen van documentstructuur n.removechild(node): verwijdert child node van n. n.appendchild(node): voegt child node toe aan n. createtextnode(text): maakt nieuwe tekst-node aan. createelement(tagname): maakt nieuwe element-node aan. Voorbeeld var boom = document.getelementbyid( boom ); var tak = document.createelement( p ); boom.appendchild( tak ); 12
Document Object Model Wijzigen van de weergave van een element(class style) classname is een eigenschap van een element. Voorbeeld: document.getelementbyid( decision1 ).classname =. ; Je kan bv de weergave wijzigen als je met de muis over iets beweegt (onmouseover) of ervan weggaat met je muis (onmouseout) 13
Document Object Model Wijzigen van de weergave van een element(class style) Soms wil je niet de volledige lay-out gaan manipuleren, maar enkel iets zichtbaar of onzichtbaar maken. Hier kan je dan beter het style-attribuut van het element gebruiken (ipv een andere class). Voorbeeld <span id= x style= visibility:hidden /> Via JavaScript: document.getelementbyid( x ).style.visibility = hidden ; 14
15 Bron: http://christianheilmann.com/stuff/javascript-dom-cheatsheet.pdf
Objecten in Javascript Objecten in javascript kunnen zowel gegevens als gedrag bevatten. Objecten groeperen variabelen en functies als één geheel wat wie wanneer Uitnodiging bezorg() toon() waar Zoals in java wordt ook hier de dot-notatie gehanteerd. 16
Objecten in Javascript Properties en methodes binnen een object zijn het equivalent van variabelen en functies Variabelen Functies variabelen worden properties van het object var wie; var wat; var wanneer; var waar; Properties var wie; var wat; var wanneer; var waar; Uitnodiging function bezorg(wat, wanneer, waar) { } function toon(wie) { } Methodes bezorg() toon() functies worden methodes van het object Een object "bezit" de properties en methodes Zoals in java wordt ook hier de dot-notatie gehanteerd. Voorbeeld: invitation.who = "Puzzler Ruby"; 17
Voorbeeld: Blog Ruby houdt momenteel een handgeschreven dagboek bij, maar ze wil overschakelen op een blog. Elke entry bestaat uit een datum + tekst De datum van de entry De tekst van de entry 18
Blog - custom objects De standard objects zoals date - string - array volstaan soms niet om data bij te houden, zoals voor een entry in onze blog: die bestaat uit datum en tekst. Standaard JavaScript objecten Custom JavaScript objecten Date August 14th, 2008 7:00 pm Het Blog object dient als een samen gesteld datatype: er worden 2 stukken data gecombineerd tot 1 eenheid String Got the new cube I ordered. It's a real pearl. Blog "08/14/2008" "Got the new cube I ordered. It's a real pearl." Array Blog date Blog body Blog date + Blog body = Blog object 19
Blog Custom objects aanmaken 1. function declareren = constructor function Blog(body, date) { // Assign the properties this.body = body; this.date = date; } 2. nieuw object aanmaken met new keyword new Blog("Got the new cube I ordered. It's a real pearl.", new Date("08/14/2008")); Zie volledige code voorbeeld YouCube yc1.js 20
Blog datum formatteren: Date Object Door gebruik te maken van de methodes van het date object kan de datum geformatteerd worden. Met behulp van de methodes van het date object, kan je de individuele delen waaruit de datum bestaat, krijgen Date August 14th, 2008 7:00 pm getmonth() getdate() getfullyear() 7 14 2008 De maand is een getal tussen 0 en 11 De dag is een getal tussen 1 en 31 Het jaartal bestaat uit 4 cijfers 21
Blog datum formatteren Door gebruik te maken van de methodes van het date object kan de datum geformatteerd worden var blogtextdate = document.createtextnode(blog[i].date.getdate() + "/" + (blog[i].date.getmonth() + 1) + "/" +blog[i].date.getfullyear()); 22
Blog op datum sorteren: Array Object De blog-objecten zijn opgeslagen in een array. We maken gebruik van het custom sorteren van een array en van de eigenschappen/methodes van het date-object. Indien een custom sort gewenst is, kan een ingebouwde vergelijkingsfunctie (compare) gebruikt worden. Aan deze worden twee argumenten meegegeven. De return-value kan kleiner, gelijk of groter dan nul zijn. Functie: compare(x, y) < 0 x wordt voor y geplaatst = 0 beide elementen zijn gelijk > 0 x wordt na y geplaatst 23
Blog sorteren op datum We gaan gebruik maken van het feit dat de blog objecten in array opgeslagen zijn om te sorteren. 1. Door de array gaan 2. Twee opeenvolgende elementen met elkaar vergelijken 3. Indien de datum van het volgende element recenter is worden de elementen gewisseld. 24
Blog sorteren op datum Array heeft ook een sort method, maar die sorteert de elementen van klein naar groot: ascending. => we maken gebruik van een custom sort De custom sort methode maakt gebruik van een comparison method. Om de elementen van groot naar klein te sorteren, maken we gebruik van een eigen custom compare function. Om je eigen compare function te gebruiken - geef je deze mee als parameter reference in de sort method. Bijvoorbeeld nums.sort (compare); Het sorteren van de array wordt nu bepaald door de functie compare() 25
Blog sorteren op datum In onze blog maken we gebruik van een function literal om de compare te definieren blog.sort(function(blog1,blog2){return blog2.date - blog1.date;}); Zie volledige code voorbeeld YouCube yc2.js 26
Blog zoekfunctie String Object Er moet een zoekfunctie toegevoegd worden aan de blog Werking van de zoekfunctie De zoekterm van de gebruiker ophalen Overloop alle blog entries Controleer of de zoekterm voorkomt in de blog entry Spring uit de lus wanneer er een match is De zoekterm wordt ingegeven en gebruikt bij het doorzoeken van de blog 27
Blog - zoekfunctie We maken gebruik van het string object en zijn methods. String length "Got the new cube I ordered. It's a real pearl" indexof() chartat() tolowercase() touppercase() Controleert of een string een bepaalde substring bevat Controleert of een bepaald karakter zich in de string bevindt Converteert de string naar kleine letters Converteert de string naar hoofdletters Het aantal karakters In de string 28
Blog - zoekfunctie Maak gebruik van de indexof methode om de string te doorzoeken Bijvoorbeeld var str = "Got the new cube I ordered. It's a real pearl"; alert (str.indexof("new")); Elk karakter heeft een unieke index (die begint te tellen vanaf 0) De zoekterm "new" start vanaf index 8 in de string 29
Blog - zoekfunctie function searchblog() { var searchtext = document.getelementbyid("searchtext").value; for (var i = 0; i < blog.length; i++) { // See if the blog entry contains the search text if (blog[i].body.tolowercase().indexof(searchtext.tolowercase())!= -1) { alert("[" + (blog[i].date.getdate() + "/" + (blog[i].date.getmonth() + 1) + "/" +blog[i].date.getfullyear()) + "]\n " + blog[i].body); break; } } // If the search text wasn't found, display a message if (i == blog.length) alert("sorry, there are no blog entries containing the search text."); } 30
Blog - random weergeven Er moet een functie toegevoegd worden die een random entry selecteert uit alle blog entries We maken gebruik van het custom JavaScript Math object om random getallen te genereren. Het Math object is een uniek object dat geen data heeft die kan veranderen en die dus ook geen methodes heeft die inwerken op de interne data Math round() Een kommagetal afronden naar een geheel getal PI De constante PI floor() ceiling() random() Een kommangetal naar beneden afronden naar een geheel getal Een kommagetal naar boven afronden naar een geheel getal Een random getal tussen 0 en 1 genereren 31
Blog - random weergeven Math.random() genereert een waarde tussen 0 en 1. Blog wenst een random nummer tussen 0 en de lengte van de array. var onetosix = Math.floor(Math.random() * 6) + 1; 32
Blog - random weergeven function randomblog() { // Pick a random number between 0 and blog.length - 1 var i = Math.floor(Math.random() * blog.length); alert("[" + (blog[i].date.getdate() + "/" + (blog[i].date.getmonth() + 1) + "/" +blog[i].date.getfullyear()) + "]\n " + blog[i].body); } Zie volledige code voorbeeld YouCube yc3.js 33
Blog - betere code. Het probleem is dat onze blog objecten enkel properties bevatten en geen gedrag. Nochtans zijn er stukken code die in aanmerking komen om als blog-methods, specifiek aan onze blog objecten gelinkt te worden. 34
Blog tohtml methode while (i < blog.length && i < numentries) { var blogpar = document.createelement("p"); var datestrong = document.createelement("strong"); var blogbr = document.createelement("br"); if (i % 2 == 0) blogpar.setattribute("style", "background-color:#eeeeee"); var blogtextdate = document.createtextnode(blog[i].date.getdate() + "/" + (blog[i].date.getmonth() + 1) + "/" +blog[i].date.getfullyear()); var blogtextbody = document.createtextnode(blog[i].body); datestrong.appendchild(blogtextdate) blogpar.appendchild(datestrong); blogpar.appendchild(blogbr); blogpar.appendchild(blogtextbody); blogdiv.appendchild(blogpar); i++; } 35
Blog tohtml methode function Blog(body, date) { this.body = body; this.date = date; this.tohtml = function(highlight) { var blogpar = document.createelement("p"); var datestrong = document.createelement("strong"); var blogbr = document.createelement("br"); if (highlight)blogpar.setattribute("style", "background-color:#eeeeee"); var blogtextdate = document.createtextnode(this.date.getdate() + "/" + (this.date.getmonth() + 1) + "/" +this.date.getfullyear()); var blogtextbody = document.createtextnode(this.body); datestrong.appendchild(blogtextdate) blogpar.appendchild(datestrong); blogpar.appendchild(blogbr); blogpar.appendchild(blogtextbody); return blogpar; } } 36
Blog tohtml methode function showblog(numentries) { // sorteren met custom compare function blog.sort(function(blog1,blog2){return blog2.date - blog1.date;}); // Adjust the number of entries to show the full blog, if necessary if (!numentries) numentries = blog.length; // Show the blog entries var i = 0; var blogdiv = document.getelementbyid("blog"); // delete all existent childnodes while (blogdiv.firstchild)blogdiv.removechild(blogdiv.firstchild); // show all blogs while (i < blog.length && i < numentries) { blogdiv.appendchild(blog[i].tohtml(i % 2 == 0)); i++; } } 37
Andere methods van object. Nog twee andere methodes komen in aanmerking: weergave van blog als string toegepast bij alert(blog[i]) zoeken string in body Code: zie voorbeeld yc4.js 38
Blog - objecten - instanties Het probleem is nu dat alle methodes telkens opnieuw gecreëerd worden als er een nieuw object wordt gemaakt. Dit is niet echt nodig. Alle methodes kunnen eigenlijk gebruikt worden door middel van één instantie. Blog "Managed to get a " August 16th,2008 tohtml() tostring() containstext() Blog "Got the new cube I ordered " August 14th,2008 tohtml() tostring() containstext() Elk Blog object creëert zijn eigen kopie van de 3 Blog methodes Blog "Solved the new cube but " August 15th,2008 tohtml() tostring() containstext() 39
Blog - objecten - instanties Blog "Got the new cube I ordered " August 14th,2008 tohtml() tostring() containstext() De methode behoort toe aan de Blog class => de instances moeten niet zelf over een kopie beschikken De methode bij de instances is gewoon een verwijzing naar de methode in de klasse Blog De data wordt bijgehouden in de properties van de Instance, maar je krijgt toegang tot de methodes via de Blog class Blog "Managed to get a " August 16th,2008 tohtml() tostring() containstext() Blog "Solved the new cube but " August 15th,2008 tohtml() tostring() containstext() 40
Blog - objecten - instanties Om op niveau van een klasse te werken in Javascript maakt men gebruik van de prototype property van een klasse. Prototype is een object dat voor elk object bestaat als een property. Het prototype object maakt het mogelijk om properties en methodes te declareren die gekoppeld zijn aan het klasse niveau en niet aan instanties, maar wel worden toegepast op instanties = a class owned instance method. Blog.prototype.toHTML = function(){ } Blog Prototype tohtml() var blogentry1 = new Blog("Not much ", ); blogentry1.tohtml(); Als de methode tohtml() opgeroepen wordt, wordt de methode tohtml van de klasse Blog uitgevoerd 41
Blog - vaste handtekening Ruby heeft 1 signature => Niet elke instantie van Blog moet zijn eigen signature hebben 42
Blog - vaste handtekening Een property kan ook aan de klasse gekoppeld worden via het prototype object. Blog.prototype.signature = Puzzler Ruby ; Blog.property.signature = "Puzzler Ruby" Class properties worden gecreëerd buiten de constructor van het object mbv het prototype object Er bestaat 1 signature voor alle blog entries Instance properties function Blog (body, date) { this.body = body; this.date = date; } Instance properties worden gecreëerd binnen de constructor van het object Blog Elke Blog instance heeft zijn eigen waarde voor body en date Code: zie voorbeeld yc5.js 43
JS Standard Objects uitbreiden Het is ook mogelijk om standaard javascript klassen met methodes uit te breiden. In ons voorbeeld doen we dat met de datum - formatteren (zo vermijden we dubbele code). Ook hier wordt gebruik gemaakt van de prototype property van een klasse. Date.prototype.shortFormat = function() { return (this.date.getdate() + "/" + (this.date.getmonth() + 1) + "/" +this.date.getfullyear()); } var blogtextdate = document.createtextnode(this.date.shortformat()); Blog.prototype.toString = function() { return "[" + this.date.shortformat() + "]\n " + this.body; } 44
Sortering - revisited De volgende code staat in de showblog functie - deze declareert een functie om custom te sorteren. blog.sort(function(blog1, blog2) { return blog2.date - blog1.date; }); Dit is niet de goede plaats aangezien de functie showblog niet verantwoordelijk is voor de sortering. Hoe oplossen? Door de comparison functie te declareren als een class-method. Dit is een methode die gekoppeld is aan een klasse. Deze heeft geen toegang tot de properties of methodes van de instanties van deze klasse maar kan wel met instanties van deze klasse werken. Blog.blogSorter = function(blog1, blog2) { return blog2.date - blog1.date; }; blog.sort(blog.blogsorter); Code: zie voorbeeld yc6.js 45