[javascript] Elementen toevoegen aan DOM-tree

Pagina: 1
Acties:
  • 161 views sinds 30-01-2008
  • Reageer

  • Zoefff
  • Registratie: September 2001
  • Laatst online: 23:05
Momenteel ben ik bezig met een formulier waarop iemand kan aangeven hoeveel deelnemers er zijn. Voor iedere deelnemer moeten er nog een aantal dingen ingevuld worden, en moeten er dus ook nieuwe input-velden komen.

Nou ben ik een vrijwel absolute javascript-n00b, maar ik ben er met enig zoek- en leeswerk achter gekomen dat ik elementen toe moet voegen aan de DOM-tree. Het stuk HTML dat per deelnemer moet worden toegevoegd, is het volgende:

HTML:
1
2
3
4
5
6
7
8
9
<h4>Deelnemer 1</h4>
<dl class='reserveer'>
    <dt><label for='voornaam'>Voorna(a)m(en):</label></dt>
    <dd><input style='width:250px;' name='voornaam' id='voornaam' type='text' size='20' maxlength='50' /></dd>
    <dt><label for='achternaam'>Achternaam:</label></dt>
    <dd><input style='width:250px;' name='achternaam' id='achternaam' type='text' size='20' maxlength='50' /></dd>      
    <dt><label for='geboortedatum'>Geboortedatum <em>(dd-mm-jjjj)</em>:</label></dt>
    <dd><input style='width:75px;' name='geboortedatum' id='geboortedatum' type='text' size='10' maxlength='10' /></dd>     
</dl>

Nou ben ik tot het volgende stuk javascript gekomen, wat stuk voor stuk de verschilende elementen en inhoud aanmaakt:
Java:
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
30
31
32
33
34
35
36
37
38
39
40
41
function addDeelnemer() {
    var div = document.createElement('div');
    var h4 = document.createElement('h4');
    var dl = document.createElement('dl');
    var dt_voornaam = document.createElement('dt');
    var dt_achternaam = document.createElement('dt');
    var dt_geboortedatum = document.createElement('dt');
    var dd_voornaam = document.createElement('dd');
    var dd_achternaam = document.createElement('dd');
    var dd_geboortedatum = document.createElement('dd');
        
    dl.setAttribute('class', 'reserveer');
    // .setAttribute('', '');
    
    var h4_tekst = document.createTextNode('Deelnemer');
    var dt_voornaam_tekst = document.createTextNode('Voornaam');
    var dt_achternaam_tekst = document.createTextNode('Achternaam');
    var dt_geboortedatum_tekst = document.createTextNode('Geboortedatum');
    var dd_voornaam_tekst = document.createTextNode('Voornaam dd');
    var dd_achternaam_tekst = document.createTextNode('Achternaam dd');
    var dd_geboortedatum_tekst = document.createTextNode('Geboortedatum dd');
    
    h4.appendChild(h4_tekst);   
    
    dt_voornaam.appendChild(dt_voornaam_tekst);
    dt_achternaam.appendChild(dt_achternaam_tekst);
    dt_geboortedatum.appendChild(dt_geboortedatum_tekst);
    dd_voornaam.appendChild(dd_voornaam_tekst);
    dd_achternaam.appendChild(dd_achternaam_tekst);
    dd_geboortedatum.appendChild(dd_geboortedatum_tekst);
    
    dl.appendChild(dt_voornaam);
    dl.appendChild(dd_voornaam);
    dl.appendChild(dt_achternaam);
    dl.appendChild(dd_achternaam);
    dl.appendChild(dt_geboortedatum);
    dl.appendChild(dd_geboortedatum);
    
    div.appendChild(h4);
    div.appendChild(dl);
}

Een enorme waslijst dus, en dan te bedenken dat daar de input-velden nog niet eens tussen zitten, met al hun attributen :D

Mijn vraag is, kan dit niet véél simpeler?

Uiteraard moet ik nog dingen toevoegen als automatische nummering, en een functie die de boel plaatst, maar dat is van later belang, en daar kom ik ook wel uit (denk ik).


FotoblogWerkaandemuur.nlMoestuincursus.nlTwitter


  • André
  • Registratie: Maart 2002
  • Laatst online: 28-04 11:43

André

Analytics dude

Een makkelijkere manier om dit te doen is door alle elementen en alle teksten in arrays te zetten en daar doorheen lopen.

Verwijderd

innerHTML :P

verder kan je ook dingen samenvoegen aangezien appendChild de child returned:

code:
1
dt_voornaam.appendChild(document.createTextNode('Voornaam'));

  • Borizz
  • Registratie: Maart 2005
  • Laatst online: 02-01 15:55
Je kan inderdaad innerHTML gebruiker (oke het is geen W3C standaard, maar de moderne browsers ondersteunen het wel). Of je doet het serverside met PHP / ASP maar dat is waarschijnlijk niet je bedoeling.

If I can't fix it, it ain't broken.


  • PierreAronnax
  • Registratie: Maart 2002
  • Niet online
Kan je niet makkelijker in 1 keer met div.innerHTML = "html code"; de hele div vullen, en die vervolgens aan de DOM toevoegen?

edit:
Hm, ok, laat...

[ Voor 20% gewijzigd door PierreAronnax op 03-10-2005 19:41 ]

Pierre - Motormedia.nl - Motor-Forum.nl - Motorshopper.nl - Motormeuk.nl - Motorstek.nl


  • Zoefff
  • Registratie: September 2001
  • Laatst online: 23:05
Ik had begrepen dat innerHTML een minder mooie oplossing was dan die ik wil gebruiken, of zit ik daar fout?

Alles in array's zetten heb ik inderdaad niet aan gedacht, dom. In combinatie met het samenvoegen misschien wel een goede oplossing :)

Serverside is inderdaad niet de bedoeling, aangzien de pagina dan eerst vernieuwd moet worden. Het gaat overigens over deze pagina.

Edit:

In Array's zetten is toch niet echt een ideale situatie kom ik nu achter, omdat niet ieder element een tekst krijgt (zoals div, dl). Voor de attributen van de input's kan het natuurlijk wel.

[ Voor 50% gewijzigd door Zoefff op 03-10-2005 19:57 ]


FotoblogWerkaandemuur.nlMoestuincursus.nlTwitter


  • PierreAronnax
  • Registratie: Maart 2002
  • Niet online
Als snelheid ook een issue is: innerHTML is aanzienelijk sneller dan via de DOM.
Of het netter is is een ander verhaal.

http://www.quirksmode.org/dom/innerhtml.html

Pierre - Motormedia.nl - Motor-Forum.nl - Motorshopper.nl - Motormeuk.nl - Motorstek.nl


  • Zoefff
  • Registratie: September 2001
  • Laatst online: 23:05
Hm oke, dat is duidelijk ja. Misschien om die reden toch maar innerHMTL dan. Ik zie overigens ook dat IE het vertikt om mijn stylesheet toe te passen op de nieuw toegevoegde elementen, waarom is dat?

Edit:

Daar ben ik inmiddels achter. IE werkt niet mee met x.setAttribute, brakheid. In plaats daarvan x.className = 'classname' gebruiken werkt wel, maar dat moet ik voor alle andere attributen dus ook doen?

[ Voor 37% gewijzigd door Zoefff op 03-10-2005 21:39 ]


FotoblogWerkaandemuur.nlMoestuincursus.nlTwitter


  • Borizz
  • Registratie: Maart 2005
  • Laatst online: 02-01 15:55
Nee, zover ik weet werkt setAttribute wel op andere attributen maar het class attribuut kan je inderdaad het beste via className zetten!

If I can't fix it, it ain't broken.


  • Zoefff
  • Registratie: September 2001
  • Laatst online: 23:05
Het werkt ook niet op style en maxlength.

[ Voor 63% gewijzigd door Zoefff op 03-10-2005 22:05 ]


FotoblogWerkaandemuur.nlMoestuincursus.nlTwitter


  • Borizz
  • Registratie: Maart 2005
  • Laatst online: 02-01 15:55
Hmm ik gebruik het weleens om een eigen attribuut toe te voegen meestal niet voor style of classname, waarschijnlijk neemt IE dat niet mee bij het renderen dan, het opvragen met getAttribute() gaat weer wel goed.

edit: even snel wat opgezocht: http://www.quirksmode.org...IE_when_used_with_th.html.

[ Voor 27% gewijzigd door Borizz op 03-10-2005 22:10 ]

If I can't fix it, it ain't broken.


  • crisp
  • Registratie: Februari 2000
  • Nu online

crisp

Devver

Pixelated

Als je dit stuk HTML al een keer op je pagina hebt staan kan je het natuurlijk gewoon clonen ;)

Intentionally left blank


  • frickY
  • Registratie: Juli 2001
  • Laatst online: 24-04 11:26
De makkelijkste oplossin is alle input-velden gewoon al in verborgen (style display: none) DIVjes mee te geven, maar pas te tonen wanneer deze nodig zijn.
Iets in de trant van;
JavaScript:
1
2
3
4
for(i = 0; i < aantalDeelnemers; i++)
  document.getElementById('deelnemerblock_' + i).style.display: block);
for(i = aantalDeelnemers; i < totaalAantalBlocks; i++)
  document.getElementById('deelnemerblock_' + i).style.display: hidden); // de rest verbergen

elke keer dat het aantal deelnemers wordt aangepast

Soortgelijke oplossing kun je met innerHTML gebruiken, door net zo vaak het block in een DIV bij te maken als dat er deelnemers zijn.

[ Voor 20% gewijzigd door frickY op 03-10-2005 22:14 ]


  • Zoefff
  • Registratie: September 2001
  • Laatst online: 23:05
crisp schreef op maandag 03 oktober 2005 @ 22:11:
Als je dit stuk HTML al een keer op je pagina hebt staan kan je het natuurlijk gewoon clonen ;)
Dat klinkt verdomde goed, want ik ben nu echt aan het kloten. Ik ga daar eens naar zoeken. Moet ik alleen wel zorgen dat er pas velden worden toegevoegd als het aantal deelnemers meer dan 1 is, maar dat moet wel lukken...
frickY schreef op maandag 03 oktober 2005 @ 22:12:
De makkelijkste oplossin is alle input-velden gewoon al in verborgen (style display: none) DIVjes mee te geven, maar pas te tonen wanneer deze nodig zijn.
Iets in de trant van;
JavaScript:
1
2
3
4
for(i = 0; i < aantalDeelnemers; i++)
  document.getElementById('deelnemerblock_' + i).style.display: block);
for(i = aantalDeelnemers; i < totaalAantalBlocks; i++)
  document.getElementById('deelnemerblock_' + i).style.display: hidden); // de rest verbergen

elke keer dat het aantal deelnemers wordt aangepast

Soortgelijke oplossing kun je met innerHTML gebruiken, door net zo vaak het block in een DIV bij te maken als dat er deelnemers zijn.
T is wel een ranzige oplossing, want in mijn geval zou ik dan 40 verborgen div-jes toe moeten voegen..


FotoblogWerkaandemuur.nlMoestuincursus.nlTwitter


  • Borizz
  • Registratie: Maart 2005
  • Laatst online: 02-01 15:55
JavaScript:
1
clone = element.cloneNode(true);


Je zult alleen wel de id's en names van de input velden moeten veranderen dan.

If I can't fix it, it ain't broken.


  • Zoefff
  • Registratie: September 2001
  • Laatst online: 23:05
Ok, clonen bleek dus inderdaad het magische woord te zijn. Ik heb nu het volgende:
Java:
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
var counter = 0;

function addFields() {
        counter++;
        var newFields = document.getElementById('deelnemer_source').cloneNode(true);
        newFields.id = 'deelnemer_' + counter;
        newFields.style.display = 'block';
    
        newFields.firstChild.firstChild.nodeValue = 'Deelnemer ' + counter;
            
        var newField = newFields.getElementsByTagName('input');
        for (var i=0; i < newField.length; i++) {
            var fieldName = newField[i].name;
                if (fieldName) {
                        newField[i].name = fieldName + "_" + counter; }
        }
        var insertFields = document.getElementById('deelnemers');
        insertFields.parentNode.insertBefore(newFields, insertFields);
}

function addRemove(aantal) {
    if ((aantal > 0) && (aantal <= 10)) {
        if (aantal < counter) {
            var remove = counter-aantal;
            var last = counter;
            var first = aantal;
            for (k = last; k > first; k--) {
                var deelnemer = "deelnemer_" + k;
                var toRemove = document.getElementById(deelnemer);
                toRemove.parentNode.removeChild(toRemove);
                counter = aantal;
            }           
        }
        else if (aantal > counter) {
            var add = aantal-counter;
            for (j = 1; j <= add; j++) {
                addFields();
            }
        }       
    }
    else {
        alert("Minimaal 1 deelnemer, maximaal 10 deelnemers per reservering");
        document.getElementById('aantal').value = "";
    }
}

window.onload = addFields;

Wat ik aanroep met:
code:
1
onkeyup=\"addRemove(this.value);\"

En dat werkt opzich prima :)

Wat ik alleen niet begrijp is dat als ik in het script iets zet als
code:
1
window.onload = addRemove(4);

dat het dan niet meer werkt, ik krijg dan een error:

Error: document.getElementById("deelnemer_source") has no properties


Waar komt dat dan ineens weer vandaan, en waarom gaat het wel goed als het in de 'onkeyup' staat?


FotoblogWerkaandemuur.nlMoestuincursus.nlTwitter


  • crisp
  • Registratie: Februari 2000
  • Nu online

crisp

Devver

Pixelated

Omdat je een functiecall doet en geen functie reference toekent aan de handler :P
Probeer het eens zo:
JavaScript:
1
2
3
4
window.onload = function()
{
    addRemove(4);
}

Intentionally left blank


  • Tom
  • Registratie: Juni 1999
  • Niet online

Tom

Ter info: dit hele handeltje had je in 3 minuten in ASP.NET kunnen maken met minder dan 6 regels code... ;)

  • Zoefff
  • Registratie: September 2001
  • Laatst online: 23:05
Jeuj \o/

Ik moet me toch nog eens gaan verdiepen in de basis van JavaScript geloof ik, iemand nog interessante guides of boeken? :X
Tom schreef op dinsdag 04 oktober 2005 @ 16:12:
Ter info: dit hele handeltje had je in 3 minuten in ASP.NET kunnen maken met minder dan 6 regels code... ;)
Hoezo? Punt is dat het niet serverside afgehandeld kan worden, omdat de pagina dan eerst ververst moet worden. Nu kan je gewoon invullen, en zodra je aangeeft hoeveel personen er meegaan, krijg je extra invulveldjes :)

[ Voor 62% gewijzigd door Zoefff op 04-10-2005 16:16 ]


FotoblogWerkaandemuur.nlMoestuincursus.nlTwitter


  • Tom
  • Registratie: Juni 1999
  • Niet online

Tom

Je kunt waarschijnlijk niks met mijn post, maar toch.. kon het niet laten je even te pesten ;)
Zoefff schreef op dinsdag 04 oktober 2005 @ 16:15:

Hoezo? Punt is dat het niet serverside afgehandeld kan worden, omdat de pagina dan eerst ververst moet worden. Nu kan je gewoon invullen, en zodra je aangeeft hoeveel personen er meegaan, krijg je extra invulveldjes :)
ASP.NET onthoud de waardes die zijn ingevuld bij een postback.

  • Zoefff
  • Registratie: September 2001
  • Laatst online: 23:05
Maar dan moet de pagina alsnog gerefreshed worden, toch? En dat is nou juist niet de bedoeling :)


FotoblogWerkaandemuur.nlMoestuincursus.nlTwitter

Pagina: 1