How do I post back data from a partial view in MVC

2019-09-02 10:40发布

问题:

I have a main view and two partial views

  1. Index - main view
  2. _Details - partial view
  3. _Address- partial view inside the Details partial view

Index - main view

    @model IndexViewModel
    @{
        Layout = "~/Views/Shared/_CodeLayout.cshtml";

    }

@Html.Partial("_Details", Model)

2. _Details - partial view

     @model IndexViewModel
<div id="Detailsdiv">  



    @using (Html.BeginForm("_Details", "FS", FormMethod.Post, new
        {
            id =
              "frmFS",
            @class = "form-horizontal"
        }))
    { 

    <div class="row">
        <div class="col-lg-1 nopadding">
            <div class="col-lg-1 nopadding">
                @Html.LabelFor(m => m.User.Name):
            </div>
            <div class="col-lg-2">
                @Html.TextBoxFor(m => m.User.Name, new { @id = "txtName", @style = "width:140px;height:24px", @maxlength = "25" })
            </div>
        </div>
    </div>
  @Html.Action("_Address", "Shared", new { userId = Model.User.UserId })
        }
        <button type="button" value="Save" ID="btnSave"> Save </button>
        }
    </div>

3. _Address- partial view

@model AddressViewModel 

<div id="divAddress">

    @using (Html.BeginForm("_Address", "Shared", FormMethod.Post, new { id = "frmAddress", @class = "form-horizontal" }))
    {
<div class="row">
<div class="col-lg-1 nopadding">
                                    @Html.LabelFor(m => m.Address.AddressDesc):
                                </div>
                                <div class="col-lg-2">
                                    @Html.TextBoxFor(m => m.Address.AddressDesc, new { @id = "txtAName", @style = "width:140px;height:24px", @maxlength = "25" })
                                </div>
</div>
---
-
-
And some more 
  <button type="button" value="Save" ID="btnCreate"> Create </button>
</div>

}



   $('#btnCreate').click(function () {

                $("#ajax_loader").show();
                 var inputdata = $("#frmAddress").serialize();
                $.ajax({
                    url: '@Url.Action("CreateAddress", "Shared")',
                    type: 'POST',
                    cache: false,
                    data: inputdata
                }).done(function (result) {
                    $("#divAddress").html(result);
                    $("#ajax_loader").hide();
                });

        });

SharedConroller

Get Action for Address

public ActionResult _ Address (short userId )
        {


}

public ActionResult CreateAdderess(AddressViewModel addressViewModel)
        {
Create address…………..
But AddressViewModel is coming null 
}
    }


public class AddressViewModel
{
    [Key]
    public decimal AddressId { get; set; }


    [DisplayName("Address Type")]

    public string Addr_Typ { get; set; }
    [DisplayName("Address Description")]
    [MaxLength(256)]
    public string Addr_Desc { get; set; }
    [DisplayName("City")]
    [MaxLength(30)]
    public string City_Nm { get; set; }

    [DisplayName("State")]
    [MaxLength(2)]
    public string State_Cd { get; set; }

    [DisplayName("Zip")]
    [RegularExpression(@"^\d{5}(?:[\-]?\d{4})?$", ErrorMessage = "Invalid Zip")]
    [MaxLength(10)]
    public string Zip { get; set; }
}

Post back from the _Details is working. Post back from the Address- partial view is not working.

Thanks in advance

回答1:

I'm assuming you have both HTTP GET and HTTP POST actions that return the same, partial view. You need a DIV on the parent view that contains a partial view

<div id="divYourPartial"></div>

On load (or change of id value within the page) the data is loaded into the partial view from the HTTP GET action. The POST activity is handled by the partial view itself using an Ajax.BeginForm element

$.ajax({
    url: '/YourController/YourAction/' + YourId,
    type: "get",
    success: function (result) {
    $("#divYourPartial").html(result);
    }
});

A partial view might look like this. Note that the update target is the outer div within which this view sits but this works using the "InsertionMode.Replace" option. Your (same named) get and post actions return this partial view with whatever model you are using

@model YourModels.ModelView
@{
    Layout = null;
}

@using (Ajax.BeginForm("YourAction", "YourController",
            new AjaxOptions
            {
                HttpMethod = "POST",
                InsertionMode = InsertionMode.Replace,
                UpdateTargetId = "divYourPartial"
            }))
{
    @Html.AntiForgeryToken()
    @Html.HiddenFor(m => m.YourId)

    @Html.ValidationSummary(false, "", new { @class = "text-danger" })

    <div>
        @Model.SomeInfo
    </div>

    <div class="form-group mt-1">
        @Html.LabelFor(model => model.Notes, htmlAttributes: new { @class = "control-label" })
        @Html.TextAreaFor(model => model.Notes, new { @class = "form-control", @rows = 6, @cols = 80 })
        @Html.ValidationMessageFor(model => model.Notes, "", new { @class = "text-danger" })
    </div>
    <input type="submit" value="Save" class="btn btn-default btn-primary" title="Save changes to these notes" />
}


回答2:

You can have multiple forms on a page. For example, if you have a table with rows where you want to delete any row, you an create a form in a table cell on that row. In this way, the delete takes only one id to the POST action for delete.

I suggest you split your partial views up into their own forms, each one acting independently. The only issue with this is if an update in one form requires the other to be redisplayed. Your outer view can handle that better than partial views trying to communicate. It is a simple matter to return the results of two views in a JSON object from an action and assigned the HTML to each of the corresponding DIV that has the partial view

You have two choices of initially populating your partial. If you have something like this in your main view, on first load, your details HTML is rendered by the RAZOR engine into the div. This comes from the HTTP GET action (assuming you have separate ones for GET and POST)

<div id="divYourPartial">
    @Html.Partial("_Details", Model)
</div>

The code I suggested in the first answer will then repopulate this DIV when a user saves (POSTS) their changes. There is nothing more for you to do.

You can also populate the div on first load using JavaScript, as in my first answer

<div id="divYourPartial">
</div>

You will need a scripts section that performs the load initially - unless you wait for a user to click some element and load the data by ID. If you want to capture events from descendants that are dynamically loaded, put an event handler on a fixed, outer element otherwise you won't catch them.

        @section Scripts
        {
            <script type="text/javascript">

function LoadData(){
$.ajax({
    url: '/YourController/YourAction/' + YourId,
    type: "get",
    success: function (result) {
    $("#divYourPartial").html(result);
    }
});
}


        $(function () {
// first time page load
LoadData()

    $("#divOuter").on("dblclick", function (event) {
    // when user double clicks an item, show it for editing
    // on an outer div awaiting an event to percolate up from a descendant, the target is not $(this)
    var target = $(event.target);

    // Your ajax here to load the div
        });
    });
    </script>