Aserian
Aserian

Reputation: 1127

Updating only a partial view in asp.net mvc from another partial view

I have a question concerning updating a partial view from another partial view where the first view is contained.

I have 4 dropdowns that are populated based on the previous selections, then the user may submit their selections and a database is queried and a table is populated based on their selections. I should note that I am very new to asp.net mvc and it's all still quite confusing to me.

Below is my code:

<form action="/Home/LoadRelease" method="post" style="text-align: center;">
    @*Headers*@
    <div id="BusinessAreaLabel" class="inline" style="width:14em;">Business Area</div>
    <div id="GenericProjectLabel" class="inline" style="width:13em;">Generic Project</div>
    <div id="ProjectLabel" class="inline" style="width:17em;">Project</div>
    <div id="ReleaseLabel" class="inline" style="width:13em;">Release</div>

    <br />

    @*Dropdowns*@
    <select id="BusinessAreaDropDown" name="BusinessArea" onchange="javascript: FillGenericProject(); FillProject(); FillReleases();" style="width: 13em;">
    @Html.Partial(@"Dropdowns\_BusinessArea", Model.ProjectViewModels);
    </select>
    <select id="GenericProjectDropDown" name="GenericProject" onchange="javascript: FillProject(); FillReleases();" style="width: 13em;"></select>
    <select id="ProjectDropDown" name="Project" style="width: 17em;" onchange="javascript: FillReleases();"></select>
    <select id="ReleaseDropDown" name="Release" style="width: 13em;"></select>
    <input type="submit" id="GoButton" style="visibility:hidden;" value="Go" />

</form>
<form id="ReleaseTableBody" style="text-align:center;">
    @Html.Partial("_TableBody", Model.OpenCloseViewModels)  //I want to update this.
</form>
<br />

and Home/LoadRelease:

    [HttpPost]
    public ActionResult LoadRelease(string Project, string Release)
    {
        var ProjectID = _ProblemReportsDB.ProjectMaps
             .Where(r => r.Project == Project)
             .Select(r => r.ID).FirstOrDefault();

        ViewBag.Project = Project;

        var Releases = from row in _ProblemReportsDB.PlannedOpenCloses
                       where (row.Project == ProjectID)
                       select row;

        return PartialView("_TableBody", Releases.ToList());
    }

The above loads the partial view "_TableBody", but actually directs to the page containing only the contents of _TableBody.

Ideally, I would remain on the page displaying and only update the _TableBody section of the page. I think I understand why it is currently failing, I'm telling it to run the action /Home/LoadRelease, which returns the _TableBody partial view, which it loads.

I'm having trouble figuring out how to make it only update the _TableBody partial view.

Thanks for any help you can offer.

EDIT:

Attempting Jasens method I have begun using an ajax function: Still loads to another page instead of updating the partial:

Code:

    @using (Html.BeginForm("LoadRelease", "Home", FormMethod.Post, new { id = "DropDownForm", style="" }))
{ 
    @*Headers*@
    <div id="BusinessAreaLabel" class="inline" style="width:14em;">Business Area</div>
    <div id="GenericProjectLabel" class="inline" style="width:13em;">Generic Project</div>
    <div id="ProjectLabel" class="inline" style="width:17em;">Project</div>
    <div id="ReleaseLabel" class="inline" style="width:13em;">Release</div>

    <br />

    @*Dropdowns*@
    <select id="BusinessAreaDropDown" name="BusinessArea" onchange="javascript: FillGenericProject(); FillProject(); FillReleases();" style="width: 13em;">
        @Html.Partial(@"Dropdowns\_BusinessArea", Model.ProjectViewModels);
    </select>
    <select id="GenericProjectDropDown" name="GenericProject" onchange="javascript: FillProject(); FillReleases();" style="width: 13em;"></select>
    <select id="ProjectDropDown" name="Project" style="width: 17em;" onchange="javascript: FillReleases();"></select>
    <select id="ReleaseDropDown" name="Release" style="width: 13em;"></select>
    <button type="submit" id="GoButton" style="visibility:hidden;">Go</button>
}
@*</form>*@

<form id="ReleaseTableBody" style="text-align:center;">
    @Html.Partial("_TableBody", Model.OpenCloseViewModels)
</form>
<br />

In index: (Parent of _DropDownBody):

<script src="~/Scripts/jquery-1.10.2.js">
    $(document).ready(function () {
        $("#DropDownForm").on("submit", function (event) {
            event.preventDefault();

            var form = $(this);
            var Project = $('#ProjectDropDown').val();
            var Release = $('#ReleaseDropDown').val();
            alert(Project);
            $.ajax({
                url: form.attr("action"),
                method: form.attr("method"),
                data: form.serialize()
            })
            .done(function (result) {
                $("#ReleaseTableBody").html(result);
            });
        });

    });
</script>

Using A. Burak Erbora's method produces the same issue as well. Am I missing something?

Final edit: Jasen's answer worked and allowed me to update a partial view without redirecting. Still having issues getting the partial to show my content, but as far as the question goes - Jasen's answer works!

Upvotes: 0

Views: 6008

Answers (2)

Jasen
Jasen

Reputation: 14250

Submitting a form will cause navigation. Since you want to stay on the same page you'll need to trap the submission event and use AJAX to update your page.

Main View

@using(Html.BeginForm("LoadRelease", "Home", FormMethod.Post, new { id = "DropDownForm", style = "" })
{
    <!-- your drop down inputs -->
    <button type="submit">Go</button>
}
<form id="ReleaseTableBody" style="text-align:center;">
    @Html.Partial("_TableBody", Model.OpenCloseViewModels)  //I want to update this.
</form>

Then the page script (don't forget to load jquery.js before this). Also note if you are embedding partial views you need to move this script "up" to the parent since @section will not render in partials.

<script src="jquery.js"></script>
<script>
$(document).ready(function() {
    $("#DropDownForm").on("submit", function(e) {
        // prevent default submission
        e.preventDefault();

        // do AJAX post instead
        var form = $(this);
        $.ajax({
            url: form.attr("action"),
            method: form.attr("method"),
            data: form.serialize()
        })
        .done(function(result) {
            // replace content
            $("#ReleaseTableBody").html(result);
        });
    });
}
</script>

Controller action unchanged

[HttpPost]
public ActionResult LoadRelease(string Project, string Release)
{
    // search
    return PartialView("_TableBody", results);
}

Upvotes: 3

A. Burak Erbora
A. Burak Erbora

Reputation: 1064

First off, I'd recommend you use html helpers. What you seem to need here is an ajax call instead of a standard form post. Instead of

<form action="/Home/LoadRelease" method="post" style="text-align: center;">

you can use

@using (Ajax.BeginForm("LoadRelease", "Home", options)){

        @*Headers*@
        <div id="BusinessAreaLabel" class="inline" style="width:14em;">Business Area</div>
        <div id="GenericProjectLabel" class="inline" style="width:13em;">Generic Project</div>
        <div id="ProjectLabel" class="inline" style="width:17em;">Project</div>
        <div id="ReleaseLabel" class="inline" style="width:13em;">Release</div>

        <br />

        @*Dropdowns*@
        <select id="BusinessAreaDropDown" name="BusinessArea" onchange="javascript: FillGenericProject(); FillProject(); FillReleases();" style="width: 13em;">
        @Html.Partial(@"Dropdowns\_BusinessArea", Model.ProjectViewModels);
        </select>
        <select id="GenericProjectDropDown" name="GenericProject" onchange="javascript: FillProject(); FillReleases();" style="width: 13em;"></select>
        <select id="ProjectDropDown" name="Project" style="width: 17em;" onchange="javascript: FillReleases();"></select>
        <select id="ReleaseDropDown" name="Release" style="width: 13em;"></select>
        <input type="submit" id="GoButton" style="visibility:hidden;" value="Go" />

    }

and somewhere in your html you have:

<div id="ReleaseTableBody">
    @Html.Partial(_TableBody", Model.OpenCloseViewModels)
</div>

you will need to define the options object for the Ajax helper like:

var options = new AjaxOptions
{
    HttpMethod = "POST",
    UpdateTargetId = "ReleaseTableBody",
    OnBegin = "OnCallbackBegin",
    OnFailure = "OnCallbackFailure",
    OnSuccess = "OnCallbackSuccess",
    LoadingElementId = "loading"
};

you can also use the event callback methods if you define their JavaScript functions like:

<script>

function OnCallbackBegin() {
    $(".btn-loading-icon").show();
    $(".btn-loading-text").hide();
}
function OnCallbackSuccess(data) {
    //alert("onSuccess: result = " + data.result);
    $(".btn-loading-icon").hide();
    $(".btn-loading-text").show();
    SomeOtherFunction();
}

I would also advise using the @Html.DropdownFor helper for your dropdowns.

Upvotes: 1

Related Questions