Jilet'i JavaScript içinde kullanma


435

Jilet sözdizimini JavaScript içinde bir görünümde ( cshtml) kullanmak mümkün mü veya geçici bir çözüm var mı?

Bir Google haritasına işaretçiler eklemeye çalışıyorum ... Örneğin, bunu denedim, ancak bir ton derleme hatası alıyorum:

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

3
@:sözdizimi ile ilgili güncellememle ilgilenebilirsin .
StriplingWarrior

@ herkes bu şekilde yapmayı düşünüyorsa, en azından verileri daha sonra JS'de kullanılan bazı JSON'u tanımlayan ayrı bir komut dosyası etiketine koyun. Ön uçtaki arka uç bağlantılı JS, birkaç kez benim için eski bir PITA oldu. Gerekmiyorsa kodu kodla yazmayın. Bunun yerine verileri dağıtın.
Erik Reppen

Yanıtlar:


637

Razor derleyicisini tekrar içerik moduna zorlamak için <text>sözde elemanı, burada açıklandığı gibi kullanın :

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

Güncelleme:

Scott Guthrie kısa süre önce Razor'da@: sözdizimi hakkında bir şeyler yayınladı<text> . Aşağıdaki yaklaşım muhtemelen tercih edilir, çünkü üretilen HTML'nin boyutunu azaltır. (Boyutu daha da azaltmak için addMarker işlevini statik, önbelleğe alınmış bir JavaScript dosyasına bile taşıyabilirsiniz):

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

Aramayı addMarkerdaha doğru yapmak için yukarıdaki kod güncellendi .

Açıklığa kavuşturmak için, @:Razor, addMarkerçağrı C # koduna çok benzese bile metin moduna geri dönüyor . Daha sonra Razor @item.Propertysözdizimini alır ve bu özelliklerin içeriğini doğrudan vermesi gerektiğini söyler.

Güncelleme 2

View code'un JavaScript kodu koymak için gerçekten iyi bir yer olmadığını belirtmek gerekir. JavaScript kodu statik bir .jsdosyaya yerleştirilmeli ve ardından bir Ajax çağrısından veya data-HTML'den nitelikleri tarayarak ihtiyacı olan verileri almalıdır . JavaScript kodunuzu önbelleğe almayı mümkün kılmanın yanı sıra, Razor HTML için kodlamak için tasarlanmış ancak JavaScript için tasarlanmadığından kodlama ile ilgili sorunları da önler.

Kodu Görüntüle

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

JavaScript kodu

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

3
Güncellenmiş örneğinizi anlamıyorum. Addmarker işlevi doğru mu?
NVM

2
@NVM: Aynı javascript kodunu birkaç kez çıkarmak yerine, tek bir javascript işlevi (önbelleğe alınmış bir .js dosyasında tutulabilir) oluşturmayı ve bu işleve birkaç çağrı yapmayı öneririm. Fonksiyonun doğru olup olmadığı hakkında hiçbir fikrim yok: Ben sadece OP koduna dayandı.
StriplingWarrior

1
Neden '@ Model.Latitude' foreach. Neden öğe değil.
NVM

5
C # değişkenlerinizin kaçması gerekir. Eğer @item.Titlebu kod patlayacak tek alıntı içeriyor.
mpen

7
@ Mark: İyi gözlem. Aslında, genellikle javascript ve Razor birleştirmeyiz hiç ben HTML oluşturmak için Razor kullanmayı tercih: Kendi kodu data-nitelikler ve sonra DOM bu bilgileri toplamak için statik, göze batmayan javascript kullanın. Ancak tüm tartışma, sorunun kapsamı dışındaydı.
StriplingWarrior

39

Ben sadece bu yardımcı işlevi yazdım. Koy App_Code/JS.cshtml:

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

Sonra örneğinizde, böyle bir şey yapabilirsiniz:

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

Etrafına nasıl alıntı koymadığımı fark et. Başlık zaten tırnak işareti içeriyorsa, patlamaz. Sözlükleri ve anonim nesneleri de güzel ele alıyor gibi görünüyor!


19
Görünümdeki bir nesneyi kodlamaya çalışıyorsanız yardımcı kod oluşturmaya gerek yoktur, zaten bir tane var. Bunu her zaman kullanıyoruz@Html.Raw(Json.Encode(Model))
PJH

2
Cevabınızı genişletebilir misiniz PJH? Sadece "Model" kodluyorsanız başlığı nasıl belirlersiniz?
15:33

2
Ayrıca, Model.Title ile bu yaklaşımı denediğimde kodlanmış javascript etrafında bazı ekstra tırnak olsun. Başka bir şeye birleştirirsem bile tırnaklardan kurtulamıyorum. Bu alıntılar senin js bir parçası haline gelir.
15:16

1
PJH'nin yorumu mükemmel. Bir şekilde sunucu tarafı modellerinin serisini, javascript bloğuna serileştirebilirsiniz.
netfed

24

Yuvarlak bir deliğe kare bir dübel sıkmaya çalışıyorsunuz.

Razor, HTML üreten bir şablon dili olarak düşünülmüştü. JavaScript kodu oluşturmak için çok iyi olabilirsiniz, ancak bunun için tasarlanmamıştır.

Örneğin: Model.TitleKesme işareti varsa ne olur ? Bu JavaScript kodunuzu kırar ve Razor varsayılan olarak doğru şekilde kaçmaz.

Bir yardımcı işlevde bir String üreteci kullanmak muhtemelen daha uygun olacaktır. Bu yaklaşımın muhtemelen daha az istenmeyen sonuçları olacaktır.


17

Hangi spesifik hataları görüyorsunuz?

Böyle bir şey daha iyi çalışabilir:

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

Tıraş makinesinin işaretleme moduna geçmesi gerektiğini belirtmek için simgesinden <text>sonra sihirli etikete ihtiyacınız olduğunu unutmayın foreach.


1
yineleme Modeli (foreach ile) ve @ Model.Latidue? yinelemenin işlevi nedir? sanırım bu bir şeyleri kaçırdı. @ item.Latitude etc
Nuri YILMAZ

12

Harici bir JavaScript dosyasında değil CSHTML sayfasında olduğu sürece bu iyi çalışır.

Razor şablon motoru, çıktısını umursamıyor ve <script>diğer etiketler arasında ayrım yapmıyor .

Ancak, XSS saldırılarını önlemek için dizelerinizi kodlamanız gerekir .


2
Sorumu güncelledim, benim için çalışmıyor-yanlış olan herhangi bir fikir? teşekkürler
raklos

3
@raklos: İplerden kaçman gerekiyor. ÇağrıHTML.Raw(Server.JavaScriptStringEncode(...))
SLaks

1
HTML.Raw(HttpUtility.JavaScriptStringEncode(...))- Sunucu özelliği şu anda bu yönteme sahip değil. HttpUtility yapar.
it3xl

1
The Razor template engine doesn't care what it's outputting and does not differentiate between <script> or other tags.Kesinlikle emin misin? stackoverflow.com/questions/33666065/…
HMR

2
@HMR: Bu yanıtı yazdığımda bu özellik yoktu.
SLaks

11

"<! -" "->" "metin>" gibi

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

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

</script>

bu garip bir şekilde benim için işe yarayan tek çözüm, çünkü dahil etmem gereken metinde @:<text>
Razor'un

8

Eklenecek bir şey - Razor sözdizimi hilighter (ve muhtemelen derleyici) açılış braketinin konumunu farklı yorumladığını buldum:

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

6

Basit ve iyi, basit bir örnek:

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

Bu, sayfanızda yukarıdaki kodu yerleştirdiğiniz konumda aşağıdaki gibi bir komut dosyası oluşturur:

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

Artık razorUserName, istemcide erişebileceğiniz ve kullanabileceğiniz adlı genel bir JavaScript değişkeniniz var . Razor motoru açıkça @User.Identity.Name(sunucu tarafı değişkeni) değerini çıkardı ve kod etiketinize yazdığı koda koydu.


6

Aşağıdaki çözüm benim için JavaScript'i Razor ile birleştirmekten daha doğru görünüyor. Şuna bir göz at: https://github.com/brooklynDev/NGon

ViewBag.Ngon'a neredeyse tüm karmaşık verileri ekleyebilir ve JavaScript'e erişebilirsiniz

Denetleyicide:

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

JavaScript'te:

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

Varsayılan kullanılarak serileştirilebilen düz eski CLR nesnelerine (POCO) izin verir JavascriptSerializer.


5

@: Ve öğelerinden başka bir seçenek daha vardır <text></text>.

<script>Bloğun kendisini kullanma .

Razor koduna bağlı olarak büyük miktarda JavaScript yapmanız gerektiğinde, bunu şu şekilde yapabilirsiniz:

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

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

Bu yolun avantajları, JavaScript ve Razor'u çok fazla karıştırmamasıdır, çünkü onları çok karıştırmak sonunda okunabilirlik sorunlarına neden olacaktır. Ayrıca büyük metin blokları da okunamıyor.


4

Önceki çözümlerin hiçbiri doğru çalışmıyor ... Tüm yolları denedim, ancak beklenen sonucu vermedi ... Sonunda kodda bazı hatalar olduğunu buldum ... Ve tam kod verildi altında.

<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

Sonunda çözümü buldum (* .vbhtml):

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

    /* String */
    var str = '@stringvariable';
    alert(str);
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.