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>
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.
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.
@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);
});
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!
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.
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.
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 .
Je préfère "<! -" "->" comme un "texte>"
<script type="text/javascript">
//some javascript here
@foreach (var item in itens)
{
<!--
var title = @(item.name)
...
-->
</script>
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>
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.
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
.
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.
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>
J'ai finalement trouvé la solution (* .vbhtml):
function razorsyntax() {
/* Double */
@(MvcHtmlString.Create("var szam =" & mydoublevariable & ";"))
alert(szam);
/* String */
var str = '@stringvariable';
alert(str);
}