Toon posts:

[dhtml] DOM tree icm eigen object tree

Pagina: 1
Acties:

Verwijderd

Topicstarter
Dit verhaal gaat over de manier van aanpak van het creeeren van een eigen objectboom dmv javascript.

Om even te beginnen bij beehive van Clay.
Clay's beehive is een objectgeorienteerd geheel, waarin dynamische objecten worden gecreerd die allerlei egenschappen bevatten die het gedrag ervan bepalen (width en height enzo) dit object is niet direct gekoppeld met de output die uiteindelijk op het scherm verschijnt. Om dit te realiseren is binnen het dynObject een layer property die een div bevat met bijbehorende troep (style enzo) dit object is dus het daadwerkelijke (DOM) object dat je op het scherm ziet (clay, verbeter me als het niet klopt)

Als je met deze dynobjecten een boom gaat maken door ze mbv een parent-child structuur aan elkaar te hangen, krijg je een beetje twee systemen naast elkaar. Je hebt enerzijds je eigen boom van objecten, en elk van deze objecten heeft een layer die onderling gekoppeld zijn om de DOM boom te vormen (een plaatje zou hier verhelderend zijn denk ik, maar daar heb ik de mogelijkheden effe niet voor)

Dit lijkt me niet altijd handig, wat ik liever zou zien is dat je zelfgecreeerde object in de DOM structuur gezet wordt. Hier heb ik wat mee zitten prutsen en dan loop ik tegen problemen aan.

Ipv nieuwe objecten aanmaken dmv een constructor gebeurt het nu dmv newDiv = document.createElement('div'); en vervolgens worden allerlei properties aan die div toegevoegd.

als ik methods aan dit object wil hangen gaat dit niet via het prototype, werkt dit niet, dit moet direct: newDiv.foo = eenFunctie;
probleem hier is dat we ook geen variabelen mee kunnen geven.
Ook mis je de inheritance die je dmv prototyping kan regelen

Liever zou ik zien dat ik volgens de standaard methode een object maak (dus met een constructor en dan alle methods via prototyping eraan hangen). En vervolgens dit hele object in de DOM tree hangen.

Ik wil dus graag een discussie opstarten over hoe men dit het beste zou kunnen aanpakken. Je kan er voor kiezen om twee min of meer gescheiden boomstructuren te bouwen, waarvan 1 dus een directe afspiegeling is van wat je op je scherm ziet (de DOM tree) en de andere een abstractere tree die je applicatie meer functioneel beschrijft (je eigen tree dus). Je zou bijvoorbeeld een object ChessBoard kunnen hebben, dat bestaat uit een hele berg div's en plaatjes.

Een probleem waar ik hier bijvoorbeeld weer tegenaan loop is de vraag hoe je een method van je abstracte object koppelt aan een event van je DOM object.

Verwijderd

Twee aparte bomen beheren is niet zo'n enorm probleem. Synchronizatie is vrij eenvoudig als elke node in de ene boom één op één mapt op één node in de andere boom.
Een probleem waar ik hier bijvoorbeeld weer tegenaan loop is de vraag hoe je een method van je abstracte object koppelt aan een event van je DOM object.
Dit kun je bijvoorbeeld doen door in je custom object een pointer naar je DOM object te hangen en aan je DOM object een pointer naar je custom object. Methodes van je custom object kunnen dan via die pointer kunnen worden aangeroepen.
JavaScript:
1
2
var oDIV = document.getElementById('customDIV');
oDIV.oPointer.MyMethod('yeah baby');

Verwijderd

Topicstarter
dus dan heb je iets als
HTML:
1
<div id="customDIV" onclick="this.oPointer.MyMethod('flep');" />
?

twee aparte bomen is wel te doen idd, maar de vraag is of dat wenselijk is, mij lijkt het persoonlijk af en toe handiger om je eigen objecten te embedden in de DOM tree, zoals bij layer sleur en pleur acties (een of ander (tree)menu ofzo), alleen dan ben je dus niete cht object georienteerd bezig omdat je stiekum eigenschappen in je DOM objecen zit bij te prutsen ipv bijvoorbeeld een descendant te maken met de goede eigenschappen

[ Voor 12% gewijzigd door Verwijderd op 25-06-2003 12:52 ]


  • Clay
  • Registratie: Oktober 1999
  • Laatst online: 22-06 13:51

Clay

cookie erbij?

Het is (bij beehive) idd soms lastig dat je een soort "wrapper" om je element hebt hangen die naar het element praat. Waar je om te beginnen al gauw tegenaanloopt zijn dubbele gegevens. Ga je alle css properties ook nog eens in het object opslaan bv? (liefst niet dus)
Nou zitten er ook genoeg voordelen aan de wrapper. Als je bijvoorbeeld moveTo en moveBy functies maakt is het practischer om een int property aan je object te hebben hangen dan elke keer de px van je element.style.left te moeten parseInten. Zeker als je dingen wil gaan animeren, dat scheelt bergen performance. Ook zoals je al aangeeft is prototypen makkelijker.

Ik denk dan ook dat dat wrapper principe beter is dan direct dingen aan je element te plakken, als is het om een centraal systeem te hebben waar "componenten" naartoe kunnen gaan praten. Want ergens beginnen de abstracte object zowiezo mee te doen, dus waarom niet meteen?
Om te beginnen geef je zelf al aan dat je runtime alle functies opnieuw aan je element moet plakken. Misschien dat je in mozilla de verschillende elementen wel aan hun prototype kan oppakken (htmlDivElement oid?), maar dan gaat er een aardige bak code zitten in het preppen van htmlelementen, en javascript houd je het liefst zo kort mogelijk, met zo min mogelijk uitvoer van wazige code die ook vermeden kan worden.

[reclame ;) ]
Overigens is Beehive II niet meer specifiek toegespitst op absolute gepositioneerde div's, maar kan je op een vergelijkbare manier als de dom elke html element aanmaken en/of aanpassen, ala:

JavaScript:
1
2
obj = document.createObject('div', {html attributen}, {css attributen});
obj.createObject('p', {innerHTML:'hoi'}, {padding:'5px'});


het werkelijk gemaakte element zit dan in obj.element, en domElement.dynObject verwijst dan naar het abstracte object. Intern zorgt het voor een eigen objectboom structuur met oa. .parent property en .children array property. Het gebruik van "id" attributen is in zijn geheel weg, zowel extern als intern, omdat dat gewoon niet nodig bleek.
[/reclame]
Een probleem waar ik hier bijvoorbeeld weer tegenaan loop is de vraag hoe je een method van je abstracte object koppelt aan een event van je DOM object.
Als het abstracte object bij zijn dom objecten kan komen en andersom lijkt me dat niet eens zo'n groot probleem. Dat blijft denk ik meer een kwestie van de opzet van je code, zoals bv bij een ChessBoard object.

Instagram | Flickr | "Let my music become battle cries" - Frédéric Chopin


  • Bosmonster
  • Registratie: Juni 2001
  • Laatst online: 19-08 22:14

Bosmonster

*zucht*

Het hele idee van de wrapper is imho iets achterhaald en afkomstig uit de tijd dat zoiets nodig was om DHTML op de legacy browsers programmeerbaar te maken.

De hele DOM is al een object-boom waar je weinig meer aan hoeft te doen en ik zie dan persoonlijk meer heil in een functie-bibliotheek om de specifieke DOM-objecten te manipuleren. Of functies die de bestaande methoden overschrijven om DOM-verschillen op te vangen. Of je een dergelijke bibliotheek weer packaged op een Object-georienteerde manier is uiteraard aan de ontwikkelaar.

Om iets te noemen, animatie-methoden zijn simpel los te ontwikkelen en direct op de DOM toe te passen. Maak een animatieobject dat weer direct elementen accepteert om te manipuleren. Waarom zou je daarvoor een hele element-wrapper voor nodig hebben?

[ Voor 19% gewijzigd door Bosmonster op 25-06-2003 13:58 ]


  • Clay
  • Registratie: Oktober 1999
  • Laatst online: 22-06 13:51

Clay

cookie erbij?

Omdat je alles via die element wrapper kan regelen, van css tot events. IE en in mindere mate Moz(+aanverwanten), Opera en straks Safari zijn dan wel zowat de enige browsers die er nog toe doen, en heel erg veel gaat al generiek voor alle browsers op, maar er zijn nog steeds verschillen.

De dom is dan wel een object boom, maar als je al een functie-lib schrijft kan je die net zo goed OO maken, zodat je het object maar 1 keer ergens aan hoeft te voeren, en daar is dan je "wrapper" weer.
De dhtml library is achterhaald. Maar het principe van een script library wordt er niet minder handig om, het blijft een practisch centraal systeem waarvandaan je je pagina kan besturen; events, style, content, alles. Het voordeel van een consistente dom is dat de library veel korter kan, en eerder een "dom" library genoemd kan worden. In weze hetzelfde als een functie lib, maar dan OO.

Ik vind document.getElementById veel te lang om meer dan 1 keer te moeten typen. Ook document.createElement en htmlElement.appendChild(htmlElement) zijn prima samen te combineren tot 1 ding. Waarom zou je dat verspreid over je script overal los neerzetten?
Maar ik ben dan ook een gigantische voorstander van supercentrale systemen :)

Instagram | Flickr | "Let my music become battle cries" - Frédéric Chopin


  • Bosmonster
  • Registratie: Juni 2001
  • Laatst online: 19-08 22:14

Bosmonster

*zucht*

Dat spreek ik ook niet tegen, alleen de specifieke 'wrapper' implementatie. :) Een wrapper is over het algemeen een inflexibele en inefficiente oplossing. Als je meer gestandaardiseerde functionaliteit wilt toevoegen kun je toch ook 'extenden' (zie Blues zijn voorbeeld).

Verwijderd

Topicstarter
Om even met een concreet voorbeeld te komen (ik ben bezig met tal van case studies naar realiseerbaarheid van verschillende ideeen): Neem een treeviewer. We gaan dan uit van 2 objecten:

• het omhullende TreeView object
Dit element zou volgens de wrappermethode een div bevatten die geplaatst wordt in een ander element (waarvan het id bv meegegeven wordt in de constructor van het TreeView object.

• TreeElement Objecten
Deze nodes zijn via bijvoorbeeld TreeView.addElement('naam') aan de TreeView te hangen.
Een dergelijke method moet dus ook voor dit object bestaan. Elk element bevat dan weer een DOM objecten, zoals een plaatje of een link, of een functiereferentie.

Nu heb je dus een baseNode (met een div) en allemaal losse elementen (met hun div's met daarin allerlei troep), die je aan elkaar hangt via een parent-child structuur.

Is het dan niet veel handiger om in zo'n geval de div's zelf uit te rusten met de functies die de boel in- en uitklapt (dat scheelt je methods schrijven die het linken van objecten regelt, want dat heb je al standaard), ik zou zeggen van wel

Maar wat dan als dit TreeView'tje een onderdeel is van een veel groter systeem, dat je je TreeView object aan een veel grotere boom wilt hangen waar allerlei complexe objecten aan hangen (bijvoorbeeld het beroemde object forum() :P) Is het dan nog wel zo handig?

Verwijderd

Even iets over het hangen van eigen properties / methoden aan DOM nodes: eigenlijk is dat vreselijk ranzig. Met javascript levert het doorgaans weinig problemen op, maar met talen als Java zou je om het minste of geringste al DOM-classes moeten gaan extenden.

DOM level 3 biedt een uitstekende 'oplossing': aan elke node kan data worden gehangen, bijvoorbeeld strings, getallen, classes, wigenlijk alles. Maar daarvoor zou je wel voor het mooie setUserData moeten gebruiken. Iets wat IE sowieso nog niet ondersteunt. Maar daar kun je juist zelf een mooie oplossing voor schrijven. ;)

  • Bosmonster
  • Registratie: Juni 2001
  • Laatst online: 19-08 22:14

Bosmonster

*zucht*

Het extenden van classes is juist een typische Java oplossing, dus ik snap de 'ranzigheid' er niet van. Javascript is echter niet class-based, maar prototype-based, maar het extenden van prototypes komt op hetzelfde neer.

(Al weet ik niet of het mogelijk is om het element-prototype te extenden...)

Het zijn juist wrappers die normaliter als laatste redmiddel worden gekozen en eerder tot 'ranzigheid' kunnen worden gerekend. Maar misschien dat je bij dhtml door de beperkte invloed niet anders kan dan je tot dit laatste redmiddel wenden :)

[ Voor 46% gewijzigd door Bosmonster op 25-06-2003 15:19 ]


  • Bosmonster
  • Registratie: Juni 2001
  • Laatst online: 19-08 22:14

Bosmonster

*zucht*


code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<html>
<head>
<script type="text/javascript">

Object.prototype.getId = function () {
    if (this.id)
        return this.id;
    else
        return 'no id specified';
}

function fnAfterLoad () {
    var ele = document.createElement('DIV');
    ele.style.backgroundColor = '#FF0000';
    ele.innerHTML = 'hallo';
    ele.id = 'aDiv';
    document.body.appendChild (ele);

    alert (document.getElementById('aDiv').getId());
    alert (document.getElementById('bestaandeDiv').getId());
}

onload = fnAfterLoad;
</script>
</head>
<body>
<div id='bestaandeDiv'>bladibla</div>
</body>
</html>



Dit werkt dus wel in Mozilla, maar niet in IE :( Voor Mozilla zijn alle objecten en elementen afgeleiden van het centrale Object() object. IE maakt daar blijkbaar voor html elementen e.d. eigen Objecten voor waarvan de prototypes niet bereikbaar zijn (of zover ik weet niet).

Dit zou imho de netste manier zijn om elementen te extenden met extra functionaliteiten, zoals animatie-methods... Voordeel is dat het werkt voor ALLE elementen en je geen gekke wrapper vertalingen nodig hebt.

edit: iets aangepast om te laten zien dat het ook met in de html gedefineerde elementen werkt..

[ Voor 21% gewijzigd door Bosmonster op 25-06-2003 15:42 ]


  • Clay
  • Registratie: Oktober 1999
  • Laatst online: 22-06 13:51

Clay

cookie erbij?

Er is wel 1 ding waar je op moet letten met prototyping op "Object";

JavaScript:
1
2
3
4
5
6
7
8
Object.prototype.fiets = function() {
    alert('hoi');
}

var test = [1,2,3,4,5];
for(var i in test) {
    alert(test[i]);
}


de 1e alert is niet "1", maar die functie fiets. Met een for(var i in object) krijg je dus ook dingen die je aan Object.prototype hebt gekoppeld. Je zal dus checks moeten inbouwen als je zo'n for gebruikt.

Instagram | Flickr | "Let my music become battle cries" - Frédéric Chopin


Verwijderd

Topicstarter
maar dit werkt dus niet in ie begrijp ik? dan valt het hele concept voor mij (en ik denk voor velen anderen) al af.
Het is opzich wel een mooie truc, behalve dus dat je idd alle objecten een extention geeft, dus ook een array zoals Clay aangeeft. Dan zou het nuttiger zijn als alle DOM elementen van een gemeenschappelijk object afgeleid waren, zodat je die kan extenden.

Wat overigens wel gaat (in ie iig, verder nog niet getest) is het creeren van een soort dummytags: document.createElement('foo'), waar je dus allerlei functionaliteiten aan kan hangen als je dat niet direct aan je html elementen wilt doen.

Als je daar een pointer in stopt naar een object die al je gegevens bevat, heb je toch een beetje je eigen object in je dom tree ingebouwd, maar ook dit voelt vies (net als zomaar properties en methods aan DOM elementen hangen dus).

De netste oplossing lijkt me dus vooralsnog het bijhouden van twee (strict gescheiden) objectbomen en je de "viezigheid" beperkt tot een pointer van je DOM element naar de wrapper in je andere boom.

  • Bosmonster
  • Registratie: Juni 2001
  • Laatst online: 19-08 22:14

Bosmonster

*zucht*

Clay schreef op 25 June 2003 @ 17:28:
Er is wel 1 ding waar je op moet letten met prototyping op "Object";

JavaScript:
1
2
3
4
5
6
7
8
Object.prototype.fiets = function() {
    alert('hoi');
}

var test = [1,2,3,4,5];
for(var i in test) {
    alert(test[i]);
}


de 1e alert is niet "1", maar die functie fiets. Met een for(var i in object) krijg je dus ook dingen die je aan Object.prototype hebt gekoppeld. Je zal dus checks moeten inbouwen als je zo'n for gebruikt.
Dat is dus ook een van de problemen... ik wil niet aan Object iets koppelen, maar aan Element oid.. helaas bestaat dat niet, of ben ik er nog niet achter :) Het Object-prototype aanpassen is ook ranzig, maar op die manier werken is wel erg netjes... In Mozilla zijn dus alle objecten en elementen ge-extend van Object(), zoals het hoort. In IE is dit dus echter niet het geval...

Voor zover ik weet zijn hier ook geen standaard-afspraken over.. Ik zou dus in IE/Mozilla iets aan het HTML-element prototype willen hangen.

[ Voor 4% gewijzigd door Bosmonster op 25-06-2003 20:11 ]

Pagina: 1