web-dev-qa-db-ja.com

JavaScript内でRazorを使用する

ビュー内(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>
401
raklos

here のように<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で@:構文について を投稿しました。追加する1行または2行のJavaScriptコードがある場合、これは<text>タグよりも少しわかりにくいです。次の方法は、生成される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の呼び出しをより正確にするために上記のコードを更新しました。

明確にするために、たとえaddMarker呼び出しがC#コードによく似ていても、@:はRazorをテキストモードに強制的に戻します。それから、Razorは@item.Property構文を選び、それらのプロパティの内容を直接出力するようにします。

アップデート2

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

コードを見る

@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);
});
594

このヘルパー関数を書きました。 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);

引用符で囲まないでください。タイトルにすでに引用符が含まれている場合は、爆発しません。辞書や匿名のオブジェクトもうまく扱えるようです。

38
mpen

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

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

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

おそらく、ヘルパー関数でStringジェネレータを使用するほうが適切でしょう。そのアプローチの意図しない結果はおそらく少なくなるでしょう。

22
Adam Lassek

具体的なエラーは何ですか。

このような何かがうまくいく可能性があります。

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

16
marcind

外部のJavaScriptファイルではなくCSHTMLページにある限り、それは問題なく動作します。

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

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

11
SLaks

私は "<> - " " - >"を "text>"のように好む

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

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

</script>
10
Fernando JS

追加する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>
8
Andy

簡単でわかりやすい例:

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

次の解決策は、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>

デフォルトのJavascriptSerializerを使ってシリアライズすることができる 普通の古いCLRオブジェクト (POCO)を使うことができます。

6
Ice2burn

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

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

Razorコードに応じて大量のJavaScriptを実行する必要がある場合は、次のようにします。

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

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

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

5
Tuukka Lindroos

これまでの解決策はどれも正しく動作しません...私はすべての方法を試してみましたが、それは私に期待される結果を与えませんでした...以下。

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

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

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

    /* String */
    var str = '@stringvariable';
    alert(str);
}
4
SZL