web-dev-qa-db-fra.com

Utiliser Razor dans JavaScript

Est-il possible ou existe-t-il une solution de contournement d'utiliser la syntaxe Razor dans JavaScript qui se trouve dans une vue (cshtml)?

J'essaie d'ajouter des marqueurs sur une carte Google ... Par exemple, j'ai essayé ceci, mais je reçois une tonne d'erreurs de compilation:

<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

Utilisez le pseudo-élément <text>, comme décrit ici , pour forcer le compilateur Razor à revenir en mode contenu:

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

Mise à jour:

Scott Guthrie a récemment posté à propos de @: syntaxe dans Razor, qui est légèrement moins lourde que la balise <text> si vous avez juste une ou deux lignes de code JavaScript à ajouter. L'approche suivante serait probablement préférable, car elle réduit la taille du code HTML généré. (Vous pouvez même déplacer la fonction addMarker dans un fichier JavaScript statique mis en cache afin de réduire davantage la taille):

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

Mise à jour du code ci-dessus pour rendre l'appel à addMarker plus correct.

Pour clarifier, le @: force Razor à revenir en mode texte, même si l'appel addMarker ressemble beaucoup au code C #. Razor sélectionne ensuite la syntaxe @item.Property pour indiquer qu'il doit générer directement le contenu de ces propriétés.

Mise à jour 2

Il est à noter que View code n'est pas vraiment un bon endroit pour mettre du code JavaScript. Le code JavaScript doit être placé dans un fichier .js statique, puis les données dont il a besoin doivent être extraites d'un appel Ajax ou en analysant les attributs data- à partir du code HTML. En plus de rendre possible la mise en cache de votre code JavaScript, cela évite également les problèmes d’encodage, car Razor est conçu pour encoder en HTML, mais pas en JavaScript.

Voir le code

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

Code JavaScript

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

Je viens d'écrire cette fonction d'assistance. Mettez-le dans App_Code/JS.cshtml:

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

Ensuite, dans votre exemple, vous pouvez faire quelque chose comme ceci:

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

Remarquez comment je ne mets pas de citations autour de ça. Si le titre contient déjà des guillemets, il n'explosera pas. Semble bien gérer les dictionnaires et les objets anonymes!

38
mpen

Vous essayez de coincer une cheville carrée dans un trou rond.

Razor était conçu comme un langage de template générant du HTML. Vous pouvez très bien le faire générer du code JavaScript, mais il n’a pas été conçu pour cela.

Par exemple: Et si Model.Title contient une apostrophe? Cela casserait votre code JavaScript et Razor ne l’échappera pas correctement par défaut.

Il serait probablement plus approprié d'utiliser un générateur de chaînes dans une fonction d'assistance. Il y aura probablement moins de conséquences inattendues de cette approche.

22
Adam Lassek

Quelles erreurs spécifiques voyez-vous?

Quelque chose comme ça pourrait mieux fonctionner:

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

Notez que vous avez besoin de la balise magique <text> après la foreach pour indiquer que Razor doit basculer en mode marquage.

16
marcind

Cela fonctionnera correctement, à condition que ce soit dans une page CSHTML et non dans un fichier JavaScript externe.

Le moteur de gabarit Razor ne tient pas compte de ce qu'il produit et ne fait pas la différence entre <script> ou d'autres balises.

Cependant, vous devez encoder vos chaînes pour empêcher les attaques XSS .

11
SLaks

Je préfère "<! -" "->" comme un "texte>"

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

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

</script>
10
Fernando JS

Une chose à ajouter - j'ai trouvé que le surligneur de la syntaxe Razor (et probablement le compilateur) interprétait différemment la position du crochet d'ouverture:

<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

Un exemple simple et bon:

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

Cela crée un script dans votre page à l'emplacement où vous placez le code ci-dessus, qui ressemble à ce qui suit:

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

Vous avez maintenant une variable JavaScript globale nommée razorUserName à laquelle vous pouvez accéder et que vous pouvez utiliser sur le client. Le moteur Razor a évidemment extrait la valeur de @User.Identity.Name (variable côté serveur) et l'a insérée dans le code qu'il a écrit dans votre balise de script.

6
raddevus

La solution suivante me semble plus précise que de combiner JavaScript avec Razor. Vérifiez ceci: https://github.com/brooklynDev/NGon

Vous pouvez ajouter presque toutes les données complexes à ViewBag.Ngon et y accéder en JavaScript

Dans le contrôleur:

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

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

Il autorise tous les anciens objets CLR simples (POCO) pouvant être sérialisés à l'aide du paramètre par défaut JavascriptSerializer.

6
Ice2burn

Il existe également une option de plus que @: et <text></text>.

Utiliser <script> se bloquer.

Lorsque vous avez besoin de faire de gros morceaux de JavaScript en fonction du code Razor, vous pouvez le faire comme ceci:

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

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

L'avantage de cette méthode est qu'il ne mélange pas trop JavaScript et Razor, parce que beaucoup de mélange causera des problèmes de lisibilité. Les grands blocs de texte ne sont pas non plus très lisibles.

5
Tuukka Lindroos

Aucune des solutions précédentes ne fonctionne correctement ... J'ai essayé tous les moyens, mais cela ne m'a pas donné le résultat attendu ... Enfin, j'ai constaté qu'il y avait des erreurs dans le code ... Et le code complet est donné au dessous de.

<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

J'ai finalement trouvé la solution (* .vbhtml):

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

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