One set of common questions in the world of ASP.NET MVC & JavaScript revolve around getting data from the server into JavaScript. This isn't about pulling data with SignalR or the WebAPI, but questions along the lines of:
- How do I generate an ActionLink in JavaScript and not hard code a URL?
- How do I get the URL for a WebApi?
- How do I get the ID value of something when the user clicks an item in a list?
If your JavaScript lives inside of your view, you can always use a Razor code expression to inject a value directly into the script. However, this doesn't solve all the scenarios listed above, and if your JavaScript is in an external .js file you don't have the ability to use code expressions. Here are a few techniques I've used to pass computed data from the server to the client.
Generating a <link> tag from a view is simple, and the value can represent an action link, a WebAPI endpoint, or a resource like a template. In the case of the WebAPI, for example, you could emit a link tag from a view using Url.RouteUrl (which requires an httproute member in route values to work properly).
<link id="cartApiUrl"
href ="@Url.RouteUrl("DefaultApi",
new { httproute = "", controller = "Cart"})"
rel="api"/>
With jQuery it is easy to find the value of the link, and use the value to call the web service.
var cartApiUrl = $("#cartApiUrl").attr("href");
$.post(cartApiUrl + "/" + itemId).then(updateCart);
Data- (data dash) attributes are popular because you can embed nearly anything inside, and they are easy to consume from jQuery. Let's take the question of "What item did the user click on?". If the view renders a data- attribute with an identifier inside, the task is trivial. The view code would look something like the following.
<div>
<img src="@item.ImageUrl" data-itemid="@item.Id" />
</div>
The JavaScript to retrieve the Id of the clicked item can use jQuery.data.
$("img[data-itemid]").click(function () {
var itemId = $(this).data("itemid");
// ...
});
You can even embed JSON data into a data- attribute, and if jQuery detects JSON data (the value starts with { or [), it will try to parse the value inside and give you an object back. This is useful in cases when you need to build options for a widget, like jQuery UI autocomplete, and include a server generated value (like the URL of the action for autocomplete to use as a data source). The view would look like:
<input type="search" name="q"
data-quicksearch ='{"source":"@Url.Action("Search")",
"minLength":4, "delay":250}'/>
Then a few lines of JavaScript could wire up autocomplete throughout an application:
$("input[data-quicksearch]").each(function() {
var input = $(this);
var options = input.data("quicksearch");
// You can now use:
// options.source
// options.minLength
// options.delay
input.autocomplete(options);
});
Yet another option is to dump a data structure into a view for script to consume. One framework to help with this approach is NGon (inspired by Gon in the Rails world). The NGon implementation takes information you put into a NGon property of the ViewBag and serializes the property into JSON. In a controller action you can throw anything into NGon.
public ActionResult Index()
{
ViewBag.NGon.Count = 3;
ViewBag.NGon.Name = "Home";
ViewBag.NGon.OtherStuff = new[]{2, 4, 6};
ViewBag.NGon.Thing = new Thing
{
Id = 5,
Name = "Home"
};
return View();
}
Then place the serialized data into your view using an HTML helper provided by NGon:
@Html.IncludeNGon()
And on the client, all the values are available to your script code.
var count = ngon.Count;
var thingName = ngon.Thing.Name;
NGon doesn't have a NuGet package and still uses the .NET JavaScriptSerializer (instead of Json.NET). Perhaps there is a pull request in Alex's future.