Toon posts:

setTimeout op objecten, crossbrowser oplossing?

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik ben nu een tijdje bezig met een treeview en heb hier een method waarbij een gedefinieerd pad door de treeview wordt uitgeklapt.

Omdat de treeview xml datasources onder een node kan hebben, moet bij het uitklappen eerst de data worden ingeladen alvorens de childNode kan worden geselecteerd. Hiervoor gebruik ik setTimeout op het object, die vervolgens de functie opnieuw aanroept.

Onder MSIE gebruik ik de welbekende object fix hiervoor:

PHP:
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
Object.prototype.eval = function(code){
   eval(code);
};

Object.prototype.setTimeout = function(code, time){
    var scheduleNumber = null;
    
    if (Object.schedules == null){
        Object.schedules = [];
    }
   
   scheduleNumber = Object.schedules.push(this) - 1;
   code = code.replace(new RegExp('(\'|\\\\)', 'g'), '\\$1');
   return window.setTimeout('Object.schedules[' + scheduleNumber + '].eval(\'' + code + '\')', time);
};

Object.prototype.setInterval = function(code, time){
   var scheduleNumber = null;

   if (Object.schedules == null){
    Object.schedules = [];
   }
   
   scheduleNumber = Object.schedules.push(this) - 1;
   code = code.replace(new RegExp('(\'|\\\\)', 'g'), '\\$1');
   return window.setInterval('Object.schedules[' + scheduleNumber + '].eval(\'' + code + '\')', time);
};


Deze werkt alleen niet onder Mozilla bij mij. Ik heb ook nog op advies van een andere persoon het volgende geprobeerd, maar ook deze gaf geen krimp:

PHP:
1
2
var self = this;
setInterval(function() {self.selectByLabelPath(path);}, 100)



De functie als laatste die er gebruik van maakt is als volgt, en heeft als doel om via een pad de treeview uit te klappen:


PHP:
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
treeview.prototype.selectByLabelPath = function(path){
    
    var path;
    selectedNode = this;
    path = path.split(",");
    
    if(this.src != null && !this.loaded){
        this.load();
        /*
        var self = this;
        setInterval(function() {
            self.selectByLabelPath(path);
        }, 100)
        */
        this.setTimeout("this.selectByLabelPath('"+path+"')",100);
        return;
    }           
    
    var found = false;
    for(i=0;i<this.oNodeChilds.childNodes.length;i++){
        if(this.oNodeChilds.childNodes[i].obj.label == path[0]){
            this.oNodeChilds.childNodes[i].obj.select();
            found = true;
            break;
        }
    }
    
    if(!found){
        details = 'what happened: no childnodes found with provided label\nprovided label: '+path[0];
        alert('an error occured within treenode.prototype.selectByLabelPath or treeview.prototype.selectByLabelPath: \n\ndetails:\n' + details);
    }else{
        path = path.slice(1,path.length);
        if(path.length > 0){
            var tmp = '';
            for(i=0;i<path.length;i++){
                tmp += path[i];
                if(i<path.length-1){
                tmp += ',';
                }
            }
            path = tmp;
            selectedNode.selectByLabelPath(path);
        }
    }
}


Hoe gaat dit nu in Mozilla werken? :) OF nog beter crossbrowser :)

  • paragon
  • Registratie: April 2000
  • Laatst online: 20-08 22:56
Omdat de treeview xml datasources onder een node kan hebben, moet bij het uitklappen eerst de data worden ingeladen alvorens de childNode kan worden geselecteerd. Hiervoor gebruik ik setTimeout op het object, die vervolgens de functie opnieuw aanroept.
Dit gebeurt dus niet in mozilla, krijg je nog foutmelding? En als je het nou niet via een intervall/timeout probeert maar door bijvoorbeeld op eerste klik xml laden en 2de klik de rest?

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 20:27

crisp

Devver

Pixelated

Ik heb wel eens experimentjes van Clay gezien om timers te zetten op een object waarbij de executie in de scope van dat object draaide; zelf echter nog nooit mee geprutst (ook nooit echt nodig gehad).
Wil je dit doen uit purisme, of uit noodzaak?

Intentionally left blank


Verwijderd

Topicstarter
Het enige wat er gebeurt is dat die setTimeout functie niet wordt aangeroepen :)

Want de load method wordt wel aangeroepen, en elke keer als ik handmatig de method selectLabelByPath aanroep wordt de volgende node in het pad gepakt.

Ik zie toevallig net 2 errors opduiken in Mozilla.
nl:

path.split is not a function

die zal dan wel niet in Mozilla supported zijn

en

code.replace is not a function

Deze wordt dus in die object.prototype.settimeout gebruikt maar is wel vreemd ..

Verwijderd

Topicstarter
crisp schreef op 25 oktober 2003 @ 22:04:
Ik heb wel eens experimentjes van Clay gezien om timers te zetten op een object waarbij de executie in de scope van dat object draaide; zelf echter nog nooit mee geprutst (ook nooit echt nodig gehad).
Wil je dit doen uit purisme, of uit noodzaak?
Puur uit noodzaak. Aangezien onder Mozilla synchroon xmlHttp requests niet mogelijk zijn, gaat andere scripting gewoon door in een loop.

Ik moet gewoon de browser tijd geven om xml data in te laden, naar een set childNodes te outputten, en de nodes weer te geven om vervolgens geselecteerd te worden.

Bijv:
Ik selecteer het volgende pad 1,2,3

1
|-- 2
| |---3
|-- 3
|-- 4

Eerst wordt node 1 geselecteerd. Vervolgens wordt node 2 onder node 1 geselecteerd, maar als node 1 zijn childs niet heeft ingeladen krijg je dus een object expected geval.

Kortom, 1 moet eerst zijn data inladen, en daarna kan je pas childnode 2 selecteren.

In dat geval wordt de load method op de node aangeroepen, en een settimout gezet op de huidige method. Zodra de node is ingeladen stapt die over deze check heen.

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 20:27

crisp

Devver

Pixelated

Verwijderd schreef op 25 October 2003 @ 22:04:
Het enige wat er gebeurt is dat die setTimeout functie niet wordt aangeroepen :)

Want de load method wordt wel aangeroepen, en elke keer als ik handmatig de method selectLabelByPath aanroep wordt de volgende node in het pad gepakt.

Ik zie toevallig net 2 errors opduiken in Mozilla.
nl:

path.split is not a function

die zal dan wel niet in Mozilla supported zijn

en

code.replace is not a function

Deze wordt dus in die object.prototype.settimeout gebruikt maar is wel vreemd ..
split en replace worden wel degelijk door Mozilla ondersteund, echter moet je er rekening mee houden dat het methods zijn voor een String object - check even of je typen kloppen. Misschien is het ook wel handig niet dezelfde namen te gebruiken voor je prototypes als de globale methoden setTimeout en setInterval.

Wb noodzaak bedoelde ik of het noodzakelijk is dat je de timeouts in de scope van het object staan. De meest gangbare methode is om een referentie naar het object globaal op te slaan en een 'key' mee te sturen met je functie in de timeout waarmee je in de functie weer het object kan ophalen uit je global (meestal een array)

Intentionally left blank


Verwijderd

Topicstarter
Ik doe zojuist een testje nl:

PHP:
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
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Untitled Document</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

<script type="text/javascript">
function mijnobject(){
    this.init();
}
mijnobject.prototype.init = function(){
alert('init');
    var self = this;
        setTimeout(function() {
            self.init();
        }, 5000)
}
</script>
</head>

<body onload="new mijnobject()">


</body>
</html>


En die werkt vreemd genoeg wel. Ik vraag me dus af of mijn structuur qua object niet te complex is voor de browser :? ..

Het zit dus overduidelijk in mijn code, en niet in missende browser functionaliteit.

Verwijderd

Topicstarter
Ben er al uit gewoon een stomme fout. Ik had in de setTimeout het attribuut path meegegeven. Zodra je dit meegeeft alla '+path+' gaat het ok, maar zodra je het als een directe variabele toevoegt ook mits je er voorheen een array van had gemaakt :P |:( ...

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

Clay

cookie erbij?

Verwijderd schreef op 25 oktober 2003 @ 22:14:
[...]

Puur uit noodzaak. Aangezien onder Mozilla synchroon xmlHttp requests niet mogelijk zijn, gaat andere scripting gewoon door in een loop.
volgens mij is dit voorbeeld anders wel synchroon, en werkt hier in moz/fb prima.

JavaScript:
1
2
3
4
5
6
7
8
9
10
function loadXML(url) {
    try { xmlhttp = new XMLHttpRequest(); } 
    catch (e) { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); }
    
    xmlhttp.open("GET", url, false);
    xmlhttp.send(null); 
    return xmlhttp.responseText;
}

alert(loadXML('test.xml'))
crisp schreef op 25 October 2003 @ 22:04:
Ik heb wel eens experimentjes van Clay gezien om timers te zetten op een object waarbij de executie in de scope van dat object draaide; zelf echter nog nooit mee geprutst (ook nooit echt nodig gehad).
Wil je dit doen uit purisme, of uit noodzaak?
Dat berust dus op het meegeven van een functieref in de timeout of interval in plaats van een string die ge-evalt wordt. Verder gebruik ik dan ook een apply, daarmee kan je een willekeurige functie laten uitvoeren in de scope van een willekeurig object, met een willekeurig aantal params:

code:
1
functieReferentie.apply(objectScope, argumentsArray);


Je zou b.v de resizeTo van window daarmee expliciet op window laten uitvoeren met:

code:
1
resizeTo.apply(window, [320, 240]);


ware het niet dat IE een bug heeft die dit ene voorbeeld onmogelijk maakt :P maar moz doet het wel. Zo kan je dan b.v. een Tread object bouwen, die je gewoon een scope voert, en een string of functieref (afhankelijk van hoe je het bouwt, kan alletwee, maar ik houd het bij de string) om zo met een interval gescoped functies uit te voeren:

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
function Thread() { }
Thread.prototype = {
    run:function(ref, specs) {
        this.stop();
        this.timer = setInterval(function(){ 
            specs.scope[ref].apply(specs.scope, specs.arguments);
        }, specs.delay);
    },

    stop:function() {
        if(this.timer) 
            clearInterval(this.timer);
    }
}


// Counter
// ----------------
function Counter() {
    this.n = 0;
}

Counter.prototype.count = function(n) {
    window.status = (this.n += n);
}

// Test
// ----------------
window.onload = function() {
    var counter = new Counter();
    var thread = new Thread();

    thread.run('count', {scope:counter, arguments:[1], delay:100});
}


de truuk zit em dan in deze regel:

JavaScript:
1
specs.scope[ref].apply(specs.scope, specs.arguments);


de ref is een string, de functie ref zit dan in de string index property van de scope (al moet je object die functie dan wel hebben!), de apply plakt de functie weer aan het object, en de argumenten had je zelf meegegeven. Het klinkt misschien als abracadabra, maar als je het doorhebt is het eigenlijk heel makkelijk O-)

[ Voor 3% gewijzigd door crisp op 26-10-2003 13:58 . Reden: code fix ]

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

Pagina: 1