Connexion

javascript eval global

Posté le Dimanche 1 octobre 2006 à 12 h 33, Read it in english with Google

ça fait un peu près 1 mois que je cherche à exécuter mon code javascript contenu dans mes données chargées via AJAX. Tout le monde me dira qu’il existe eval, seulement voila, ceci ne marche uniquement pour le code éxécuté en live et non pour les déclaration de fonction.

En effet, même dans le framework du style prototype, eval() est déclaré dans le contexte de l’objet AJAX, autrement dit dans la fonction AJAX. Ainsi toute les fonctions déclarées dans eval ne sont disponibles que dans la fonction où l’on fait le eval().

un petit exemple pour m’expliquer :

function myeval(){
  eval(‘function test(){alert(’test ok‘);}’);
  alert(typeof(test)); //affiche function
  test(); // affiche ‘test ok’
}
myeval();
alert(typeof(test)); //affiche undefined
test(); // erreur : fonction test inconnu

ceci peut poser de gros problèmes pour déclarer des objects via AJAX :

//x est votre object XMLHttpRequest
x.onreadystatechange = function (){
  if (this.readyState == 4 && this.status == 200){
    var c = document.getElementById(‘monconteneur’);
    c.innerHTML = x.responseText;
    //maintenant que les données reçu on été placé dans la page,
    //il faut exécuter toutes les balise script :
    var allscript = c.getElementsByTagName(’script’);
    for(var i=0;i< allscript.length;i++){
      eval(allscript[i].text);
    }
    alert(typeof(une_function_dans_mes_balise_script));//return function
  }
}

seulement voilà : si maintenant vous avez un bouton avec dans l’action onClick une fonction qui est déclaré dans la page chargé, celle ci ne s’éxécutera pas car elle n’est pas déclaré dans un contexte global mais seulement dans la fonction onreadystatechange.

Mais, pour toi public, j’ai la solution. vous pouvez utiliser :

window.eval();
//ou encore :
var global = this; //dans un contexte global
//puis
global.eval();

vos function seront alors déclarée dans un contexte global.
var global = this; est utilisé pour forcé la compatibilité.

A noté que les différents framework tel que prototype n’exécute pas vos script via eval dans un contexte global (voir la function evalScripts pour prototype).

Je ne vous cache pas que j’ai galéré pour un truc tout con cependant astucieux :)

35 Réponses à “javascript eval global”

  1. Skan

    Je crois avoir le même problème avec Firefox et les feuilles XSL (pas testé sur IE) mais ça passe sur Safari, et p’tre encore aussi le même problème lors d’inclusion de multiples SVG…

    Aurais-tu un exemple de code?
    Ton window.eval() tu le mets dans la page “racine” ou dans chaque module chargé?

    Merci :)

  2. XoraX

    euh.. qu’est-ce que t’entend par “dans chaque modules chargé” ?
    le window.eval() tu peu le mettre où tu veux tant que t’es sur qu’il va s’exécutér.

    dans l’exemple du dessus je mettrais :
    window.eval(allscript[i].text);
    au lieu de :
    eval(allscript[i].text);

    si ça passe pas, tu mets var global = this; à la racine de chez racine puis t’utilise global.eval(); dans tes fonctions.

  3. Skan

    Merci ^^

    Mais en fait c’est pas ça :/

    Firefox 2: les javascripts dans les feuilles XSL importées ne sont pas exécutés. Même un alert(’toto’) ne donne rien. Par contre les Javascripts de la feuille XSL initiate fonctionnent bien.

    Safari 2 (+Webkit): un élément SVG déclaré dans un fichier SVG () est considéré comme un bloc. J’aurais mis ça aurait été pareil. Les événements de clic sont envoyés à et non sur le nœud id=3 si j’avais cliqué dessus. C’est un peu comme mettre un gif transparent au-dessus d’une page web, on ne peut alors plus cliquer sur les liens :/
    Et évidemment c’est p’tre pas correcte de réutiliser la balise SVG à l’intérieur d’elle-même :p

    Je sens que je vais aller poser ma question sur svgfr.org car en gros j’ai un fichier XML généré dynamiquement. Celui-ci appelle une feuille de transformation XSL. Et quand je reconnais dans mon fichier XML la balise (par exemple), alors j’appelle un template importé de la feuille XSL qui me génère mes curseurs (de même pour des molettes, des joysticks…)

    Et donc, je cherche une balise SVG qui me permette de définir des nouveaux repères histoire de pouvoir faire un zoom sur mon espace de travail sans grossir le HUD, bref plein de choses ^^

  4. Skan

    Tout simplement ^^
    Heureusement “transform” n’agit pas comme “style”: un “style” parent est prioritaire sur les “style” de ses nœuds enfants. “transform” s’applique en plus.

  5. Alex

    Merveilleux!

    C’est exactement sur quoi j’ai gossé toute la soirée, excepté que moi c’est avec un IFRAME créé dynamiquement.

    Bref, merci d’avoir posté ceci ;)

  6. guillaume

    Merci,

    je galere depuis 2 jours la dessus, et grace a toi tout fonctionne !

    by

  7. XoraX

    de rien ;) merci d’être passé!
    ++

  8. Cyrille

    Superbe script j’ai jusqu’ici contourné l’utilisation du javascript sur des fichiers chargés au détriment de l’ergonomie… Et maintenant, c’est la grande classe. Merci pour ton post, très pratique, j’ai eu du mal à trouver un script fonctionnel ! ++

  9. XoraX

    Merci! moi aussi je t’explique pas comment j’ai rouillé pour trouver ça d’ailleur je l’ai vu sur un site chinois ou japonais je sais pas j’ai pas pu lire la page juste le bout de code :D ++

  10. Belette

    Tout simplement royal!!!
    Comme quoi des fois ca vaut la peine de se creuser les neurones…

  11. Belette

    Dans le même esprit, existe t’il une autre solution miracle pour que les appels de scripts externe depuis des page ouvertes en ajax, genre :

    soient également traités dans un contexte global?

  12. Belette

    désolé les balises n’ont pas été prises en compte… il fallait lire :
    script type=”text/javascript” src=”./includes/FCKEditor/fckeditor.js”

  13. XoraX

    et oui ça prend pas le fichier mais tu oeu te débrouiller :

    for(var i=0;i< allscript.length;i++){
    if(allscript[i].src){
    //et la tu fais un new XHR en l’obligeant à faire un window.eval() sur le responseText
    } else {
    window.eval(allscript[i].text);
    }
    }

    cela dit après il va falloir que tu gère un certain système de cache afin d’évité de recharger 2 fois le même fichier et de redéclarer tes fonctions et autre. Donc met un tableau quelque part où tu va stocké tout les noms des fichiers script déjà télécharger.

    Je sens que je vais faire un add-on à prototype :)

  14. belette

    Effectivement ca marche du feu de dieu, merci Xorax!
    Pour l’histoire d’un système de cache je me demande si ce ne serait pas plus simple de controler dans les fichiers js inclus de la sorte, si l’une des fonctions ou variables déclarées existe déja dans le contexte global, et si c’est le cas, de ne pas traiter le fichier.
    Je teste ca, et je donnerais le résultat…

  15. Juju

    Merci beaucoup, je commencais a desesperer à trouver la soluce.

  16. Juju

    Bonjour,
    j’ai trouver bien utile ton bout de code, mais j’ai un souci sous IE
    En fait lors de certaines réponse j’ai dans mon contenu une redirection du type parent.window.location, que je recupere bien, mais une fois que je modifie mon div, il n’est jamais interpréter, et quand je vais revérifier son contenu, en effet le contenu est vide

    voici mon bout de code, quand j’ai la réponse ajax
    var global = http_request;
    var c = document.getElementById(’contenu’);
    c.innerHTML = http_request.responseText;
    //maintenant que les données reçu on été placé dans la page,
    //il faut exécuter toutes les balise script :
    var allscript = c.getElementsByTagName(’script’);
    for(var i=0;i

  17. XoraX

    humm… je vois pas bien ce qui marche pas. y me faut plus de code!

    si tu cherche à modifier le contenu dans ta parent.window, il faudra faire un parent.window.document.getElementById(’contenu’); en espérant que ça passe au niveau sécurité…

  18. XoraX

    allez ça y est mon add-on protoype est pret !! :D

    il va permettre de faire un global.eval sur les codes inclus dans les balises script mais pas seulement !!
    il va également allez rechercher tout les fichiers script inclus du style
    script src=\”monjs.js\”
    et tout ça via ajax bien sur ;)

    je le mettrais la semaine prochaine en ligne pour l\’instant dodo :)

    ps: ouè je sais wordpress c\’est de la merde pour les commentaires pas moyen d\’éclire ce qu\’on veut sans qu\’il vire des trucs se bouffon… mais j\’ai pas envie de plonger le nez dans la bouzzz

  19. Julien

    Recoucou
    je revient vers ce site pour soumettre un probleme
    en fait ma réponse ajax me renvoit des déclarations de variables de type :
    var infoEE84 = [’UIOM DE DOUCHY’,”,”,’59282′,’Douchy-les-Mines’,”,’(UIOM) Unité d\’incinération des ordures ménagères’,'UIOM DE DOUCHY’];var infoEE85 = [’UIOM DE MAUBEUGE’,”,”,’59600′,’Maubeuge’,”,’(UIOM) Unité d\’incinération des ordures ménagères’,'UIOM DE MAUBEUGE’];

    et du code HTML exploitant ces données (toutes les fonctions étant déclarées avant)
    mais en fait il est impossible d’utiliser ces données
    je comprend pas pourquoi, si vous avez déja rencontré ce souci postez je reviendrai
    Merci par avance

  20. XoraX

    humm il faudrait des précisions.

    tu dois faire window.eval sur tes données avant d’afficher le code html.
    ton code javascript (inclue dans les balise script) dans ton code html chargé via ajax ne peut pas écrire directement afin de retourné un code html différent.
    Il peut y avoir uniquement des apel de fonction dans des événement du genre onclick=”mafonction();”

    il faudrait plus de code pour que je puisse t’aider.

  21. Julien

    Merci de ton aide
    Le problème c’est que je peut pas faire un window.eval sur ma réponse Ajax car j’ai du javascript et du html.
    Cependant j’ai vérifier via firefox et “afficher le code source de la sélection” que j’ai bien mes variables qui sont déclarées
    Mais impossible de les utiliser
    un peu plus de code :
    resultat = http_request.responseText;
    setBlocSINOE(infoCorrespondance,resultat);

    var setBlocSINOE = function(divContent, HTML) {

    document.getElementById(’infoCorrespondance’).innerHTML = HTML;

    }

  22. XoraX

    ok :)
    désolé mais tu va être obligé de faire un window.eval, je ne sais pas ce que te dit firefox mais c’est sur que tes variable ne sont pas déclaré.
    c’est pas grave si ta du javascript et du html, pour remprendre ton code :

    resultat = http_request.responseText;
    setBlocSINOE(infoCorrespondance,resultat);

    var setBlocSINOE = function(divContent, HTML) {

    var e = document.getElementById(’infoCorrespondance’);
    e.innerHTML = HTML;

    var allscript = e.getElementsByTagName(’script’);

    for(var i=0;i< allscript.length;i++){
    eval(allscript[i].text);
    }

    }

  23. Julien

    Merci pour ton aide vraiment
    Mais malheureusement ca ne marche pas
    Je vais devoir trouver une autre technique, en effet je ne passe meme pas dans le for
    Le pire dans tout cas, c’est que je suis sur que je recupere bien ce code javascript.
    Enfin bon du coup j’ai charger mes 1000 lignes de résultat possible dans ma page d’appel
    C’est nul je sais mais ca marche en attendant de trouver la solution

    Et encore merci pour ton aide

  24. belette

    Salut,
    J’ai également un problème avec IE et les chargement de pages AJAX :
    Sur une inclusion d’un fichier .js dans une page chargé en AJAX, le global.eval(obj.responseText); (le responseText étant le contenu de mon fichier .js inclus) ne semble pas traiter le code qui n’est pas inclus dans des fonctions.
    Par exemple une simple variable “var toto=1″ n’est pas déclaré, une fonction alert(”toto”); n’est pas traité.
    Par contre toutes les autres fonctions déclarées dans le fichier .js sont bien traitées dans le contexte global….
    Aurais tu une idée du problème?

  25. belette

    re,
    j’amène un peu plus de précision sur le problème cité sur mon post précédent.
    En fait cela fonctionne bien également pour les appels de fonctions. Le problème porte en fait uniquement sur les déclarations de variables globales et pas seulement dans des fichiers .js inclus mais aussi dans une page chargé en Ajax.
    Exemple :
    echo ” var titi=’my name is titi’; alert(titi); “;
    echo ‘afficher titi‘;
    le premier alert(titi) fonctionne, preuve que la première ligne à bien été traitée par le chargement Ajax.
    En revanche lors d’un appel a titi en dehors de la première séquence de script, IE renvoie l’erreur : ‘titi est indéfini’
    IE gèrerait il les variables ou le contexte global d’une manières différentes? s’agit il ici d’une sécurité de sa part?
    Pour info la version de IE utilisé est la 6.0 (le 7 plante lamentablement sur mon pc, je n’ai pas pu encore le tester…)

  26. belette

    Il fallait lire :
    echo ” script var titi=’my name is titi’; alert(titi); /script “;
    echo ‘ a href=”#” onClick=”alert(titi);” afficher titi /a ‘;

  27. XoraX

    bon apparement IE 6 c’est de la belle daube… mais ça c’est pas nouveau :)

    en gros il gère mal les déclaration de variable avec “var” devant. pour reprendre ton exemple il faudrais faire :

    echo ” script titi=’my name is titi’; alert(titi); /script “;
    echo ‘ a href=”#” onClick=”alert(titi);” afficher titi /a ‘;

    bref on est contraint de ne pas respecter le W3C. Heureusement, une déclaration comme ça ne pose pas de problème sur les autres navigateurs qui sont beaucoup plus indulgent voir même intelligent.

    Merci d’avoir fais remarqué ça je crois que j’aurais eu des problème par la suite…

  28. belette

    Salut,
    Je viens de faire quelques tests de compatibilités avec quelques navigo.
    Il semblerait qu’Opéra n’aime pas trop les :

    document.getElementById(div_to_load).innerHTML=obj.responseText;
    y_exec_scripts(document.getElementById(div_to_load));

    (y_exec_scripts étant la fonction d’éxec du js.)

    En revanche, il semble bien apprécier :

    document.getElementById(div_to_load).innerHTML=”;
    var ndiv = document.createElement(’div’);
    ndiv.innerHTML=obj.responseText;
    document.getElementById(div_to_load).appendChild(ndiv);

    A priori les navigateurs, éxécute par eux meme le js du innerHTML lors de l’appendChild, c’est assez étonnant… Firefox le fait trés bien, IE un peu moins… donc pour Opéra pas besoin a priori d’évaluer le js par la suite.
    En ce qui concerne netscape, la première méthode de xorax fonctionne bien, mais j’ai constaté un bug bizzare déformant les pages si on a des inclusions de fichiers js en milieu de page, en la mettant à la fin du code, le problème disparait…

    Je continue de tester cela et vous tiens informer

  29. ZeLegolas

    En remplacant :

    function myeval(){
    eval(‘function test(){alert(’test ok‘);}’);
    alert(typeof(test)); //affiche function
    test(); // affiche ‘test ok’
    }

    par

    myeval = function(){
    eval(‘function test(){alert(’test ok‘);}’);
    alert(typeof(test)); //affiche function
    test(); // affiche ‘test ok’
    }

    ca a marche pour moi

  30. kankrelune

    Moi je fais légèrement différament… je déclare mes fonctions dans un fichiers js ce dernier étant inclu dans le code html renvoyé par le raquette XMLHttpRequest… ensuite il me suffit de faire… .. .

    var includedModulesJs = new Array;
    
    function includeJs(src)
    {
    	if(!includedModulesJs[src])
    	{
    		var s = document.createElement("script");
    		s.src = src;
    		head = document.getElementsByTagName('head')[0];
    		head.appendChild(s);
    		includedModulesJs[src] = true;
    	}
    }
    
    function setInnerContents(targetObj, contents)
    {
    	targetObj.innerHTML = contents;
    
    	var allJs = targetObj.getElementsByTagName(”script”);
    
    	for(var i=0; i < allJs.length; i++)
    	{
    		if(allJs[i].src && allJs[i].src != “”)
    		includeJs(allJs[i].src);
    		else
    		window.eval(allJs[i].innerHTML);
    	}
    }
    

    ensuite il suffit de faire par exemple…

    setInnerContents(document.getElementById(”maDiv”), ajaxObject.responseText);

    ;o)

    @ tchaOo°

  31. javascript eval global : part 2 contient sur le sujet :

    […] Après une première approche non sans faille de l’évaluation d’un code javascript dans un contexte global , voici la seconde version, compatible FireFox et IE et tout les navigateurs dérivés. Code (javascript) […]

    le Mardi 27 février 2007 @ 13 h 04
  32. XoraX

    bonne méthode au fait kankrelune
    j’avais testé une fois mais j’avais surement du faire une erreur parce que ça foirait :)
    thanks!

  33. javascript eval global final contient sur le sujet :

    […] Historique : eval global partie 2, eval global […]

    le Mercredi 11 avril 2007 @ 17 h 16
  34. Fred

    Hello à tous
    je pose un probleme qui je ne vais pas encore croisé par la.
    Je veux utiliser un effet drag and drop dans mes fichiers retournées par ajax.
    J’utilise une application qui doit executer du cide javascript au retour des données envoyées par ajax. La méthode Xorax est niquel mais un probleme e pose lors de l’ajout au window.OnLoad .
    En gros les fonctions window.onload = function (){ ….. } ne s’executent pas …..

    Un petit peu d’aide ?

    merci bcp

  35. XoraX

    si tu utilise prototype :

    Event.observe(window, 'load', function(){
    ...
    }
    

    sinon, à chaque fois que tu veux ajouter un écouteur :

    function addLoadEvent(func) {
      var oldfunc = window.onload || function(){} ;
      window.onload = function () {
        oldfunc();
        func();
      }
    }
    

    mais je crois que ton problème c’est plutôt, que tu charge du contenu en ajax donc l’apel à window.onload ne se fait pas. Donc tu dois le faire toi-même si tu le souhaite à chaque fois que tu as fini un XHR tu lance window.onload();, tout simplement.

    en passan je ferme les commentaires pour cet article, allez voir la nouvelle version ;)

Les commentaires sont fermés.