11550 sujets

JavaScript, DOM et API Web HTML5

Bonjour à tous,
Je viens vers vous avec un soucis que je ne parviens pas à régler meme en "googlelisant" à fond...j'ai bien peur que la solution n'existe pas, mais au cas ou je préfère quand meme demander votre avis...


Voila, dans le cadre du developpement d'un mini framework JS, je me refuse à includer systématiquement une ribambelle de fichier JS (1 par type de composants) dans chacun des mes fichiers HTML.

Ce que je veux, c'est avoir une seul balise script pointant vers un fichier "engine.js" et que ce soit celui-ci qui include (ou non) les composant (fichier js) dont la page à besoin

Ca parait compliqué, mais je m'y retrouve et tout fonctionne bien à un (gros) détail près.

En effet, ma fonction pour includer utiliser le DOM pour créer une nouvelle balise de type "script" puis lui affecter un type (text/javascript) et un src (chemin vers le js en question).

Le soucis, c'est que quand j'utilise cette fonction, bien que le script soit bien ajouté à l'arbre DOM (en mettant en simple alert() en début du fichier à includer, on voit bien que le script est interprété puisque l'alert apparait à l'execution), les fonctions déclarées dans le JS includé ne sont pas directement accessible. Il me faut sortir de la fonction ayant fait l'include avant qu'elle ne soient accessible.

pour illustrer un peu voici 2 petits exemples:


ce qui marche po:



   <html>
     <head
       <script type='text/javascript'>
  
              function include(sFilePath) {
                 
                  var oScript = document.createElement('script');
                  oScript.type = 'text/javascript';
                  oScript.src = sFilePath;
                  document.getElementsByTagName('heade')[0].appendChild(oScript);

              }

              function test() {

                    include('monfichier.js');
                    fonctiondansmonfichier();

              }

        </script>
      </head>
      <body>
             <input type='button' OnClick='test();'>
      </body>
</html>


ce qui marche



   <html>
     <head
       <script type='text/javascript'>
  
              function include(sFilePath) {
                 
                  var oScript = document.createElement('script');
                  oScript.type = 'text/javascript';
                  oScript.src = sFilePath;
                  document.getElementsByTagName('heade')[0].appendChild(oScript);

              }

              function test() {

                    include('monfichier.js');

              }

        </script>
      </head>
      <body>
             <input type='button' OnClick='test();'>
             <input type='button' OnClick='fonctiondansmonfichier();'>
      </body>
</html>



Voila, bah si quelqu'un pouvait me dire comment faire en sorte de pouvoir dierctement utiliser les fonctions ajouter ainsi ca m'arrangerait très beaucoup Smiley smile

merci d'avoir lut jusqu'au bout en tous cas
Salut,

J'imagine que c'est getElementsByTagName('head') plutôt que 'heade' ...

Il y a plein de solutions pour inclure des fichiers dynamiquement.

Le problème qui se pose est que ton fichier est chargé au moment de ton événement onclick, celui risque donc soit de ne pas fonctionner soit d'être lent à réagir.

Ce qu'il faut faire c'est donc inclure tes fichiers via ton script engine.js et "externaliser" les événements dans un autre script qui peut être chargé dynamiquement aussi.
matmat a écrit :
Salut,

J'imagine que c'est getElementsByTagName('head') plutôt que 'heade' ...

Il y a plein de solutions pour inclure des fichiers dynamiquement.

Le problème qui se pose est que ton fichier est chargé au moment de ton événement onclick, celui risque donc soit de ne pas fonctionner soit d'être lent à réagir.

Ce qu'il faut faire c'est donc inclure tes fichiers via ton script engine.js et "externaliser" les événements dans un autre script qui peut être chargé dynamiquement aussi.



Alors oui j'ai fais une faute de frappe en mettant "heade" à la place de "head". Seulement les fonctions que je vous ai donner ne sont pas celle qui j'utilise, j'ai juste tenter d'isoler le plus important pour la compréhension du problème en écrivant ces fonctions au moment ou j'ai rédiger ce sujet.

A force de chercher sur ce problème, j'ai fini par comprendre ce qu'il se passe, sauf pour autant savoir comment y remédier:
En Javascript, lorsqu'on appelle une fonction (ou qu'un évènement utilisateur intervient), un contexte d'exécution est créé. La autres fonctions des différents scripts (ainsi que les variables globales, etc.) sont copiés comme propriété de l'objet "contexte" (qu'on peut utiliser via la variable "this" que vous connaissez surrement). Lorsque ma fonction ajoute le script externe à l'arbre DOM, le contexte n'est pas mit à jour, ce qui explique que les fonctions déclarées dans mon script externe ne sont pas connu par le contexte de la fonction appelante. Il n'y à que lorsque qu'une nouvelle fonction sera appeller (par un événement utilisateur ou éventuellement un setTimeout) qu'un nouveau contexte sera créer et que les nouvelles fonctions serons accessible.
En gros, il faudrait que je puisse demander à l'interpréteur JS du navigateur de recharger le contexte d'execution de la fonction....mais je cherche encore comment faire (si toutes fois cela est possible)

merci en tous cas pour ta réponse
Comme je te disais il y a pas mal de solutions, après je ne sais pas exactement quelle est la plus pertinente, ni si la démarche est réellement pertinente.

A mon avis il est préférable d'utiliser une méthode coté serveur qui compile tes scripts en un seul selon les besoins.



Imaginons que tu es un fichier a inclure comme ça :

var Fichier1 = {
  testInclude : function(text){
    alert(text);
  }
}

Dans ta fonction inclure il faut t'assurer que la fonction attend que les scripts soit chargés avant de passer à la phase suivante, un peu comme en ajax :
function include(sFilePath,fnc){
  var oScript = document.createElement('script');
  oScript.type = 'text/javascript';
  oScript.src = sFilePath;
  document.getElementsByTagName('head')[0].appendChild(oScript);
  if(window.ActiveXObject){
    oScript.onreadystatechange = function(){
      if(this.readyState == "complete"){
        fnc.call();
      }
    };
  }else{
    oScript.onload = function(){
      fnc.call();
    };
  }
}


Ensuite tu fais:
includeScript('monfichier.js',testFunction);

function testFunction(){
  Fichier1.testInclude('test');
}

tu peux très bien imaginer que tu envois un tableau de toutes tes fonctions pour simplifier la chose :

var scripts = new Array(
   'fichier1',
   'fichier2',
   'fichier3'
)
includeScript(scripts,testFunction);

function testFunction(){
   Fichier1.testInclude('test');
   Fichier2.maFunction();
   Fichier3.monAutreFunction();
}

Il faut bien sur modifier la fonction include pour quelle accepte un tableau.
Modifié par matmat (12 Nov 2008 - 18:55)
merci de ta réponse, mais le soucis n'est pas au niveau de l'execution des fonctions et du fait que cela soit synchrone ou pas, mais bien au niveau du contexte d'execution, de l'ensemble des variables sytème, fonction native et fonction ajoutée qui sont présentes lors de l'appel à une fonction et qui ne bouge - théoriquement - pas jusqu'a la fin de l'execution de celle ci...sauf que justement, je change un paramètre de ce contexte en ajoutant des fonctions qui n'étaient pas présente au moment de la création du contexte.
Tu peux tout à fait étendre une classe déja presente:
function extend(className,obj){
   for (var property in obj) className.prototype[ property ] = obj[ property ];
};


Ce qui donne:
var MaClass = function(){
   this.options = {
      option1:'value',
      option2:'value'
   };
};
include('fichier.js',testFunction);
function testFunction(){
   extend(MaClass,include)
   var oMaClass = new MaClass();
   oMaClass.testInclude('test');
}


Tu peux ainsi rajouter des méthodes dynamiquement à ta classe, par contre à voir si c'est pas plus robuste et surtout plus sécurisé de faire ça avec json et ajax.
Modifié par matmat (13 Nov 2008 - 00:31)