Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Razor within JavaScript

Is it possible or is there a workaround to use Razor syntax within JavaScript that is in a view (cshtml)?

I am trying to add markers to a Google map... For example, I tried this, but I'm getting a ton of compilation errors:

<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> 
like image 874
raklos Avatar asked Jan 04 '11 22:01

raklos


People also ask

Can you use JavaScript with Razor?

Solution 1. You can't. Razor is a . NET assembly and doesn't run on JavaScript or in a browser.

Can you mix Razor pages and MVC?

You can add support for Pages to any ASP.NET Core MVC app by simply adding a Pages folder and adding Razor Pages files to this folder.

Does not intermix JavaScript code in your page markup?

Unobtrusive JavaScript is a general term that conveys a general philosophy, similar to the term REST (Representational State Transfer). The high-level description is that unobtrusive JavaScript doesn't intermix JavaScript code in your page markup.


2 Answers

Use the <text> pseudo-element, as described here, to force the Razor compiler back into content mode:

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

Scott Guthrie recently posted about @: syntax in Razor, which is slightly less clunky than the <text> tag if you just have one or two lines of JavaScript code to add. The following approach would probably be preferable, because it reduces the size of the generated HTML. (You could even move the addMarker function to a static, cached JavaScript file to further reduce the size):

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

Updated the above code to make the call to addMarker more correct.

To clarify, the @: forces Razor back into text mode, even though addMarker call looks a lot like C# code. Razor then picks up the @item.Property syntax to say that it should directly output the contents of those properties.

Update 2

It's worth noting that View code really isn't a good place to put JavaScript code. JavaScript code should be placed in a static .js file, and then it should get the data that it needs either from an Ajax call or by scanning data- attributes from the HTML. Besides making it possible to cache your JavaScript code, this also avoids issues with encoding, since Razor is designed to encode for HTML, but not JavaScript.

View Code

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

JavaScript code

$('[data-marker]').each(function() {     var markerData = $(this).data('marker');     addMarker(markerData.Latitude, markerData.Longitude,               markerData.Description, markerData.Title); }); 
like image 85
StriplingWarrior Avatar answered Oct 07 '22 06:10

StriplingWarrior


I just wrote this helper function. Put it in App_Code/JS.cshtml:

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

Then in your example, you can do something like this:

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

Notice how I don't put quotes around it. If the title already contains quotes, it won't explode. Seems to handle dictionaries and anonymous objects nicely too!

like image 37
mpen Avatar answered Oct 07 '22 06:10

mpen