Usando Razor dentro de JavaScript

Resuelto raklos asked hace 13 años • 13 respuestas

¿Es posible o existe una solución alternativa para usar la sintaxis de Razor dentro de JavaScript que está en una vista ( cshtml)?

Estoy intentando agregar marcadores a un mapa de Google... Por ejemplo, intenté esto, pero recibo un montón de errores de compilación:

<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>
raklos avatar Jan 05 '11 05:01 raklos
Aceptado

Utilice el <text>pseudoelemento, como se describe aquí , para forzar que el compilador Razor vuelva al modo de contenido:

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

Actualizar:

Scott Guthrie publicó recientemente sobre @:la sintaxis en Razor, que es un poco menos complicada que la <text>etiqueta si solo tiene una o dos líneas de código JavaScript para agregar. Probablemente sería preferible el siguiente enfoque, porque reduce el tamaño del HTML generado. (Incluso podría mover la función addMarker a un archivo JavaScript estático en caché para reducir aún más el tamaño):

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

Se actualizó el código anterior para que la llamada sea addMarkermás correcta.

Para aclarar, @:obliga a Razor a volver al modo de texto, aunque addMarkerla llamada se parece mucho al código C#. Luego, Razor retoma la @item.Propertysintaxis para decir que debería generar directamente el contenido de esas propiedades.

Actualización 2

Vale la pena señalar que Ver código realmente no es un buen lugar para colocar código JavaScript. El código JavaScript debe colocarse en un .jsarchivo estático y luego debe obtener los datos que necesita, ya sea a partir de una llamada Ajax o escaneando data-atributos del HTML. Además de permitir almacenar en caché su código JavaScript, esto también evita problemas con la codificación, ya que Razor está diseñado para codificar HTML, pero no JavaScript.

Ver código

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

código javascript

$('[data-marker]').each(function() {
    var markerData = $(this).data('marker');
    addMarker(markerData.Latitude, markerData.Longitude,
              markerData.Description, markerData.Title);
});
StriplingWarrior avatar Jan 04 '2011 23:01 StriplingWarrior

Acabo de escribir esta función auxiliar. Ponlo adentro App_Code/JS.cshtml:

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

Luego, en tu ejemplo, puedes hacer algo como esto:

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

Observe cómo no lo pongo entre comillas. Si el título ya contiene comillas, no explotará. ¡Parece manejar muy bien diccionarios y objetos anónimos también!

mpen avatar Nov 07 '2011 01:11 mpen

Estás intentando meter una clavija cuadrada en un agujero redondo.

Razor fue pensado como un lenguaje de plantilla generador de HTML. Es muy posible que consigas que genere código JavaScript, pero no fue diseñado para eso.

Por ejemplo: ¿Qué pasa si Model.Titlecontiene un apóstrofe? Eso rompería su código JavaScript y Razor no escapará correctamente de forma predeterminada.

Probablemente sería más apropiado utilizar un generador de cadenas en una función auxiliar. Probablemente habrá menos consecuencias no deseadas de ese enfoque.

Adam Lassek avatar Jan 04 '2011 22:01 Adam Lassek

¿Qué errores específicos estás viendo?

Algo como esto podría funcionar mejor:

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

Tenga en cuenta que necesita la <text>etiqueta mágica después de foreachpara indicar que Razor debe cambiar al modo de marcado.

marcind avatar Jan 04 '2011 23:01 marcind