Toon posts:

[Javascript] Tips over fieldset status onthouden in cookie

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik werk bij een organisatie waar onder andere statistieken over examenresultaten verzameld worden. Het systeem dat we hiervoor gebruiken, is webbased en heeft zeer lange admin pagina's. Het leek mij daarom handig een library te schrijven waarmee ik de tientallen fieldsets op een pagina kan in- en uitklappen. Een werkend voorbeeld hiervan staat onderaan deze post. Ik denk dat dit een stukje code is dat we allemaal wel kunnen gebruiken :)

Nu het klaar is, loop ik tegen het volgende probleem. In de uitgangspositie staan alle fieldsets in een pagina ingeklapt. Je kunt er een of meerdere openklappen en in de inhoud ervan (bij ons textfields en textarea's) aanpassen. Maar nu: als ik een pagina reload (bijvoorbeeld omdat ik wat gegevens opsla / submit), staan alle fieldsets na de reload weer ingeklapt. De staat van de fieldsets (ingeklapt of niet) wordt niet onthouden. Dat is irritanter dan ik dacht.

Ik ben echter meer een amateur dan een professionele javascripter. Onderstaande code heb ik na heel veel moeite geschreven aan de hand van voorbeelden. Ik wilde vragen of er hier mensen zijn die mij op weg kunnen helpen met het implementeren van een systeem dat de status van elke fieldset onthoudt? Dit kan alleen via een cookie. Ik heb al twee cookie functies erbij gestopt. Ik vraag me alleen het volgende af:
  • Waarschijnlijk moet ik een cookie maken met als titel "collapsed", en daar een array met ingeklapte fieldsets stoppen. Als een fieldset dan uitgeklapt wordt, moet ik de fieldset uit de cookie verwijderen. Mijn vraag is hoe ik een array in een cookie stop en hoe ik de fieldsets uniek kan onderscheiden? Ik zit te denken aan onderscheiden op de 'legend'
  • Op welk moment in de code is het een goed moment om de cookie-functies te laten lopen? Ik heb een idee aangegeven in de code
  • hoe kan ik het beste de functie collapseAutoAttach aanpassen om door de array met ingeklapte fieldsets te lopen en de goede fieldsets een 'collapsed' class mee te geven c.q. te verwijderen?
Ik heb eerst goed rondgekeken op dit forum voordat ik lid werd. Ik weet dat script-requests niet zijn toegestaan, maar ga er vanuit dat dit er geen is. Ten eerste heb ik al een werkende applicatie (zie hieronder) en ik vraag geen kant-en-klare code, maar wordt graag in de goede richting gestuurd. Om dit zonder hulp uit te moeten zoeken, kost me een week. Ik hoop dat het met wat hulp van de echte cracks hier sneller gaat :)
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
<script>

function eregReplace(search, replace, subject) {
  return subject.replace(new RegExp(search,'g'), replace);
}

function setCookie(sName, sValue){
  document.cookie = sName + '=' + escape(sValue) + '; expires=Fri, 31 Dec 2030 23:59:59 GMT; path=/';
}

function getCookie(sName) {
  var aCookie = document.cookie.split('; '), i = aCookie.length, aCrumb;
  while (i--) {
    aCrumb = aCookie[i].split('=');
    if (sName == aCrumb[0]) {
      return typeof aCrumb[1] != 'undefined'? unescape(aCrumb[1]) : null;
    }
  }
  return null;
}

function hasClass(node, className) {
  if (node.className == className) {
    return true;
  }
  var reg = new RegExp('(^| )' + className + '($| )')
  if (reg.test(node.className)) {
    return true;
  }
  return false;
}

function addClass(node, className) {
  if (hasClass(node, className)) {
    return false;
  }
  node.className += ' ' + className;
  return true;
}

function removeClass(node, className) {
  if (!hasClass(node, className)) {
    // legend = node.getElementsByTagName('legend');
    // hier aan cookie toevoegen
    return false;
  }
  node.className = eregReplace('(^| )' + className +'($| )', '', node.className);
  return true;
}

function toggleClass(node, className) {
  if (!removeClass(node, className) && !addClass(node, className)) {
    return false;
  }
  return true;
}

function removeNode(node) {
  if (typeof node == 'string') {
    node = $(node);
  }
  if (node && node.parentNode) {
    return node.parentNode.removeChild(node);
  }
  else {
    return false;
  }
}

function collapseAutoAttach() {
  var fieldsets = document.getElementsByTagName('fieldset');
  var legend, fieldset;
  for (var i = 0; fieldset = fieldsets[i]; i++) {
    legend = fieldset.getElementsByTagName('legend');
    legend = legend[0];

    var a = document.createElement('a');
    a.href = '#';
    a.onclick = function() {
      toggleClass(this.parentNode.parentNode, 'collapsed');
      this.blur();
      return false;
    }
    a.innerHTML = legend.innerHTML;
    while (legend.hasChildNodes()) {
      removeNode(legend.childNodes[0]);
    }
    legend.appendChild(a);
  }
}
</script>

<style>
fieldset {margin-bottom: 15px;}
fieldset.collapsed {border-bottom-width: 0; border-left-width: 0; border-right-width: 0; margin-bottom: 0;}
fieldset.collapsed * {display: none;}
fieldset.collapsed table *, fieldset.collapsed legend, fieldset.collapsed legend * {display: inline;}
fieldset.collapsible legend a {padding-left: 25px; background: url("http://melati.org/melati-static/admin/minus.gif") 0 50% no-repeat;}
fieldset.collapsed legend a {background-image: url("http://www.netonews.co.il/IOS/Img/FrontIcons/plus.jpg");}
fieldset.collapsible legend a {display: block;}
</style>

<fieldset class="collapsible collapsed">
  <legend>Bedrijfsbeschrijving</legend>
  <div>Hier een heleboel interessante info!!</div>
</fieldset>

<fieldset class="collapsible collapsed">
  <legend>Persoonsbeschrijving</legend>
  <div>Hier een heleboel interessante info!!</div>
</fieldset>

<fieldset class="collapsible collapsed">
  <legend>Dingbeschrijving</legend>
  <div>Hier een heleboel interessante info!!</div>
</fieldset>

<script>
collapseAutoAttach();
</script>

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 09-12-2025
Je kunt het beste naar de standaard staat kijken. Je zegt dat dit collapsed is, dus dan geef je standaard al je fieldsets een collapsed class mee. Dit doe je al zo te zien. Wat je bij wilt houden is of je afwijkt van de standaard staat. Dit is dus als hij is uitgeklapt. Wat je dan kunt doen is per fieldset een aparte cookie zetten waarin staat dat hij is uitgeklapt, als dit het geval is. Als hij weer ingeklapt wordt, verwijder je de cookie weer.

Het lijkt mij het makkelijkst om hiervoor gewoon de index van je fieldset in de array van alle fieldsets te gebruiken, en dan in deze vorm: fieldset_expanded_12, waarbij 12 dan die index is. In je collapseAutoAttach kun je dan per fieldset controleren of de cookie bestaat, en op basis daarvan handelen.

Noushka's Magnificent Dream | Unity


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 13:15

crisp

Devver

Pixelated

Wat je dan kunt doen is per fieldset een aparte cookie zetten ...
remember: max 20 per domain dus dit lijkt mij geen goed idee ;)

overigens heeft dit forum een werkende implementatie van een dergelijke functionaliteit (zie de index) ;)

Intentionally left blank


  • Michali
  • Registratie: Juli 2002
  • Laatst online: 09-12-2025
crisp schreef op maandag 23 oktober 2006 @ 13:14:
[...]

remember: max 20 per domain dus dit lijkt mij geen goed idee ;)
Ok, dat wist ik niet eens :P


Dan lijkt het me het beste om gewoon 1 cookie te zetten expanded_fieldsets, en daarin een lijstje bijhouden van alle fieldsets. Je kunt daarvoor de split() method van String gebruiken en de join() method van Array:
JavaScript:
1
2
3
4
5
var cookieValue = getCookie('expanded_fieldsets');
var expandedFieldsets = ( cookieValue === null ? [] : cookieValue.split(',') );
expandedFieldsets.push(123);
var newCookieValue = expandedFieldsets.join(',');
setCookie('expanded_fieldsets', newCookieValue);


Of er moet natuurlijk nog een betere methode zijn?

Noushka's Magnificent Dream | Unity


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 13:15

crisp

Devver

Pixelated

Wij slaan het ook komma-seperated op in 1 cookie

Intentionally left blank


Verwijderd

Topicstarter
Michali schreef op maandag 23 oktober 2006 @ 13:23:
[...]
Je kunt daarvoor de split() method van String gebruiken en de join() method van Array [...]
Naar aanleiding van de post van crisp heb ik de js van GoT er maar eens bijgetrokken. Zij doen het idd op eenzelfde manier :) Ik denk niet dat er een betere manier is, omdat je bij mijn weten alleen strings kunt opslaan in een cookie.
Michali schreef op maandag 23 oktober 2006 @ 13:10:
Het lijkt mij het makkelijkst om hiervoor gewoon de index van je fieldset in de array van alle fieldsets te gebruiken, en dan in deze vorm: fieldset_expanded_12, waarbij 12 dan die index is.
Alleen naar de index kijken kan niet, omdat er meerdere admin schermen met elk meerdere fieldsets zijn. Als ik dus op pagina A de fieldset met index 4 uitklap, en ik ga naar pagina B, dan zou de fieldset met index 4 op die pagina ook uitgeklapt zijn. Vandaar:
  • de index moet gecombineerd worden met een unieke andere identifier (document.location?)
  • of de programmeur van de admin sectie moet ervoor zorgen dat elke fieldset een unieke naam mee krijgt. In dat geval kun je deze naam in het cookie gebruiken...
2 Functies moeten voor deze uitbreiding aangepast worden: toggleClass en collapseAutoAttach. Als iemand een fieldset toggled, moet het cookie worden aangepast (fieldname (oid) erin of eruit). Standaard heeft elke fieldset als class "collapsible collapsed". collapseAutoAttach dient door de fieldset collectie te lopen en fieldsets die in het cookie staan alsnog als class "collapsible" mee te geven (dus: removeClass collapsed). Twee vragen:
  • Is het een goede manier om standaard alle fieldsets als class "collapsible collapsed" mee te geven en pas clientside mbv het cookie te kijken of de fieldset toch ook wel werkelijk "collapsed" moet zijn, of is het beter om serverside die cookie al te checken en uitgeklapte fieldsets meteen alleen maar "collapsible" als class mee te geven?
  • Kan iemand een voorzet geven over hoe de functie collapseAutoAttach aangepast moet worden in het geval alles clientside gechecked wordt?
JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function collapseAutoAttach() {
  var fieldsets = document.getElementsByTagName('fieldset');
  var legend, fieldset;
  for (var i = 0; fieldset = fieldsets[i]; i++) {
    legend = fieldset.getElementsByTagName('legend');
    legend = legend[0];

    var a = document.createElement('a');
    a.href = '#';
    a.onclick = function() {
      toggleClass(this.parentNode.parentNode, 'collapsed');
      this.blur();
      return false;
    }
    a.innerHTML = legend.innerHTML;
    while (legend.hasChildNodes()) {
      removeNode(legend.childNodes[0]);
    }
    legend.appendChild(a);
  }
}

[ Voor 38% gewijzigd door Verwijderd op 23-10-2006 14:10 ]


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 13:15

crisp

Devver

Pixelated

Wij gebruiken sidewide unieke id's (ook handig bij de lookups uiteraard ;) ). Op page-basis zou ook kunnen maar dan zou ik voor een multi-dimensionale array gaan die je op een andere manier serialized (JSON-formaat is erg geschikt hiervoor) opslaat in je cookie.

Pas op met al te grote identifiers aangezien de max size van alle cookies van een domein ook maar 4KB is in de meeste browsers.

[ Voor 6% gewijzigd door crisp op 23-10-2006 13:41 ]

Intentionally left blank


Verwijderd

Topicstarter
Ik heb besloten om als unieke identifier de legend titel te gebruiken. Ik heb twee functies toegevoegd aan de code uit de startpost: getExpandedFieldsets (om de expanded fieldsets uit een cookie te halen) en inArray (om te kijken of een legend titel in het cookie zit). Ik heb om te testen een cookie gezet met "setCookie('fieldsets', 'Persoonsbeschrijving, Ding beschrijving')". Ik denk dat ik in regel 39 van collapseAutoAttach() een check moet invoeren om te kijken welke fieldsets uitgeklapt moeten worden. Of moet ik dit inbouwen bij de toggleClass functie? Ik weet niet wat logischer is, dus alle hulp is welkom :)
JavaScript:
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
function getExpandedFieldsets() {
  var fieldsets = getCookie('fieldsets');
  return (fieldsets === null) ? [] : fieldsets.split(',');
}

function inArray(theString, theArray) {
  for (s = 0; s < theArray.length; s++) {
      entry = theArray[s].toString();
    if (entry == theString) {
      return true;
    }
  }
  return false;
}

function collapseAutoAttach() {
  var fieldsets = document.getElementsByTagName('fieldset');
  var expandedFieldsets = getExpandedFieldsets();
  
  var legend, fieldset;
  for (var i = 0; fieldset = fieldsets[i]; i++) {
    legend = fieldset.getElementsByTagName('legend');
    legend = legend[0];
    fieldName = legend.innerHTML;

    var a = document.createElement('a');
    a.href = '#';
    a.onclick = function() {
      toggleClass(this.parentNode.parentNode, 'collapsed');
      this.blur();
      return false;
    }
    a.innerHTML = legend.innerHTML;
    while (legend.hasChildNodes()) {
      removeNode(legend.childNodes[0]);
    }
    legend.appendChild(a);

    if (inArray(fieldName, expandedFieldsets)) {
      // expand fieldset?
    }
  }
}

Verwijderd

Topicstarter
Ik heb wat vooruitgang gemaakt sinds gisteren, maar heb nu een klein probleem. Als ik namelijk op een fieldset legend klik (en hem uitklap), wordt hij keurig toegevoegd aan het cookie. Als ik er weer op klik, wordt de naam uit het cookie verwijderd. De komma'tjes blijven echter in de cookie staan! Ik snap niet waarom, omdat ik gewoon met join werk. Na een paar keer fieldsets open en dichtklikken, ziet de cookie er bijvoorbeeld zo uit:
code:
1
,,,,,,Persoonsbeschrijving,,,Bedrijfsberchrijving,

Hoe kan dit? Ik heb mijn code al meerdere keren doorlopen, maar zie niet waar het fout gaat :'(

Dit is de code die ik nu gebruik (rest staat in de openingspost maar is niet nodig voor dit probleem):
JavaScript:
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
48
49
50
51
52
53
54
function getExpandedFieldSets() {
  var expandedFieldSets = getCookie('expandedFieldSets');
  return (expandedFieldSets === null) ? [] : expandedFieldSets.split(',');
}

function addFieldSet(field) {
  var expandedFieldSets = getExpandedFieldSets();
  if (!inArray(field, expandedFieldSets)) {
    expandedFieldSets.push(field);
    expandedFields = expandedFieldSets.join(',');
    setCookie('expandedFieldSets', expandedFields);
  }
}

function removeFieldSet(field) {
  var expandedFieldSets = getExpandedFieldSets();
  if (key = expandedFieldSets.find(field)) {
    delete expandedFieldSets[key];
    expandedFields = expandedFieldSets.join(',');
    setCookie('expandedFieldSets', expandedFields);
  }
}

function inArray(stringToSearch, arrayToSearch) {
  for (i = 0; i < arrayToSearch.length; i++) {
    thisEntry = arrayToSearch[i].toString();
    if (thisEntry == stringToSearch) {
      return true;
    }
  }
  return false;
}

Array.prototype.find = function (element) {
  for (var keys in this) {
    if (this[keys] == element) {
      return keys;
      break;
    }  
  }
  return false;
};

function removeClass(node, className) {
  var legend = node.getElementsByTagName('legend');
  var field = legend[0].childNodes[0].childNodes[0].nodeValue;
  if (!hasClass(node, className)) {
    removeFieldSet(field);
    return false;
  }
  node.className = eregReplace('(^| )' + className +'($| )', '', node.className);
  addFieldSet(field);
  return true;
}

[ Voor 27% gewijzigd door Verwijderd op 24-10-2006 15:21 ]


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 13:15

crisp

Devver

Pixelated

JavaScript:
1
2
3
var a = [];
a[4] = 'foo';
alert(a.join(','));
;)

Intentionally left blank


Verwijderd

Topicstarter
crisp schreef op dinsdag 24 oktober 2006 @ 15:22:
JavaScript:
1
2
3
var a = [];
a[4] = 'foo';
alert(a.join(','));
Ah! Dus ik moet nadat ik een element gedelete heb, de array opnieuw indexeren?

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 13:15

crisp

Devver

Pixelated

Verwijderd schreef op dinsdag 24 oktober 2006 @ 15:43:
[...]

Ah! Dus ik moet nadat ik een element gedelete heb, de array opnieuw indexeren?
inderdaad, of de manier waarop wij het doen gebruiken (geen items in een array maar properties van een object)

Intentionally left blank


Verwijderd

Topicstarter
Kan iemand mij een helpen bij het her-indexeren van de array? Ik heb nu het volgende, en had verwacht dat dit zou werken, maar zodra ik een element verwijder, wordt de hele cookie leeg gegooid:
JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function removeFieldSet(field) {
  var expandedFieldSets = getExpandedFieldSets();
  var newExpandedFieldSets = Array();
  if (key = expandedFieldSets.find(field)) {
    delete expandedFieldSets[key];
    for (x in expandedFieldSets) {
      var i = 0;
      newExpandedFieldSets[i] = expandedFieldSets[x];
      i++;
    }
    expandedFields = newExpandedFieldSets.join(',');
    setCookie('expandedFieldSets', expandedFields);
  }
}

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 13:15

crisp

Devver

Pixelated

Waarom niet zo:
JavaScript:
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
// fieldsets ophalen
var expandedFieldSets = {};
var cookiecontent = getCookie('expandedFieldSets');
if (cookiecontent !== null)
{
    var temp = cookiecontent.split(','), i = temp.length;
    while (i--)
        expandedFieldSets[temp[i]] = 1;
}

// fieldset toevoegen
expandedFieldSets['somefieldset'] = 1;

// fieldset verwijderen
delete(expandedFieldSets['somefieldset']);

// checken of fieldset bestaat
if (typeof expandedFieldSets['somefieldset'] != 'undefined')
{
}
//of
if ('somefieldset' in expandedFieldSets)
{
}

// fieldsets weer wegschrijven
var temp = [];
for (var fieldset in expandedFieldSets)
    if (!Object.prototype[fieldset])
        temp.push(fieldset);
setCookie('expandedFieldSets', temp.join(','));

Juist het hele zoeken in je array en het telkens weer moeten indexeren maakt het onnodig traag en complex; ik doe enkel een kleine omzetting bij het ophalen en bij het wegschrijven en de rest blijft heerlijk simpel :)

Intentionally left blank

Pagina: 1