it-swarm.com.de

Verwenden von Razor in JavaScript

Ist es möglich oder gibt es eine Problemumgehung für die Verwendung der Razor-Syntax in JavaScript, das sich in einer Ansicht befindet (cshtml)?

Ich versuche, einer Google-Karte Markierungen hinzuzufügen. Ich habe dies beispielsweise versucht, erhalte aber eine Menge Kompilierungsfehler:

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

Verwenden Sie das Pseudoelement <text>, wie beschrieben hier , um den Razor-Compiler zurück in den Inhaltsmodus zu zwingen:

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

Update:

Scott Guthrie hat kürzlich geschrieben über die @: -Syntax in Razor, die etwas weniger umständlich ist als das <text> -Tag, wenn Sie nur ein oder zwei Zeilen JavaScript-Code hinzufügen müssen. Der folgende Ansatz wäre wahrscheinlich vorzuziehen, da er die Größe des generierten HTML verringert. (Sie können die Funktion addMarker sogar in eine statische, zwischengespeicherte JavaScript-Datei verschieben, um die Größe weiter zu verringern.)

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

Den obigen Code aktualisiert, um den Aufruf von addMarker korrekter zu machen.

Zur Verdeutlichung zwingt der @: Razor zurück in den Textmodus, obwohl der addMarker -Aufruf dem C # -Code sehr ähnlich sieht. Razor greift dann auf die @item.Property -Syntax zurück, um anzugeben, dass der Inhalt dieser Eigenschaften direkt ausgegeben werden soll.

Update 2

Es ist erwähnenswert, dass View Code wirklich kein guter Ort ist, um JavaScript-Code zu platzieren. JavaScript-Code sollte in einer statischen .js -Datei abgelegt werden und dann die erforderlichen Daten aus einem Ajax-Aufruf oder durch Scannen von data- -Attributen aus dem HTML-Code abrufen. Dadurch können Sie nicht nur Ihren JavaScript-Code zwischenspeichern, sondern auch Codierungsprobleme vermeiden, da Razor für die Codierung von HTML, nicht jedoch von JavaScript konzipiert ist.

Code anzeigen

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

JavaScript-Code

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

Ich habe gerade diese Hilfsfunktion geschrieben. Gib es in App_Code/JS.cshtml ein:

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

Dann können Sie in Ihrem Beispiel so etwas tun:

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

Beachten Sie, wie ich es nicht in Anführungszeichen setze. Wenn der Titel bereits Anführungszeichen enthält, wird er nicht explodieren. Scheint Wörterbücher und anonyme Objekte auch gut zu handhaben!

38
mpen

Sie versuchen, einen quadratischen Stift in ein rundes Loch zu stecken.

Razor war als HTML-generierende Vorlagensprache gedacht. Sie können es sehr gut dazu bringen, JavaScript-Code zu generieren, aber es wurde nicht dafür entwickelt.

Zum Beispiel: Was ist, wenn Model.Title einen Apostroph enthält? Das würde Ihren JavaScript-Code beschädigen und Razor wird ihn standardmäßig nicht korrekt umgehen.

Es wäre wahrscheinlich sinnvoller, einen String-Generator in einer Hilfsfunktion zu verwenden. Es wird wahrscheinlich weniger unbeabsichtigte Folgen dieses Ansatzes geben.

22
Adam Lassek

Welche spezifischen Fehler sehen Sie?

So etwas könnte besser funktionieren:

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

Beachten Sie, dass Sie das magische <text> -Tag nach dem foreach benötigen, um anzugeben, dass Razor in den Markup-Modus wechseln soll.

16
marcind

Das funktioniert einwandfrei, solange es sich um eine CSHTML-Seite und nicht um eine externe JavaScript-Datei handelt.

Die Razor-Vorlagen-Engine kümmert sich nicht um die Ausgabe und unterscheidet nicht zwischen <script> oder anderen Tags.

Sie müssen jedoch Ihre Zeichenfolgen codieren, um XSS -Angriffe zu verhindern.

11
SLaks

Ich bevorzuge "<! -" "->" wie ein "Text>"

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

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

</script>
10
Fernando JS

Eine Sache, die ich hinzufügen muss: Ich habe festgestellt, dass der Razor-Syntax-Textmarker (und wahrscheinlich der Compiler) die Position der öffnenden Klammer unterschiedlich interpretiert:

<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

Ein einfaches und gutes einfaches Beispiel:

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

Dadurch wird auf Ihrer Seite ein Skript erstellt, über dem Sie den Code platzieren. Dieser sieht folgendermaßen aus:

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

Jetzt haben Sie eine globale JavaScript-Variable mit dem Namen razorUserName, auf die Sie zugreifen und die Sie auf dem Client verwenden können. Die Razor-Engine hat offensichtlich den Wert aus @User.Identity.Name (serverseitige Variable) extrahiert und in den Code eingefügt, den sie in Ihr Skript-Tag schreibt.

6
raddevus

Die folgende Lösung scheint mir genauer zu sein, als JavaScript mit Razor zu kombinieren. Überprüfen Sie dies: https://github.com/brooklynDev/NGon

Sie können fast alle komplexen Daten zu ViewBag.Ngon hinzufügen und in JavaScript darauf zugreifen.

In der Steuerung:

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

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

Es sind alle einfache alte CLR-Objekte (POCOs) zulässig, die mit dem Standardwert JavascriptSerializer serialisiert werden können.

6
Ice2burn

Es gibt auch eine Option mehr als @: und <text></text>.

Verwenden Sie <script>, um sich selbst zu blockieren.

Wenn Sie je nach Razor-Code große Teile von JavaScript benötigen, können Sie dies folgendermaßen tun:

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

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

Der Vorteil dieser Art ist, dass JavaScript und Razor nicht zu oft gemischt werden, da ein häufiges Mischen letztendlich zu Lesbarkeitsproblemen führen kann. Auch große Textblöcke sind nicht gut lesbar.

5
Tuukka Lindroos

Keine der vorherigen Lösungen funktioniert richtig ... Ich habe alle Möglichkeiten ausprobiert, aber es gab mir nicht das erwartete Ergebnis ... Endlich stellte ich fest, dass der Code einige Fehler enthält ... und der vollständige Code ist angegeben unten.

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

Ich habe endlich die Lösung gefunden (* .vbhtml):

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

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