11548 sujets

JavaScript, DOM et API Web HTML5

Bonjour,

J'ai le bout de code HTML suivant :


<div id='modele'>
<table>
  <tr>
    <td style='color:red; [b]%prop%[/b]'>Hello world !
    </td>
  </tr
</table>
</div>


Notez la présence de %prop% qui va être traité ensuite :

template = document.getElementById("modele").innerHTML;
template = template.replace("%prop%","width:50%");


Et bien, avant même de faire le replace, la chaine %prop% a disparu de template !
Après quelques tests, je me suis rendu compte qu'en renommant l'attribut "style" en "_style", cette fois-ci, cela marchait Smiley eek !

Tout se passe donc comme si le contenu de l'attribut était épuré des propriétés inconnues !
Salut,

hem... voilà une bien étrange façon de faire du web ! Smiley langue

Pour rappel JavaScript peut être désactivé/indisponible et il faut donc que le code original soit valide. On évitera donc les attributs et les valeurs inexistantes.

Ensuite je ne sais pas trop ce que tu veux faire (par exemple j'imagine plus un langage serveur tel que PHP pour gérer les templates) mais s'il s'agit d'affecter des styles différents via JavaScript je t'invite à regarder cette solution proposée par Gatsu35.
Modifié par Heyoan (10 Jun 2009 - 15:17)
marcmendez a écrit :
Tout se passe donc comme si le contenu de l'attribut était épuré des propriétés inconnues !

C'est le cas, et c'est un comportement tout à fait logique. Le navigateur attend un contenu de type style sheet data, et doit parser ce contenu pour construire le DOM. Tout ce qui n'est pas reconnu est écarté...

Le problème de récupérer ton template avec innerHTML, c'est que tu ne récupères pas (il me semble) le code HTML correspondant, mais sa traduction interne par le navigateur. Donc aucune garantie que tes %marqueurs% soient conservés.

Une solution possible: si tu as besoin de placer le template dans la page HTML, tu peux éventuellement placer un élément SCRIPT pour le déclarer comme variable JS.
<script type="text/javascript">
var machintruc_template = "<table>\n\
    ...\n\
</table>\n\";
</script>

Bon, la chaine de caractères multi-lignes avec un \ ça marche, mais théoriquement ce n'est pas standard. (Et, en HTML 4, il faudrait théoriquement échapper les «</» dans le code JS; no souci en HTML 5.)
Bonjour,

Je comprends ton interrogation, mais plutot stricte sans connaître le contexte Smiley cligne

Je suis exclusivement en intranet, donc les problèmes d'activation ou non de JS ne sont pas d'actualité dans mon cas. Et non, mes utilisateurs ne changent pas la configuration, et ... enfin, bref, pas de problème de disponibilité de JS Smiley langue . Sinon, crois bien que j'opèrerais différement.
Quant à la notion de template, cela dépend des conditions qui influent sur ton affichage. Si tes conditions ne dépendent pas de l'action de ton utilisateur sur la page ou que tu recharges ta pages entre deux actions "influentes", oui, tu le fais en PHP (et j'aimerais bien...). Dans mon cas, le code en question réagit à des choix de l'utilisateur sur la page en question et je ne recharge pas la page entre deux actions de l'utilisateur (ça serait ultra lourd !). Le (re)traitement de l'affichage se fait donc côté client exclusivement.

Dans mon cas, je pense éventuellement avoir une solution alternative.

<td class='%prop%' style='color:red;'></td>

Et là, j'applique le replace pour changer la classe.

NB : notez dans l'exemple initial que le premier argument de replace est censé être un RegExp et non une chaine de caractère... Smiley confused Smiley rolleyes
Modifié par marcmendez (10 Jun 2009 - 16:27)
marcmendez a écrit :
Je suis exclusivement en intranet
C'est vrai que cela change la donne... même si personnellement je reste adepte du code valide même pour une partie d'un site en back-office dans laquelle j'oblige l'activation du JavaScript ne serait-ce que pour ne pas avoir de surprises au niveau du DOM. Smiley cligne

De la même façon j'aurais plutôt utilisé un nom de classe valide (comme classe_base) plutôt que %prop%.
J'ai l'immense chanc (et je pèse mes mots), d'avoir des utilisateurs ultra disciplinés... Smiley lol C'est tout juste s'ils appelent pas pour avoir l'autorisation de cliquer sur un bouton Smiley rolleyes

Bref, pour le nom de la classe, je serai d'accord, mais, par expérience, je préfère volontairement mettre un nom atypique et facilement "parsable", pour éviter tout effet de bord avec un autre bout de texte dans mon modèle. N'oublie pas que je fais un replace "bourrin". Ainsi, "maclasse_base" contient la sous-chaine "classe_base"... tu vois où je veux en venir...
Cette précaution est d'autant plus vrai qu'en fait, le texte HTML de mon modèle est contenu dans un fichier externe à ma page PHP. Cette externalisation permet d'éditer facilement le code du modèle (pour avoir une vision de ce que ça va donner à la fin) avec un éditeur HTML (pas trop regardant sur la syntaxe, car il n'y a pas de balise HTML ou BODY). L'édition est faite toutefois par un informaticien.

Donc, je ne suis pas à l'abri que quelqu'un saisisse dans la page HTML du modèle un texte qui contienne, comble de malchance, un bout du nom de ma "variable"....
Ok, je te le concède, avec "classe_base", 'faudra me donner des exemples de texte qui pourraient le contenir... mais enfin, ton exemple est juste illustratif Smiley ravi . En encadrant avec des "%" des "$" ou des "_" (ce dernier cas serait éventuellement plus acceptable), je réduis le risque d'effet de bord.
Arf ! Ben du coup je suis d'accord avec toi ! Smiley langue

Mais ça veut dire que je ne peux plus t'embêter !... Ah si ! Moi, Je et moi-même on aurait plutôt utilisé les méthodes du DOM à la place du innerHTML et le nom de la classe ne posait plus de problème !

Bon... mais c'était juste pour rire. Smiley biggol
Heyoan a écrit :
Arf ! Ben du coup je suis d'accord avec toi ! Smiley langue

Mais ça veut dire que je ne peux plus t'embêter !... Ah si ! Moi, Je et moi-même on aurait plutôt utilisé les méthodes du DOM à la place du innerHTML et le nom de la classe ne posait plus de problème !

Bon... mais c'était juste pour rire. Smiley biggol


Nananananère....

Ah, DOM versus innerHTML ! Là, je te renvois à la discussion initiale que j'ai eu il y a quelques jours sur ce même forum, concernant justement ce bout de code. Pour résumé, j'avais demandé, dans le cas de la gestion d'un template via JS, de l'utilisation du innerHTML ou du DOM, quelle méthode était la plus pratique.
Mon template est assez complexe (une table avec des colspan dans tous les sens, pour résumer des informations saisies sur la page). J'avais opté pour ce système de template et de fichier externe pour éviter d'avoir à me coder manuellement tout le tableau. Là, je peux modifier aisément le template avec un éditeur HTML, sans avoir à rentrer dans mon code PHP ou JS.
Je n'aurais qu'un ou deux "variables" à changer, le DOM suffirait. Là, j'en ai plus d'une trentaine, réparties un peu partout !
marcmendez a écrit :
Ah, DOM versus innerHTML ! Là, je te renvois à la discussion initiale que j'ai eu il y a quelques jours sur ce même forum
Il se trouve que j'ai également participé à une telle discussion voilà quelques jours. Smiley smile
Florent V. a écrit :

C'est le cas, et c'est un comportement tout à fait logique. Le navigateur attend un contenu de type style sheet data, et doit parser ce contenu pour construire le DOM. Tout ce qui n'est pas reconnu est écarté...

Le problème de récupérer ton template avec innerHTML, c'est que tu ne récupères pas (il me semble) le code HTML correspondant, mais sa traduction interne par le navigateur. Donc aucune garantie que tes %marqueurs% soient conservés.

C'est ce que je pense. Tant que mes marqueurs ne sont pas à une position stratégique, ça passe. Mais, à ta charge, note que si je mets un attribut qui n'existe pas, c'est pas pour autant qu'il l'épure

<td _style='color:red;'>


passe très bien, même si le navigateur (FF) signale un attribut inconnu.

<td style='color:red;X-perso:none;'>


est épuré, et le X-perso et sa valeur sautent. Pourtant, hormis le fait que la propriété X-perso n'est pas officielle, la syntaxe est juste.
En résumé, il semble que tu puisses ajouter des attributs non standards (exemple : _style), mais pas des propriétés;
Et pour en rajouter :
<td style='color:red;%prop%'>

est épuré. Ca semble normal, car, au premier coup d'oeil, la syntaxe est complètement fausse !
Mais :
<td _style='color:red;%prop%'>

passe sans problème, alors que la syntaxe des propriétés de l'attribut "_style" n'est toujours pas juste !

Florent V. a écrit :


Une solution possible: si tu as besoin de placer le template dans la page HTML, tu peux éventuellement placer un élément SCRIPT pour le déclarer comme variable JS.
<script type="text/javascript">
var machintruc_template = "<table>\n\
    ...\n\
</table>\n\";
</script>

Bon, la chaine de caractères multi-lignes avec un \ ça marche, mais théoriquement ce n'est pas standard. (Et, en HTML 4, il faudrait théoriquement échapper les «</» dans le code JS; no souci en HTML 5.)


C'est surtout que je perds énormément en souplesse ! Si le code HTML est simple, ok, mais pour mon cas, c'est loin d'être le cas. D'autant plus qu'il est voué à évoluer, donc, corriger une table avec des colspan et des rowspan, c'est ch..nt, mais en plus, dans une variable... Smiley biggol
Ok, je sais, je pourrais le coller dans un éditeur HTML, faire la modif, et convertir le code en variable JS... Mais je vais passer mon temps à faire ça ! Là, je fais juste la modif dans mon fichier template, je vois l'aspect immédiatement, et ça roule. upload/22087-template.png
Modifié par marcmendez (10 Jun 2009 - 17:34)
Salut,

Ta méthode est vraiment étrange Smiley eek !

Ton mécanisme de "innerHTML parser" ne sert à rien, les classes ou les id et le DOM font exactement la même chose et beaucoup mieux.

La solution est toute simple tu envoie l'id qui va bien en php :
<div id='modele'>
<table>
  <tr>
    <td style='color:red;' id="cel_4">Hello world !</td>
  </tr
</table>
</div>

et ensuite tu fais ce que tu veux avec ton id :

document.getElementById('cel_4').style.width = '50%'


Le problème ce n'est pas innerHTML ou pas le problème c'est ta méthode de remplacement pour identifier des éléments dans du code. Pour cela on utilise les id ou les classe, j'imagine que tu dois avoir des tas de raisons de faire autrement mais des milliers de personnes on fait des milliers d'applications avec cette méthode de "selecteurs" dans des tas de cas différents et il me semble que c'est suffisamment souple pour s'adapter à ton cas.

"Florent V." a écrit :

Le problème de récupérer ton template avec innerHTML, c'est que tu ne récupères pas (il me semble) le code HTML correspondant, mais sa traduction interne par le navigateur. Donc aucune garantie que tes %marqueurs% soient conservés.

C'est bien là le problème, innerHTML interprète ton code donc tu dépends de l'interprétation qu'en fait le navigateurs, tu vas donc beaucoup galérer! Il suffit de faire
alert(document.getElementById("modele").innerHTML)

et tu comprendras tout de suite le problème, ie met tout en majuscule et enlève carrément style='%prop%' Firefox affiche style='' etc...

Bref à ta place j'abandonnerais cette idée
marcmendez a écrit :
Mais, à ta charge, note que si je mets un attribut qui n'existe pas, c'est pas pour autant qu'il l'épure

Oui, ce n'est pas le même mécanisme. Tant que l'attribut est bien formé, il sera accessible dans le DOM (enfin, à voir pour IE qui peine un peu sur ce genre de choses il me semble), et son contenu sera gardé tel quel. Le cas de style est particulier vu que le contenu de cet attribut n'est pas de type text mais de type style sheet data. De même pour des attributs qui acceptent un contenu de type ID, NAME, ou encore NUMBER, il se peut qu'une valeur invalide soit ignorée et donc pas accessible dans le DOM.

En passant, HTML 5 utilise cette gestion des attributs pour proposer des attributs personnalisés de type data-whatever:
http://dev.w3.org/html5/spec/Overview.html#embedding-custom-non-visible-data

marcmendez a écrit :
Pourtant, hormis le fait que la propriété X-perso n'est pas officielle, la syntaxe est juste.

Je dirais que ce n'est pas pas la syntaxe qui importe (enfin si, ça compte), mais le fait que le navigateur puisse représenter en interne et dans le DOM la valeur donnée pour la propriété.

marcmendez a écrit :
Mais :
<td _style='color:red;%prop%'>

passe sans problème, alors que la syntaxe des propriétés de l'attribut "_style" n'est toujours pas juste !

Quelle syntaxe? Ton attribut est un attribut «custom», sa valeur est de type «text» et donc le navigateur la garde telle quelle sans la parser ou l'appliquer d'une quelconque manière.

marcmendez a écrit :
Ok, je sais, je pourrais le coller dans un éditeur HTML, faire la modif, et convertir le code en variable JS... Mais je vais passer mon temps à faire ça !

Ben pourquoi pas faire ça en PHP? Tu as un fichier de template en HTML (avec juste ton tableau, pas de Doctype & co), tu en récupères le contenu en PHP et tu transformes ça en chaine qui va bien pour JS. Tu peux même virer les retours à la ligne pour ne pas être obligé de bricoler avec des \ ou des \n\ (pas standard, comme je le disais).

matmat a écrit :
Ton mécanisme de "innerHTML parser" ne sert à rien, les classes ou les id et le DOM font exactement la même chose et beaucoup mieux.

Sauf si tu dois modifier vingt ou même cent valeurs, là ça devient pénible de faire du DOM Scripting qui va bien...
Florent V. a écrit :
Sauf si tu dois modifier vingt ou même cent valeurs, là ça devient pénible de faire du DOM Scripting qui va bien...


C'est exactement la même chose qu'avec le système d' "innerHTML replacement". Sauf que c'est beaucoup plus efficace, beaucoup plus souple et en plus c'est réutilisable et standard!

1. Tu assignes les bon id à tes cellules de "cel_1" "cel_100" par exemple
2. tu génères avec php un fichier json selon l'action de l'utilisateur genre :
[{ 
  "cel_1": "valeur 1", 
  "cel_2":[{
    "style":[{"width":"50%"}], 
    "text":"Valeur 2"     
  }]
}]

3. tu récupères ces valeurs avec ajax et tu les mets dans les cellules correspondantes, tu peux ainsi différencier les types de valeurs : texte, style, événement...
myJsonArray.forEach(function(item,index){
   var cel = document.getElementById(index);
   if(item[text]){
       cel.firstChild.nodeValue = item[[text]];
       for(var prop in item[[styles]]) cel.style[[prop]] = item[[styles]][[prop]];
   }else{
       document.getElementById(index).firstChild.nodeValue = item
   }
})


Le fait qu'il y est 10 ou 200 éléments à changer cela revient au même, au final la seul chose qu'il faut modifier c'est le fichier json, le reste dépend des valeurs de celui ci.

En plus si il y a 100 valeurs, copier 100 fois le innerHTML pour le recoller 100 fois pour le coup c'est vraiment pas une bonne idée.

Par contre avec innerHTML une solution toute simple et toute aussi efficace, c'est de génerer tout le tableau html en php avec toute les variables qui vont bien et de coller entièrement celui ci.

1. action de l'utilisateur qui appelle le fichier ajax avec les bon paramètres.
2. génération du tableau html avec php en fonction de ces paramètres
3. on colle tout simplement tout le tableau au bonne endroit, pas besoin de replace, ni de %prop%
Modifié par matmat (11 Jun 2009 - 04:53)
matmat a écrit :



1. action de l'utilisateur qui appelle le fichier ajax avec les bon paramètres.
2. génération du tableau html avec php en fonction de ces paramètres
3. on colle tout simplement tout le tableau au bonne endroit, pas besoin de replace, ni de %prop%


J'interviens rapidement sur ton commentaire (je prendrai la peine de répondre plus en détail plus tard, car là, j'suis à la bourre....) :
Je suis d'accord de générer tout le tableau HTML directement en PHP (ça, je le fais déjà depuis longtemps ailleurs), mais tu oublies un élément essentiel dans mon cas :
Le contenu de ce tableau n'est pas statique ! Il contient des informations qui proviennent de la page elle-même et que l'utilisateur change, sans que la page soit rechargée....
Donc pour le PHP, c'est râté
matmat a écrit :
Salut,


Le problème ce n'est pas innerHTML ou pas le problème c'est ta méthode de remplacement pour identifier des éléments dans du code. Pour cela on utilise les id ou les classe, j'imagine que tu dois avoir des tas de raisons de faire autrement mais des milliers de personnes on fait des milliers d'applications avec cette méthode de "selecteurs" dans des tas de cas différents et il me semble que c'est suffisamment souple pour s'adapter à ton cas.

Bref à ta place j'abandonnerais cette idée


Et bien non, je n'ai pas 50000 raisons. Je n'ai pas eu l'occasion de faire beaucoup joujou avec le DOM (quoique des fois, on en fait sans s'en rendre compte...). Mais dans un esprit curieux, c'est pour cela que j'ai posé une question dans le même sens que toi il y a quelques jours sur ce forum.
Pour l'instant, le choix est fait et je ne vais pas revenir en arrière pour ce dev (plus le temps et autres raisons perso...). Mais je note précisément tes remarques pour un cas similaires !
matmat a écrit :

C'est exactement la même chose qu'avec le système d' "innerHTML replacement". Sauf que c'est beaucoup plus efficace, beaucoup plus souple et en plus c'est réutilisable et standard!

1. Tu assignes les bon id à tes cellules de "cel_1" "cel_100" par exemple
2. tu génères avec php un fichier json selon l'action de l'utilisateur genre :
[{ 
  "cel_1": "valeur 1", 
  "cel_2":[{
    "style":[{"width":"50%"}], 
    "text":"Valeur 2"     
  }]
}]


Je ne connaissais pas le JSON.... Comme beaucoup de choses d'ailleurs. Très intéressant d'ailleurs. Je prends note ! Je t'avoue du bout des lèvres que j'utilise encore la serialization pour faire quelques échanges entre JS et PHP (mais pour de petites quantités de données). Smiley confused Smiley confused
matmat a écrit :

3. tu récupères ces valeurs avec ajax et tu les mets dans les cellules correspondantes, tu peux ainsi différencier les types de valeurs : texte, style, événement...
myJsonArray.forEach(function(item,index){
   var cel = document.getElementById(index);
   if(item[text]){
       cel.firstChild.nodeValue = item[[text]];
       for(var prop in item[[styles]]) cel.style[[prop]] = item[[styles]][[prop]];
   }else{
       document.getElementById(index).firstChild.nodeValue = item
   }
})


Le fait qu'il y est 10 ou 200 éléments à changer cela revient au même, au final la seul chose qu'il faut modifier c'est le fichier json, le reste dépend des valeurs de celui ci.

En plus si il y a 100 valeurs, copier 100 fois le innerHTML pour le recoller 100 fois pour le coup c'est vraiment pas une bonne idée.

Par contre avec innerHTML une solution toute simple et toute aussi efficace, c'est de génerer tout le tableau html en php avec toute les variables qui vont bien et de coller entièrement celui ci.

Je vois très bien ce que tu veux dire.
matmat a écrit :


1. action de l'utilisateur qui appelle le fichier ajax avec les bon paramètres.
2. génération du tableau html avec php en fonction de ces paramètres
3. on colle tout simplement tout le tableau au bonne endroit, pas besoin de replace, ni de %prop%
Conclusion :

Ce fil et l'autre auquel je fais référence m'ont été très utiles. Je ne dis pas que je vais l'utiliser systématiquement à tout bout de champ, mais j'ai un outil en plus dans ma caisse !

Pour le développement à l'origine de mes questions, ça restera ainsi. Ca fonctionne et le seul hic c'est éventuellement la pertinence de la méthode choisie.
Lorsque je dis que cela fonctionne, ce n'est pas une démission de ma part ou un manque de rigueur. Je reste parfaitement dans la norme après avoir réglé mon problème de style. Mais il n'en reste pas moins que j'ai appris beaucoup !
Ca me donne envie de mettre en oeuvre tout ça ! Smiley cligne