web-dev-qa-db-ja.com

<%タグ内のEJSおよびJavaScript変数を織り交ぜます

次のように、一部のEJSコードでJavascript変数(フロントエンドで定義)を使用する必要があります。

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

私はEJS、Express.js、およびsocket.ioを使用しています。 Node.jsサーバーインスタンスにメッセージを送信することにより、JavaScript変数をEJS変数に変換できますが、それはばかげています... EJS内でJavascript変数を使用する方法はありますか?

編集:ユーザーがドロップダウンメニューから項目を選択した後、javascript配列である消耗品にアクセスしたいと思います。彼がこのアイテムを選択すると、上記のコードを含むJavaScript関数がEJSにアクセスする必要があります。そのため、EJSで通常のJavaScript変数を使用する必要があります。

15
philipDS

JavaScript変数をテンプレートに渡すことはできますか?

より多くのデータをテンプレートに取り込み、それを再レンダリングすることは可能ですが、あなたが考えている方法ではなく、サーバーに別の要求を行うことなく(より多くのデータを取得するためではなく、HTMLを取得するためでない限り)可能です。

ソリューション:

この質問は、詳細がなければ答えるのが難しいので、選択した値をEJSテンプレートに渡す必要がある理由についていくつか仮定します。私はあなたの目標について限られた情報でこれに答えるために最善を尽くします。

ユーザーがページ上でクリーニング用品の選択などのアクションを実行しているようで、ユーザーが選択した要素に基づいて、データを異なる方法でレンダリングしたいと考えています。これを行うには、ビューヘルパーを使用して選択した要素に特定のクラスを適用し、テンプレートを再レンダリングして、選択された要素を識別するデータを渡します。

以下は、ビューヘルパーを使用してクラスが追加された、変更されたcleaning.ejsテンプレートです。

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>    

レンダリングされたHTMLは次のようになります:

<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>

このビューは、次のJavaScriptコードを使用してレンダリングされました:

// 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;

ご覧のように、supplies [i] .selectedは、選択されたクラスを、データ構造で選択済みとしてマークされた要素に適用します。配列自体の値ではなく、i番目の配列アイテムのオブジェクトにアクセスするように、href値を変更しました。

これで、選択したアイテムが変更されたら、データ変数を変更し、EJSテンプレートを再レンダリングして、DOMに追加するだけです。

このCSSをHTMLドキュメントの先頭に配置すると、以下に表示されるものと同様のものが表示されます。

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

Demo of selected element in red


テンプレート内のJavaScriptが実行されない理由:

JavaScript値の操作またはEJSテンプレート内のJavaScript値の使用に使用しようとしているメソッドは機能しません。これは、JavaScriptが実行されるwhenのコンテキストに主に関係しています。

EJSテンプレートはクライアント側でコンパイルされると考えるのは当然です。ただし、ビューヘルパーのJavaScriptは、グローバルコンテキストのJavaScriptとは無関係に実行されます。 ejs.jsのソースコードを見ると、プロセスでevalが使用されているように見えます。

さらに、EJSはレンダリングされたHTMLを文字列として返します。そしてEJSのドキュメントは、innerHTMLを使用して、レンダリングされたテンプレート文字列をDOMに挿入するように指示しています。

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

使用しているビュー技術に関係なく、JavaScriptに関しては一部のブラウザーの基本的な真実の1つはこれです:一部のブラウザーはDOMに追加された<script>ブロックを評価しない場合がありますinnerHTMLを使用します。

つまり、テストテンプレートで、選択した値をコンソールに出力するスクリプトタグを追加しようとすると、スクリプトブロックが追加されたことがわかりましたが、innerHTMLの動作方法が原因で実行されませんでした。

InnerHTML:を使用して追加するとJavaScriptが実行されないことを示すサンプルテンプレート

 <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:

以下に示すように、console.logステートメントはHTMLに存在します。ただし、innerHTMLを使用して追加した場合、これらは起動しません。

ビューテクノロジーを使用するアプローチは、ビューテクノロジーを使用することだけに限定して、ビューをレンダリングします。ロジックを「通常のJavaScript」に維持します。

<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>

その他の例とドキュメントは Google Code Embedded JavaScript サイトのEJSテンプレートにあります。

44
jmort253