JavaScript内でのRazorの使用


434

ビュー(cshtml)にあるJavaScript内でRazor構文を使用することは可能ですか、それとも回避策がありますか?

Googleマップにマーカーを追加しようとしています...たとえば、これを試しましたが、大量のコンパイルエラーが発生します。

<script type="text/javascript">

    // Some JavaScript code here to display map, etc.

    // Now add markers
    @foreach (var item in Model) {

        var markerlatLng = new google.maps.LatLng(@(Model.Latitude), @(Model.Longitude));
        var title = '@(Model.Title)';
        var description = '@(Model.Description)';
        var contentString = '<h3>' + title + '</h3>' + '<p>' + description + '</p>'

        var infowindow = new google.maps.InfoWindow({
            content: contentString
        });

        var marker = new google.maps.Marker({
            position: latLng,
            title: title,
            map: map,
            draggable: false
        });

        google.maps.event.addListener(marker, 'click', function () {
            infowindow.open(map, marker);
        });
    }
</script>

3
@:構文に関する私の更新に興味があるかもしれません。
StriplingWarrior、2011

この方法で行うことを検討している@誰でも、少なくともJSONを定義する別のスクリプトタグにデータを配置し、それをJSで使用します。フロントエンドのバックエンド結合JSは、多くの場合、私にとってレガシーPITAでした。必要がない場合は、コードでコードを記述しないでください。代わりにデータを渡してください。
エリック・レッペン2017

回答:


636

ここ<text>説明するように、疑似要素を使用して、Razorコンパイラを強制的にコンテンツモードに戻します。

<script type="text/javascript">

    // Some JavaScript code here to display map, etc.


    // Now add markers
    @foreach (var item in Model) {
        <text>
            var markerlatLng = new google.maps.LatLng(@(Model.Latitude), @(Model.Longitude));
            var title = '@(Model.Title)';
            var description = '@(Model.Description)';
            var contentString = '<h3>' + title + '</h3>' + '<p>' + description + '</p>'

            var infowindow = new google.maps.InfoWindow({
                content: contentString
            });

            var marker = new google.maps.Marker({
                position: latLng,
                title: title,
                map: map,
                draggable: false
            });

            google.maps.event.addListener(marker, 'click', function () {
                infowindow.open(map, marker);
            });
        </text>
    }
</script>

更新:

Scott Guthrieは最近@:、Razorの構文について投稿しました。これは<text>、追加するJavaScriptコードが1行または2行しかない場合のタグよりも少し不格好です。次のアプローチは、生成されるHTMLのサイズを縮小するため、おそらく望ましい方法です。(addMarker関数を静的なキャッシュJavaScriptファイルに移動して、サイズをさらに小さくすることもできます):

<script type="text/javascript">

    // Some JavaScript code here to display map, etc.
    ...
    // Declare addMarker function
    function addMarker(latitude, longitude, title, description, map)
    {
        var latLng = new google.maps.LatLng(latitude, longitude);
        var contentString = '<h3>' + title + '</h3>' + '<p>' + description + '</p>';

        var infowindow = new google.maps.InfoWindow({
            content: contentString
        });

        var marker = new google.maps.Marker({
            position: latLng,
            title: title,
            map: map,
            draggable: false
        });

        google.maps.event.addListener(marker, 'click', function () {
            infowindow.open(map, marker);
        });
    }

    // Now add markers
    @foreach (var item in Model) {
        @:addMarker(@item.Latitude, @item.Longitude, '@item.Title', '@item.Description', map);
    }
</script>

上記のコードを更新して、呼び出しをaddMarkerより正確にしました。

明確にするために、呼び出しはC#コードによく似@:ていますが、Razorを強制的にテキストモードに戻しaddMarkerます。次に、Razorは@item.Property構文を取得して、これらのプロパティのコンテンツを直接出力する必要があることを伝えます。

アップデート2

Viewコードは実際にはJavaScriptコードを配置するのに適した場所ではないことに注意してください。JavaScriptコードは静的.jsファイルに配置し、Ajax呼び出しまたはスキャンによって必要なデータを取得する必要がありますdata- HTMLから属性をあります。RazorはJavaScriptではなくHTMLをエンコードするように設計されているため、JavaScriptコードのキャッシュを可能にするだけでなく、エンコードの問題も回避できます。

コードを表示

@foreach(var item in Model)
{
    <div data-marker="@Json.Encode(item)"></div>
}

JavaScriptコード

$('[data-marker]').each(function() {
    var markerData = $(this).data('marker');
    addMarker(markerData.Latitude, markerData.Longitude,
              markerData.Description, markerData.Title);
});

3
更新された例がわかりません。addmarker関数は正しいですか?
NVM

2
@NVM:同じJavaScriptコードを数回出力するのではなく、単一のJavaScript関数(キャッシュされた.jsファイルに保持できる)を作成し、その関数への複数の呼び出しを出力することをお勧めします。関数が正しいかどうかはわかりません。OPのコードに基づいているだけです。
StriplingWarrior

1
foreachで「@ Model.Latitude」を使用する理由 なぜitem.Latitudeではないのですか?
NVM

5
C#変数はエスケープする必要があります。@item.Title一重引用符が含まれている場合、このコードは爆発します。
mpen 2014年

7
@マーク:良い観察。実際、私は通常、自分のコード JavaScriptとRazor をまったく組み合わせていません。Razor を使用してdata-属性付きのHTMLを生成し、静的で邪魔にならないJavaScriptを使用してDOMからこの情報を収集します。しかし、その全体の議論は、質問の範囲をある程度超えていました。
StriplingWarrior 2014年

39

私はこのヘルパー関数を書いたところです。それを入れてくださいApp_Code/JS.cshtml

@using System.Web.Script.Serialization
@helper Encode(object obj)
{
    @(new HtmlString(new JavaScriptSerializer().Serialize(obj)));
}

次に、あなたの例では、次のようなことができます:

var title = @JS.Encode(Model.Title);

引用符を付けないことに注意してください。タイトルにすでに引用符が含まれている場合、爆発しません。辞書や匿名オブジェクトもうまく処理するようです!


19
ビューでオブジェクトをエンコードしようとしている場合、ヘルパーコードを作成する必要はありません。ヘルパーコードはすでに存在しています。私たちはこれを常に使用しています@Html.Raw(Json.Encode(Model))
PJH 2014年

2
回答PJHを拡張できますか?「モデル」だけをエンコードする場合、タイトルはどのように指定しますか?
obesechicken13

2
また、Model.Titleを使用してこのアプローチを試したところ、エンコードされたjavascriptの周りに余分な引用符がいくつかあります。引用符を別のものに連結しても、引用符を取り除くことはできません。これらの引用はあなたのjsの一部になります。
obesechicken13

1
PJHのコメントはすばらしい。ある方法では、サーバー側モデルをjavascriptブロックに逆シリアル化します。
netfed

24

あなたは丸い穴に四角いペグを詰め込もうとしています。

Razorは、HTMLを生成するテンプレート言語として意図されていました。JavaScriptコードを生成することもできますが、そのために設計されていません。

たとえばModel.Title、アポストロフィが含まれている場合はどうなりますか?それはあなたのJavaScriptコードを壊すでしょう、そしてRazorはデフォルトでそれを正しくエスケープしません。

ヘルパー関数で文字列ジェネレータを使用するほうが適切でしょう。そのアプローチの意図しない結果が少なくなる可能性があります。


17

どのような具体的なエラーが発生していますか?

このようなものはうまくいくかもしれません:

<script type="text/javascript">

//now add markers
 @foreach (var item in Model) {
    <text>
      var markerlatLng = new google.maps.LatLng(@Model.Latitude, @Model.Longitude);
      var title = '@(Model.Title)';
      var description = '@(Model.Description)';
      var contentString = '<h3>' + title + '</h3>' + '<p>' + description + '</p>'
    </text>
}
</script>

Razorがマークアップモードに切り替える必要があることを示すには、の<text>後に魔法のタグが必要foreachです。


1
(foreachによって)モデルを反復し、@ Model.Latidueをマークしますか?反復の機能とは何ですか?何かを逃したと思います。@ item.Latitudeなどになる可能性があります
Nuri YILMAZ 2018年

12

これは、CSHTMLページにあり、外部JavaScriptファイルではない場合は問題なく機能します。

Razorテンプレートエンジンは、何を出力するかを気にせず、<script>または他のタグを区別しません。

ただし、XSS攻撃を防ぐために文字列をエンコードする必要があります。


2
私は私の質問を更新しました、それは私のために機能しません-どのようなアイデアが間違っていますか?感謝
raklos

3
@raklos:文字列をエスケープする必要があります。コールHTML.Raw(Server.JavaScriptStringEncode(...))
SLaks

1
HTML.Raw(HttpUtility.JavaScriptStringEncode(...))- サーバープロパティには現在、このメソッドはありません。HttpUtilityにはあります。
it3xl 2015

1
The Razor template engine doesn't care what it's outputting and does not differentiate between <script> or other tags.本当にそうですか?stackoverflow.com/questions/33666065/...
HMR

2
@HMR:私がこの回答を書いたとき、その機能は存在しませんでした。
SLaks 2015年

11

「テキスト」のように「<!-」「->」を好む

<script type="text/javascript">
//some javascript here     

@foreach (var item in itens)
{                 
<!--  
   var title = @(item.name)
    ...
-->

</script>

これは奇妙なことに私にとって@:<text>
有効

8

追加すべきことの1つ-Razor構文ハイライター(およびおそらくコンパイラ)が開き角括弧の位置を異なる方法で解釈することがわかりました。

<script type="text/javascript">
    var somevar = new Array();

    @foreach (var item in items)
    {  // <----  placed on a separate line, NOT WORKING, HILIGHTS SYNTAX ERRORS
        <text>
        </text>
    }

    @foreach (var item in items) {  // <----  placed on the same line, WORKING !!!
        <text>
        </text>
    }
</script>

6

シンプルでわかりやすい例:

<script>
    // This gets the username from the Razor engine and puts it
    // in JavaScript to create a variable I can access from the
    // client side.
    //
    // It's an odd workaraound, but it works.
    @{
        var outScript = "var razorUserName = " + "\"" + @User.Identity.Name + "\"";
    }
    @MvcHtmlString.Create(outScript);
</script>

これにより、ページの上のコードを配置した場所に次のようなスクリプトが作成されます。

<script>
    // This gets the username from the Razor engine and puts it
    // in JavaScript to create a variable I can access from
    // client side.
    //
    // It's an odd workaraound, but it works.

    var razorUserName = "daylight";
</script>

これrazorUserNameで、クライアントでアクセスして使用できるという名前のグローバルJavaScript変数が作成されました。Razorエンジンは明らかに@User.Identity.Name(サーバー側変数)から値を抽出し、それをスクリプトタグに書き込むコードに配置します。


6

次の解決策は、JavaScriptとRazorを組み合わせるよりも正確に思えます。これをチェックしてくださいhttps//github.com/brooklynDev/NGon

ほとんどすべての複雑なデータをViewBag.Ngonに追加して、JavaScriptでアクセスできます

コントローラで:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var person = new Person { FirstName = "John", LastName = "Doe", Age = 30 };
        ViewBag.NGon.Person = person;
        return View();
    }
}

JavaScriptの場合:

<script type="text/javascript">
    $(function () {
        $("#button").click(function () {
            var person = ngon.Person;
            var div = $("#output");
            div.html('');
            div.append("FirstName: " + person.FirstName);
            div.append(", LastName: " + person.LastName);
            div.append(", Age: " + person.Age);
        });
    });
</script>

デフォルトを使用してシリアル化できるプレーンオールドCLRオブジェクト(POCO)を許可しますJavascriptSerializer


5

@:と以外にも1つのオプションがあり<text></text>ます。

<script>ブロック自体を使用します。

Razorコードに応じてJavaScriptの大きなチャンクを実行する必要がある場合、次のように実行できます。

@if(Utils.FeatureEnabled("Feature")) {
    <script>
        // If this feature is enabled
    </script>
}

<script>
    // Other JavaScript code
</script>

この方法の長所は、JavaScriptとRazorをあまり混合しないことです。これらを大量に混合すると、最終的に可読性の問題が発生するためです。また、大きなテキストブロックも読みにくいです。


4

以前のソリューションはどれも正しく機能しません...私はすべての方法を試しましたが、期待した結果が得られませんでした...ついに、コードにエラーがあることがわかりました...そして完全なコードが与えられました未満。

<script type="text/javascript">

    var map = new google.maps.Map(document.getElementById('map'), {
        zoom: 10,
        center: new google.maps.LatLng(23.00, 90.00),
        mapTypeId: google.maps.MapTypeId.ROADMAP
    });

    @foreach (var item in Model)
    {
        <text>
            var markerlatLng = new google.maps.LatLng(@(item.LATITUDE), @(item.LONGITUDE));
            var title = '@(item.EMP_ID)';
            var description = '@(item.TIME)';
            var contentString = '<h3>' + "Employee " +title+ " was here at "+description+ '</h3>' + '<p>'+" "+ '</p>'

            var infowindow = new google.maps.InfoWindow({
                // content: contentString
            });

            var marker = new google.maps.Marker({
                position: markerlatLng,
                title: title,
                map: map,
                draggable: false,
                content: contentString
            });

            google.maps.event.addListener(marker, 'click', (function (marker) {
                return function () {
                    infowindow.setContent(marker.content);
                    infowindow.open(map, marker);
                }
            })(marker));
        </text>
    }
</script>

4

私は最終的に解決策を見つけました(* .vbhtml):

function razorsyntax() {
    /* Double */
    @(MvcHtmlString.Create("var szam =" & mydoublevariable & ";"))
    alert(szam);

    /* String */
    var str = '@stringvariable';
    alert(str);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.