ビュー内(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>
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
構文を選び、それらのプロパティの内容を直接出力するようにします。
Viewコードは、実際にはJavaScriptコードを配置するのには適していません。 JavaScriptコードは静的な.js
ファイルに配置してから、必要なデータをAjax呼び出しから取得するか、またはHTMLのdata-
属性をスキャンすることによって取得する必要があります。あなたのJavaScriptコードをキャッシュすることを可能にすることに加えて、これはまたRazorがJavaScriptではなくHTMLのためにエンコードするように設計されているのでエンコードの問題を避けます。
@foreach(var item in Model)
{
<div data-marker="@Json.Encode(item)"></div>
}
$('[data-marker]').each(function() {
var markerData = $(this).data('marker');
addMarker(markerData.Latitude, markerData.Longitude,
markerData.Description, markerData.Title);
});
このヘルパー関数を書きました。 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);
引用符で囲まないでください。タイトルにすでに引用符が含まれている場合は、爆発しません。辞書や匿名のオブジェクトもうまく扱えるようです。
あなたは丸い穴に四角い釘を詰め込もうとしています。
RazorはHTMLを生成するテンプレート言語として意図されていました。 JavaScriptコードを生成するようにしてもかまいませんが、そのためには設計されていません。
例:Model.Title
にアポストロフィが含まれているとどうなりますか?それはあなたのJavaScriptコードを壊すでしょう、そしてRazorはデフォルトでそれを正しくエスケープしません。
おそらく、ヘルパー関数でStringジェネレータを使用するほうが適切でしょう。そのアプローチの意図しない結果はおそらく少なくなるでしょう。
具体的なエラーは何ですか。
このような何かがうまくいく可能性があります。
<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>
タグが必要です。
外部のJavaScriptファイルではなくCSHTMLページにある限り、それは問題なく動作します。
Razorテンプレートエンジンは、それが何を出力しているのかを気にせず、<script>
や他のタグを区別しません。
ただし、 _ xss _ 攻撃を防ぐために文字列をエンコードする必要があります。
私は "<> - " " - >"を "text>"のように好む
<script type="text/javascript">
//some javascript here
@foreach (var item in itens)
{
<!--
var title = @(item.name)
...
-->
</script>
追加する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>
簡単でわかりやすい例:
<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
(サーバサイド変数)から値を抽出し、それをスクリプトタグに書き込むコードに入れました。
次の解決策は、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)を使うことができます。
@:と<text></text>
以外にももう1つオプションがあります。
<script>
ブロック自体を使用する。
Razorコードに応じて大量のJavaScriptを実行する必要がある場合は、次のようにします。
@if(Utils.FeatureEnabled("Feature")) {
<script>
// If this feature is enabled
</script>
}
<script>
// Other JavaScript code
</script>
この方法の長所は、JavaScriptとRazorをあまり混ぜ合わせないことです。それらをたくさん混ぜると、最終的に読みやすさの問題が発生するためです。大きなテキストブロックもあまり読みやすくありません。
これまでの解決策はどれも正しく動作しません...私はすべての方法を試してみましたが、それは私に期待される結果を与えませんでした...以下。
<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>
私はついに解決策(* .vbhtml)を見つけました:
function razorsyntax() {
/* Double */
@(MvcHtmlString.Create("var szam =" & mydoublevariable & ";"))
alert(szam);
/* String */
var str = '@stringvariable';
alert(str);
}