Set session variable with ajax call and refresh partial

asp.net-mvc, asp.net-mvc-4, asp.net-mvc-5, jquery, twitter-bootstrap

Solution

JQuery way:

I like to use the jquery `.load()` method for Ajax Partial View refresh actions.

Let's say that your partial is encapsulated in a div (it could just as well be a span):

<div id="divSessionStateVariableSelector">
     @Html.RenderAction("SessionStateVariableSelector","DropDownController");
</div>

When your page first renders, you would get your "Default" behavior. Let's assume that the id of your rendered Dropdown button is `"ddbSessionStateVariableSelector"`. The name is only important because we will be binding a jquery event action against the name. Could just as easily be done with a class...

Next, create an event listener that reloads your partial upon click event, passing the selection text as parameter to your partial view's child action:

<script>
$(".yourUlClassName li a").click(function() {
    $('#divSessionStateVariableSelector')
              .load('/DropDownController/SessionStateVariableSelector/' 
                     + $(this).text());

});
</script>

Important: change your partial child action signature to take an `id` as string. I'm working with the assumption that you use the "Default" route and are not interested in creating a new one.

public PartialViewResult 
           SessionStateVariableSelector(string id="{Default Value}")

AngularJS way

Even easier (but outside your range of question) use a binding framework like Angularjs to simply create a binding in your partial using the input.

It means learning a little extra (maybe a lot), but it would be a very simple implementation within your partial markup

<div ng-controller="SessionStateVariableSelectorController">

{{ SessionStateVariableSelector ||

<select ng-model="SessionStateVariableSelector" ... >

</div>

and some a little included javascript code:

<script>
function SessionStateVariableSelectorController($scope) {
$scope.SessionStateVariableSelector="Default Value";
  };
</script>

Problem

I'm trying to create a Bootstrap Dropdown Button. The list should have links that, when pressed, set a session state variable. The only page update I would like to happen is to render the Dropdown again, so the selected item appears as the header. The Dropdown itself is rendered as a Partial View by a call to Child Action ``` public PartialViewResult SessionStateVariableSelector() { string stateVariable = Session["theStateVariable"] as string; StateVariableCollectionViewModel model = GetThisFromSomewhere(); model.SelectedStateVariable = stateVariable ?? string.Empty; return PartialView("_sessionStateVariableSelector", model); } ``` I initially had two ideas as how to do this. A) `Ajax.Beginform` surrounding the Dropdown that posts to the same action. That way I would do a `UpdateTargetId` that updates the Dropdown with a new selected variable. I just have no idea how to do the `AutoPostBack` using the Bootstrap theme. I wanted to get the same behavior as when using `<a>` inside the Dropdown list. Could I intercept the `<a>` href as a postback from the AJAX call? ``` @using (Ajax.BeginForm("SetFund", new AjaxOptions { UpdateTargetId = "theSelector", HttpMethod = "Post" })) { <div class="row"> <div class="col-md-12"> <div class="btn-group pull-right" id="theSelector"> <button class="btn btn-default btn-lg dropdown-toggle" type="button" data-toggle="dropdown"> @if(string.IsNullOrEmpty( Model.SelectedStateVariable)) { Please select.... } else { <img src="@Url.Action("Image", "Resource", new { id = Model.SelectedStateVariable })" alt="image" class="img-responsive" /> <span class="caret"></span> } </button> <ul class="dropdown-menu" role="menu"> @foreach (var item in Model) { <li> @Html.HiddenFor(modelItem => item.Id) <img src="@Url.Action("Image", "Resource", new { id = item.Id })" alt="@item.Name" class="img-responsive" /> </li> } </ul> </div> </div> </div> } ``` B) Set each list element as a `<a>` with a href to some action the sets the state and somehow refreshes the partial as part of the result. I have no idea if this is possible. ``` <div class="row"> <div class="col-md-12"> <div class="btn-group pull-right" id="theSelector"> <button class="btn btn-default btn-lg dropdown-toggle" type="button" data-toggle="dropdown"> @if(string.IsNullOrEmpty( Model.SelectedStateVariable)) { Please select.... } else { <img src="@Url.Action("Image", "Resource", new { id = Model.SelectedStateVariable })" alt="image" class="img-responsive" /> <span class="caret"></span> } </button> <ul class="dropdown-menu" role="menu"> @foreach (var item in Model) { <li> <a href="@Url.Action("SetStateVariable", new { Id = item.Id })"> <img src="@Url.Action("Image", "Resource", new { id = item.Id })" alt="@item.Name" class="img-responsive" /> </a> </li> } </ul> </div> </div> </div> ``` I am really new to ASP.NET MVC and Web programming. EDIT I think all these answers below are in some way correct and each one of them adds something towards a workable solution. I picked the one that gave me AngularJS way as that is what I went with in the end.

Original source