Использование Razor в JavaScript

Возможно ли это или есть обходной путь использования синтаксиса Razor в JavaScript, который находится в представлении (cshtml)?

Я пытаюсь добавить маркеры в карту Google... Например, я пробовал это, но получаю массу ошибок компиляции:

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

Ответ 1

Используйте псевдоэлемент <text>, как описано здесь, чтобы заставить компилятор Razor вернуться в режим содержимого:

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

Скотт Гатри недавно опубликовал о синтаксисе @: в Razor, который немного менее clunky, чем тег <text>, если у вас есть только один или две строки кода JavaScript для добавления. Возможно, предпочтительнее следующий подход, поскольку он уменьшает размер сгенерированного HTML. (Вы даже можете переместить функцию addMarker в статический, кешированный файл JavaScript, чтобы еще больше уменьшить размер):

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

Обновлен приведенный выше код, чтобы сделать правильный вызов addMarker.

Чтобы уточнить, @: заставляет Razor вернуться в текстовый режим, хотя вызов addMarker выглядит очень похож на код С#. Затем Razor подбирает синтаксис @item.Property, чтобы сказать, что он должен напрямую выводить содержимое этих свойств.

Обновление 2

Стоит отметить, что просмотр кода на самом деле не является хорошим местом для размещения кода JavaScript. Код JavaScript должен быть помещен в статический файл .js, а затем он должен получить данные, которые ему нужны либо из Ajax-запроса, либо путем сканирования атрибутов data- из HTML. Кроме того, чтобы кешировать ваш код JavaScript, это также позволяет избежать проблем с кодировкой, поскольку Razor предназначен для кодирования HTML, но не для JavaScript.

Просмотреть код

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

Код JavaScript

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

Ответ 2

Я только что написал эту вспомогательную функцию. Поместите его в App_Code/JS.cshtml:

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

Затем в вашем примере вы можете сделать что-то вроде этого:

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

Обратите внимание, что я не помещаю кавычки вокруг него. Если заголовок уже содержит кавычки, он не будет взорваться. Кажется, тоже хорошо обрабатывать словари и анонимные объекты!

Ответ 3

Вы пытаетесь зажать квадратный штифт в круглом отверстии.

Razor был предназначен как язык шаблонов HTML-генерации. Вы вполне можете получить его для генерации кода JavaScript, но он не был предназначен для этого.

Например: Что делать, если Model.Title содержит апостроф? Это нарушит ваш JavaScript-код, и Razor не удастся избежать его по умолчанию.

Вероятно, было бы более целесообразно использовать генератор строк в вспомогательной функции. Вероятно, будет меньше непредсказуемых последствий этого подхода.

Ответ 4

Какие конкретные ошибки вы видите?

Что-то вроде этого может работать лучше:

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

Обратите внимание, что вам нужен магический тег <text> после foreach, чтобы указать, что Razor должен переключиться в режим разметки.

Ответ 5

Это будет работать нормально, если на странице CSHTML, а не на внешнем файле JavaScript.

Механизм шаблонов Razor не заботится о том, что он выводит и не проводит различия между <script> или другими тегами.

Однако вам нужно закодировать свои строки, чтобы предотвратить атаки XSS.

Ответ 6

Я предпочитаю "<! -" "- > " как "текст > "

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

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

</script>

Ответ 7

Одна вещь, которую нужно добавить - я обнаружил, что синтаксический hilighter Razor (и, вероятно, компилятор) интерпретирует позицию открытой скобки по-разному:

<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

Простой и хороший прямой пример:

<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 an odd workaraound, but it works.
    @{
        var outScript = "var razorUserName = " + "\"" + @User.Identity.Name + "\"";
    }
    @MvcHtmlString.Create(outScript);
</script>

Это создает script на вашей странице в месте размещения кода выше, который выглядит следующим образом:

<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 an odd workaraound, but it works.

    var razorUserName = "daylight";
</script>

Теперь у вас есть глобальная переменная JavaScript с именем razorUserName, которую вы можете получить и использовать на клиенте. Двигатель Razor, очевидно, извлек значение из @User.Identity.Name (серверная переменная) и поместил его в код, который он записывает в тэг script.

Ответ 9

Существует еще один вариант, чем @: и <text></text>.

Использование <script> блокирует себя.

Когда вам нужно делать большие куски JavaScript в зависимости от кода Razor, вы можете сделать это следующим образом:

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

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

Плюсы такого способа заключаются в том, что он не слишком сильно смешивает JavaScript и Razor, потому что их смешение в конечном итоге вызовет проблемы с читабельностью. Также большие текстовые блоки не очень читаемы.

Ответ 10

Следующее решение кажется мне более точным, чем сочетание JavaScript с Razor. Проверь это: https://github.com/brooklynDev/NGon

Вы можете добавить почти любые сложные данные в ViewBag.Ngon и получить доступ к ним в JavaScript

В контроллере

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

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

Он позволяет любому простым старым объектам CLR (POCOs), которые могут быть сериализованы с использованием стандартного JavascriptSerializer.

Ответ 11

Ни одно из предыдущих решений не работает правильно... Я пробовал все пути, но это не дало ожидаемого результата... Наконец-то я обнаружил, что в коде есть некоторые ошибки... И полный код приведен ниже.

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

Ответ 12

Наконец, я нашел решение (*.vbhtml):

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

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