web-dev-qa-db-fra.com

Entrelacer les variables EJS et Javascript dans les balises <%

J'ai besoin d'utiliser une variable Javascript (définie dans le front-end) dans du code EJS, comme suit:

var selected = 1;
<% for (var i=0; i < supplies.length; i++) { %>
    if (i == selected) {
        console.log(supplies);    
    }
<% } %>

J'utilise EJS, Express.js et socket.io. Je pourrais convertir la variable Javascript en une variable EJS en envoyant un message à mon instance de serveur Node.js, mais c'est un peu idiot ... Existe-t-il un moyen d'utiliser des variables Javascript dans EJS?

EDIT: Je veux accéder aux fournitures, un tableau javascript, après que l'utilisateur a sélectionné un élément dans un menu déroulant. Lorsqu'il sélectionne cet élément, une fonction javascript avec le code ci-dessus doit accéder à certains EJS. C'est pourquoi j'ai besoin d'utiliser une variable Javascript normale dans EJS.

15
philipDS

Puis-je passer une variable JavaScript dans un modèle? :

Il est possible d'obtenir plus de données dans le modèle et de le restituer, mais pas de la manière que vous pensez, et sans faire une autre demande au serveur (sauf si c'est pour obtenir plus de données, pas pour obtenir plus de HTML).

Solution:

Il sera difficile de répondre à cette question sans plus de détails, donc je vais faire quelques hypothèses sur pourquoi vous voulez passer une valeur sélectionnée dans un modèle EJS. Je ferai de mon mieux pour y répondre avec des informations limitées sur vos objectifs.

Il semble que votre utilisateur effectue une action sur la page, comme la sélection d'un produit de nettoyage, et que vous souhaitez rendre les données différemment, en fonction de l'élément sélectionné par l'utilisateur. Pour ce faire, vous pouvez restituer le modèle et transmettre des données qui identifient l'élément sélectionné, à l'aide d'un assistant de vue pour appliquer une classe spécifique à l'élément sélectionné:

Voici le modèle cleaning.ejs modifié, avec la classe ajoutée à l'aide de l'assistant de vue:

cleaning.ejs:

<script>
// NOTE: even if uncommented, JavaScript inside a template will not run.
//    var selected = 1;
</script>
<h1><%= title %></h1>
<ul>
    <% for(var i=0; i<supplies.length; i++) { %>

        <li>
            <!-- apply a class to the selected element -->
            <a class='<%= supplies[i].selected %>' href='supplies/<%= supplies[i].value %>'>
                <%= supplies[i].value %>
            </a>
        </li>
    <% } %>
</ul>    

Le code HTML rendu ressemble à ceci:

<script>
    /** NOTE: Script blocks will not fire in rendered templates. They are ignored
    //    var selected = 1;
</script>
<h1>Cleaning Supplies</h1>
<ul>


        <li>
            <a class="" href="supplies/Broom">
                Broom
            </a>
        </li>


        <li>
            <!-- Note the selected element -->
            <a class="selected" href="supplies/mop">
                mop
            </a>
        </li>


        <li>
            <a class="" href="supplies/Hammer">
                Hammer
            </a>
        </li>

</ul>

Cette vue a été rendue à l'aide du code JavaScript suivant:

// modified data structure so that array of supplies contains objects
 // with the name of the item and whether or not it's selected.
data = {
    "title":"Cleaning Supplies",
    "supplies":[
        {
            "value":"Broom",
            "selected":""
        },
        {
            "value":"mop",
            "selected":"selected"
        },
        {
            "value":"Hammer",
            "selected":""
        }
    ]
};

// pass data into template and render
var html = new EJS({url: 'cleaning.ejs'}).render(data);

// add HTML to the DOM using a <div id="container"></div> wrapper.
document.getElementById("container").innerHTML = html;

Comme vous pouvez le voir, supplies [i] .selected applique la classe sélectionnée à l'élément qui a été marqué comme sélectionné dans la structure de données. J'ai modifié la valeur href pour qu'elle accède à l'objet dans le ième élément du tableau au lieu de la valeur du tableau lui-même.

Maintenant, lorsque l'élément sélectionné est modifié, nous modifions simplement la variable de données, restituons le modèle EJS et l'ajoutons au DOM.

Avec ce CSS dans la tête de votre document HTML, vous verrez quelque chose de similaire à ce qui est affiché ci-dessous:

<style>
    .selected { color:red; }
</style>

Demo of selected element in red


Pourquoi JavaScript dans le modèle ne fonctionne pas:

La méthode que vous essayez d'utiliser pour manipuler des valeurs JavaScript ou utiliser des valeurs JavaScript dans le modèle EJS ne fonctionnera pas. Cela a à voir principalement avec le contexte de quand le JavaScript est exécuté.

Vous avez raison de penser que les modèles EJS sont compilés côté client. Cependant, le JavaScript dans les assistants de vue est exécuté indépendamment du JavaScript dans le contexte global. En regardant le code source ejs.js, il semble que eval soit utilisé dans le processus.

De plus, EJS renvoie le HTML rendu sous forme de chaîne, et la documentation d'EJS nous demande d'injecter cette chaîne de modèle rendue dans le DOM à l'aide de innerHTML:

document.getElementById("container").innerHTML = html;

Quelle que soit la technologie d'affichage que vous utilisez, l'une des vérités fondamentales de certains navigateurs en ce qui concerne JavaScript est la suivante: Certains navigateurs peuvent ne pas évaluer <script> blocs ajoutés au DOM à l'aide de innerHTML.

En d'autres termes, dans mon modèle de test, lorsque j'ai essayé d'ajouter une balise de script pour sortir la valeur sélectionnée sur la console, j'ai pu voir que le bloc de script a été ajouté, mais en raison du fonctionnement de innerHTML, il n'a pas été exécuté:

L'exemple de modèle montre que JavaScript ne s'exécutera pas s'il est ajouté à l'aide de innerHTML:

 <h1><%= title %></h1>
<ul>
    <% for(var i=0; i<supplies.length; i++) {  %>
       <span id="selected"></span><script>console.info('test <%= i %> = <%= supplies[i] %>');</script>            
        <li>
            <a href='supplies/<%= supplies[i] %>'>
                <%= supplies[i] %>
            </a>
        </li>
    <% } %>
</ul>

HTML rendu:

Comme vous pouvez le voir ci-dessous, les instructions console.log sont présentes dans le HTML. Cependant, lorsqu'ils sont ajoutés à l'aide de innerHTML, ils ne se déclenchent pas.

L'approche à adopter avec les technologies de vue est de limiter leur utilisation à cela, en rendant la vue. Gardez votre logique dans le "JavaScript standard".

<h1>Cleaning Supplies</h1>
<ul>

       <span id="selected"></span><script>console.info('test 0 = Brrom');</script>            
        <li>
            <a href='supplies/Brrom'>
                Brrom
            </a>
        </li>

       <span id="selected"></span><script>console.info('test 1 = mop');</script>            
        <li>
            <a href='supplies/mop'>
                mop
            </a>
        </li>

       <span id="selected"></span><script>console.info('test 2 = Hammer');</script>            
        <li>
            <a href='supplies/Hammer'>
                Hammer
            </a>
        </li>

</ul>

Vous trouverez plus d'exemples et de documentation sur les modèles EJS sur le site Google Code Embedded JavaScript .

44
jmort253