I had started to write this post a while back, but never polished it up enough to make it worthy of print, however it does offer some insight into a clean way of injecting model variables into javaScript the 'right way'*, that is not putting <%= %> tags in your script. I've learned quite a lot since I started this blog posting, so I'm NOT recommending this as the only approach, or best approach, etc. Just as a neater way to inject your model into your client side script.
An example of using JQuery with ASP.NET/MVC with Rick Stahl''s Web Utility to populate child controls:
Let's assume you want to use JQuery where you wish to have client side data sent back to a controller without a full page post back.
* I did say 'reight way' in quotes - ;-)
For the project:
You need to inject a client-side JavaScript. While you can spin one up by hand, why not use go green and recycle? Rich Stahl's site: http://www.west-wind.com has a variety of tools, some of which are free. Download http://www.west-wind.com/westwindwebtoolkit/. What we're interested in here is the Web Utility Support Classes
Download the utility and add references for Westwind.Utilities and Westwind.Web to your project. You'll also need to add ScriptVariableInjectionHelper.cs to your helpers folder.
ScriptVariableInjectionHelper provides an easy way for server code to publish strings into client script code. This object basically provides a mechanism for adding key value pairs and embedding those values into an object that is hosted on the client.
For the Master Page:
Before you start injecting scripts willy-nilly all over your pages, it is better to inject all of your client-side scripts into the header along with your other JavaScript includes.. If you are using a master page, this becomes very easy. Beneath where you put all of your other site-wide include tags, and above a content placeholder for page-level scripts, I also add a simple test for controller scripts I inject into the ViewData and a test to verify it is there before you write it out.
<script type="text/javascript" language="javascript" src="<%=Url.Content("~/Content/Scripts/jquery-1.3.2.min.js")%>"></script>
<% if(ViewData.Contains("clientScript")){
Response.Write(ViewData["clientScript"].ToString());
}%>
<asp:ContentPlaceHolder ID="Scripts" runat="server" />
</head>
For the Controller:
Now that we have a way to inject our script and a target to inject it into, we need to simply send it down for manipulation.
From your ActionMethod we add a call to a new InjectClientScript method...
public virtual ActionResult Edit(Guid id)
{
Criterion model = _CriterionSvc.GetCriterion(id);
InjectClientScript(model);
return View(model);
}
private void InjectClientScript(object model)
{
// instantiate the utility (view is the name of the JavaScript object that will appear in the View
ScriptVariables scriptVars = new ScriptVariables("view");
// add our ProfileCommon data (user context)
scriptVars.Add("Profile", profile.Preferences);
// add our model being injected
if (model != null)
scriptVars.Add("Model", model);
// call the westwind utility and inject into viewdata
ViewData["clientScript"] = scriptVars.GetClientScript(true);
}
For the view:
The output is injected into a variable called view, which in turn contains our Controller objects we injected (Profile and Model). Note Model contains objects of its own. In this example, CriterionType is one such object. You can configure the westwind utility to traverse child objects or not.
<script type="text/javascript">
var view = {
Profile: {"CountryId":0,"StateId":21,"DistrictId":6108},
Model: {"CriterionTypeId":7,"CriterionType":{"DomainId":1,"Domain":null,"Description":null,"Code":"Instructional Design Skills","Id":7,"Guid":{"Length":36},"ModifiedDate":new Date(-62135578800000),"ModifiedBy":null},"Description":null,"Code":"Teacher provides relevant examples and demonstrations to illustrate concepts and skills.\r\n","Id":31,"Guid":{"Length":36},"ModifiedDate":new Date(1245546360000),"ModifiedBy":"Admin"}
};
</script>
You now simply need to access your javascript variables.Below is a simple example of accessing those variables and sending them to a jquery function that would populate a dropdown via ajax.
$.PopulateDropdown("CriterionTypeId", "/CriterionType/GetCriterionTypeCollection/" + view.Model.CriterionType.DomainId, view.Model.CriterionTypeId);
your jquery plug in would look something like this:
(function () {
$.issPopulateDropdown = function (control, query, selected, emptyMsg) {
control = "#" + control;
$(control + ' > option').remove(); // remove any existing options
$(control).show();
$('#emptyMsg').remove(); // remove any existing message
$.ajax({
type: "GET",
contentType: "application/json; charset=utf-8",
url: query,
dataType: "json",
success: function (data) {
if (data.length > 0) {
var options = '<option id="0">Select</option>';
for (p in data) {
var item = data[p];
options += "<option value='" + item.Id + "'>" + item.Key + "</option>";
}
$(control).html(options);
$(control).val(selected);
$('#emptyMsg').remove();
}
else {
alert('there are not any existing options');
$(control).after('<div id="emptyMsg">' + emptyMsg + '</div>');
$(control).hide();
}
} // end success
}); // end ajax
} // end issPopulateDropdown
));