Set session variable with ajax call and refresh partial

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.

Answers


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>

For first time your dropdown will have value with default loading. but when any update happen you need to reload the partial view again. so your html will

<form><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="javascript:setState(@item.Id);">
                        <img src="@Url.Action("Image", "Resource", new { id = item.Id })" alt="@item.Name" class="img-responsive" />
                    </a>
                </li>
                }
        </ul>
    </div>
</div>

Now you need to define javascript method setState(Id)

         <script type="text/javascript">
   function setSate(Id)
    {
    $.ajax({
    url:'@Url.Action("SetStateVariable")'+'?Id='+Id,
    type:'get'
    }).done(function(data){
    $("form").load('@Url.Action("SessionStateVariableSelector")');

    });
    }
</script> 

Hope it can resolve your problem :)


I'm not entirely sure what you want to do but maybe something like this will help you:

var replaceDDL = function (ddlValue) {
    $.ajax({
        url: '@Url.Action("SessionStateVariableSelector", "YourController")',
        type: "GET",
        data: {
            "ddlValue": ddlValue
        },
        success: function (response) {
            $('#yourDDLId').replaceWith(response);
            $('#yourDDLId li a').click(function() { replaceDDL($(this).text()); });
        }
    });
};

$('#yourDDLId li a').click(function() { replaceDDL($(this).text()); });


public PartialViewResult SessionStateVariableSelector(string ddlValue)
{
    ....
    return PartialView("_sessionStateVariableSelector", model);
}

I created a method to call your controller and get the partialView with your ddl when you select an option from your ddl.


Need Your Help

Split actionbar for a specific fragment

android android-fragments split android-actionbar

I have an activity with three fragments. Fragment A has 1 item in actionbar. Fragment B has 4 items in actionbar, and Fragment C has 1. So, I want to have split actionbar when I change to fragment ...