Utilisation de Razor dans JavaScript

est-il possible ou y a-t-il une solution de rechange à L'utilisation de la syntaxe Razor dans JavaScript qui est dans une vue ( cshtml )?

j'essaie d'ajouter des marqueurs à une carte Google... Par exemple, j'ai essayé cela, 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>
385
demandé sur Peter Mortensen 2011-01-05 01:34:54

12 réponses

utilisez le pseudo-élément <text> , comme décrit ici , pour forcer le compilateur de rasoir de nouveau dans le mode de 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 publié à propos de la syntaxe @: dans Razor, qui est un peu moins clunky 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 il réduit la taille du HTML généré. (Vous pourriez même déplacer la fonction addMarker vers un fichier JavaScript statique, caché pour 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>

mis à Jour le code ci-dessus pour faire l'appel addMarker plus correct.

pour clarifier, le @: oblige Razor à revenir en mode texte, même si l'appel addMarker ressemble beaucoup au code C#. Rasoir puis prend la syntaxe @item.Property pour dire qu'il devrait sortir directement le contenu de ces propriétés.

Update 2

il est intéressant de noter que View code n'est vraiment pas un bon endroit pour mettre du code JavaScript. Le code JavaScript devrait être placé dans un fichier statique .js , et ensuite il devrait obtenir les données dont il a besoin soit à partir d'un appel Ajax ou en scannant les attributs data- à partir du HTML. En plus de rendre possible la mise en cache de votre Code JavaScript, cela évite également les problèmes d'encodage, puisque Razor est conçu pour encoder pour HTML, mais pas 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);
});
568
répondu StriplingWarrior 2017-05-23 12:34:48

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

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

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

remarquez que je ne mets pas de guillemets autour. Si le titre contient déjà des citations, il n'explosera pas. Semble traiter les dictionnaires et les objets anonymes aussi bien!

37
répondu mpen 2012-01-19 10:56:25

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

Razor a été conçu comme un langage de modèle générant HTML. Vous pouvez très bien l'obtenir pour 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 briserait votre code JavaScript, et Razor ne s'en échappera pas correctement par défaut.

Il serait probablement plus approprié d'utiliser une Chaîne générateur dans une fonction d'assistance. Cette approche aura probablement moins de conséquences involontaires.

20
répondu Adam Lassek 2016-01-01 16:54:01

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 l'étiquette magique <text> après le foreach pour indiquer que le rasoir devrait passer en mode markup.

15
répondu marcind 2011-01-04 23:09:02

qui fonctionnera très bien, tant qu'il est dans une page CSHTML et pas un fichier JavaScript externe.

le moteur de modèle de rasoir ne se soucie pas de ce qu'il produit et ne fait pas de différence entre <script> ou d'autres étiquettes.

cependant, vous devez encoder vos chaînes pour éviter les attaques XSS .

10
répondu SLaks 2016-01-01 16:52:57

je préfère "" comme un "texte>"

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

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

</script>
8
répondu Fernando JS 2012-03-12 20:20:07

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

<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>
7
répondu Andy 2011-05-31 10:12:28

Un simple et un bon straight-forward exemple:

<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'endroit où vous placez le code au-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>

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

5
répondu raddevus 2016-01-01 17:03:45

la solution suivante me semble plus précise que de combiner JavaScript avec Razor. Check this out: 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 est permet à toute plain old CLR objets (Poco) qui peut être sérialisée en utilisant la valeur par défaut JavascriptSerializer .

5
répondu Ice2burn 2016-01-01 17:05:52

il y a aussi une option de plus que @: et <text></text> .

utilisant <script> se bloque.

quand vous avez besoin de faire de grands morceaux de JavaScript selon le code de rasoir, vous pouvez le faire comme ceci:

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

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

les avantages de cette manière est qu'il ne mélange Pas JavaScript et rasoir trop, parce que les mélanger beaucoup va causer des problèmes de lisibilité éventuellement. Aussi de gros blocs de texte ne sont pas très lisibles.

4
répondu Tuukka Lindroos 2016-01-01 16:59:47

aucune des solutions précédentes ne fonctionne correctement... J'ai essayé toutes les façons, mais il ne me donne pas le résultat attendu... J'ai enfin trouvé qu'il y avait des erreurs dans le code... Et le code complet est donné ci-dessous.

<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>
3
répondu Atish Dipongkor 2016-01-01 16:57:30

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

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

    /* String */
    var str = '@stringvariable';
    alert(str);
}
3
répondu SZL 2016-01-01 17:00:21