Passing variables between controllers and JavaScript code in ASP.NET MVC
Posted: (EET/GMT+2)
Most web applications today require some JavaScript interaction. For instance, you might want to beef up your ASP.NET MVC web pages (views) with jQuery UI components. When doing so, you will quickly notice that you need some interaction between your JavaScript code and your C# controller code.
For instance, let's take the simple example of the jQuery UI tabs widget. This widget ("control") allows you to convert a set of DIVs into a tabbed control, and using JavaScript, you can control many different options of the widget.
For instance, your application might contain multiple tabs, and you might wish to control the initial tab shown, when it's not the first one. This can be done using the action option, which is a simple integer value from zero to the number of tabs minus one. Here's a simple JavaScript example on initializing the tabs widget with the given tab index:
$(function () {
$("#tabs").tabs({ active: 1 });
});
Now, what if you wanted to set the active/select tab inside your controller based on some application logic? This is easy, as you can use the convenient ViewBag variable to set the active page when the page loads.
You can set the ViewBag variable as follows inside your C# MVC controller:
public ActionResult JavaScriptTest()
{
ViewBag.TabToOpen = 1;
return View();
}
Now that the ViewBag has been set, you can refer to it in your JavaScript code like this:
$(function () {
// get data from the controller
var tabToOpen = @ViewBag.TabToOpen;
$("#tabs").tabs({ active: tabToOpen });
});
The above works nicely, except for one little thing. Visual Studio thinks that there's a syntax error in the JavaScript code, as it cannot statically analyze the complete code and know that a value does get passed to the ViewBag property TabToOpen. To get rid of the syntax error warning (which is always a good thing), you can slightly adjust the JavaScript code:
// a better implementation, to keep Visual Studio’s code editor happy var tabToOpen = 0@(ViewBag.TabToOpen);
Since the tabToOpen variable is an integer, you can prefix it with the zero. This keeps Visual Studio happy. However, you must also put parenthesis around the ViewBag reference, as to force Razor to execute the code (otherwise, the Razor parser does not recognize the @ sign, because it is prefixed with the number zero. This is called an explicit expression in Razor parlance, and is useful in situations like this. Note that if you variable were a string instead of an integer like above, this trick is not needed, because and empty string "" is naturally a valid string.
Now that you know how to pass variables from MVC controllers to JavaScript, you need to learn how to do it the other way around. Say, you wanted to know which tab was selected when the user submits the form. To get the active tab index in JavaScript, you can write code like this:
var currentlyActiveTab = $("#tabs").tabs("option", "active");
This gives you the zero- based index of the tab that user has selected at runtime in his/her browser. To get this value back to the MVC controller class, you need to make sure it gets passed over the wire inside the HTTP POST (submit) request.
There are multiple ways to do this, but one simple way is to use HTML hidden fields. This works fine when you are using regular HTML forms, but if you were using Ajax/JSON calls directly to the backend, then you don't need to follow this route.
To define a hidden input field, use HTML code like this in your Razor view:
<form action="/home/JavaScriptTest" method="post" id="theForm" enctype="multipart/form-data">
<input id="selectedTabIndexHiddenField" name="selectedTabIndexHiddenField" type="hidden" />
<input type="submit" value="Submit Form" />
</form>
Above, the hidden field is defined with double naming, the "id" is defined so that you can easily refer to the field in JavaScript code, and the "name" is defined so that you can access the field's value in the ASP.NET backend through the Request.Form collection. Note that if the name attribute is missing from the input tag, the value does not get passed back from the browser to your MVC application.
Finally, remember that the form method should be POST, because you usually have multiple fields that get submitted back to the web application. The GET method would work, too, but is not recommended in this case.
On the MVC backend, here's how you would access the hidden field's value in C# code:
[HttpPost]
public ActionResult JavaScriptTest(string id)
{
string hiddenFieldValue = Request["selectedTabIndexHiddenField"];
if (hiddenFieldValue != "")
{
int selectedTab = int.Parse(hiddenFieldValue);
// your code goes here...
}
return View();
}
Since the hidden field's value is part of the form submit, you can simply access the value through the Request object. The name of the request key matches the name attribute of the HTML hidden field.
The final part is to set the hidden field's value inside the browser. A convenient place to do this is to hook some code to the submit event, and set the value there. Here's an example in JavaScript:
// store data back to the controller during form submit
$("#theForm").submit(function () {
var currentlyActiveTab = $("#tabs").tabs("option", "active");
$("#selectedTabIndexHiddenField").val(currentlyActiveTab);
});
Here, the form's submit button generates the submit event, which with a little of jQuery magic executes the above code. First, we get the select tab's index, and then set the hidden field's value using the jQuery "val" function. Once the submit reaches the backend, the value can be read as shown above.
All in all, this should do the trick in your own MVC applications, too!
Good luck!