简体   繁体   中英

Submitting partial view data from parent view

How to submit partial view data from parent view .

I am newbie to MVC,
I have created a partial view _CurrentData which contains editor controls - textbox etc
and added Submit button in the main view:

<div class="row">
    <div class="col-md-12">
        @Html.Partial("_CurrentData", Model.CurrentItemDetails)
    </div>
</div>
<div class="row">
    <div class="col-md-2 col-md-offset-5">
        <div>
            <input type="button" class="btn btn-primary" value="Submit" id="btnSubmit"/>
            &nbsp;&nbsp;
            <input type="button" class="btn btn-primary" value="Cancel" id="btnCancel" />
            <br/><br />
        </div>
    </div>
</div>

ViewModel

public class ProductionViewModel
{
    public ItemDetails CurrentItemDetails { get; set; }
}

public class ItemDetails
{
    public int ID { get; set; }
    public string Name { get; set; }
}

View

<div class="panel panel-default">
    <div class="panel-heading">
        <h3 class="panel-title">Editor</h3>
    </div>
    <div class="panel-body">
        <div class="row form-group">
            <div class="col-sm-4 control-label text-right">
                <strong>Name:</strong>
            </div>
            <div class="col-sm-8 control-label">
                @Html.TextBoxFor(m => m.Name , new { @class = "form-control" })
            </div>
        </div>
    </div>
</div>

now on clicking of 'btnSubmit' I want to submit data from _CurrentData view to the server and then refresh the partial view,
How to accomplish this?

What you're asking for

The functionality you're asking for is AJAX. AJAX requests are 'Asynchronous', which at the most basic level means HTTP requests can be initiated and responded to without the need to refresh the page.

As someone wrote in comment to your question, jQuery can be used and does provide a nice way to do AJAX requests, but a lot of people would probably cry if you included the entire jQuery library just for an AJAX request.

JavaScript

So in JavaScript this is a liiiiiittle bit more complicated, there are some examples here . I'm not going to show you how to do it in JavaScript simply because I don't have a lot of time right now, but I might update the answer later. I would probably advise looking into doing it this way if you can.

jQuery

In jQuery this is easy. The documentation for AJAX requests is here .

Basically what you need to do is make a request to the server so it can update your partial view data and then return the new partial view for you to replace your current HTML with. It would look something like:

$.fn.serializeObject = function () {
    var o = {};
    var a = this.serializeArray();
    $.each(a, function () {
        if (o[this.name]) {
            if (!o[this.name].push) {
                o[this.name] = [o[this.name]];
            }
            o[this.name].push(this.value || '');
        } else {
            o[this.name] = this.value || '';
        }
    });
    return o;
};

$.ajax({
    url: '@Url.Content("~/Controller/_CurrentData")',
    type: 'POST',
    data: {
        //partialViewForm relates to the form element in your partial view
        model: JSON.stringify($('#partialViewForm').serializeObject());
    },
    success: function (response) {
        if (response) {
            //partialViewDiv relates to the div in which your partial view is rendered
            $('#partialViewDiv').html(response);
        }
    },
    error: function (xhr, ajaxOptions, thrownError) { alert(xhr.status); alert(thrownError); }
});

The above would assume you had something like this as your controller method:

[HttpPost]
public ActionResult _CurrentData(ItemDetails model)
{
    //do stuff with model here
    return PartialView("_CurrentData", model);
}

So this is basically how you'd contact the controller. In order to call that ajax from your webpage, you'd need to have a button in your partial view within the form that you can override using event.preventDefault() .

Actually there is no statement like partial view or parent view when you look at the situation in browser side. Browser only sees a html document. Html.Partial especially PartialViews are only meaningful in server side and they are there to help you indeed. It gives you ability to reuse partial views on multiple page and one place to modify all. When Razor rendering this cshtml file ,starts to render from top to bottom and when it encounters @Html.Partial("something") it executes that method which returns Html encoded string and displays the returned string. After all, Razor returns one complete html page. So when you submit data from your html only important thing is which input type has which name attribute.

Solution 1: Without Ajax Your get method is like this according to your main view.

// GET: Item
        public ActionResult MainView()
        {
            var _itemDetail = new ItemDetails { ID = 1, Name = "Item1" }; //you get this item somewhere maybe db
            var pvm = new ProductionViewModel();
            pvm.CurrentItemDetails = _itemDetail;  //add item to viewmodel
            return View(pvm);
        }

i am assuming that you have form tags,, just change your button type to submit

@using(Html.BeginForm()){
<div class="row">

    <div class="col-md-12">

        @Html.Partial("_CurrentData", Model.CurrentItemDetails)

    </div>
</div>
<div class="row">
    <div class="col-md-2 col-md-offset-5">
        <div>
            <input type="submit" class="btn btn-primary" value="Submit" id="btnSubmit" />
            &nbsp;&nbsp;
            <input type="button" class="btn btn-primary" value="Cancel" id="btnCancel" />
            <br /><br />
        </div>
    </div>
</div>
}

And add your post action to controller, this is perfectly fine.

[HttpPost]
        public ActionResult MainView(ItemDetails submittedItem)
        {
            //do stuff with model like persistence
            var pvm = new ProductionViewModel();
            pvm.CurrentItemDetails = submittedItem;
            return View(pvm);
        }

This will return same view with new item

Solution 2: Ajax Using Jquery This solution is already given. You will have two option ; return partial view from server and replace older content with the one returned from server or return json and change the content by dom manipulation. Two approach have downsides. Sippy's answer is perfect what i want to add is instead of jquery ajax method load method is more reasonable for returning static view.

$("#partialViewDiv").load('@Url.Content("~/Controller/_CurrentData")');

Solution 3:Using two way data binding or framework like Angular When you wanna refresh your partial view you may need some extra information that is server generated like id of newly created item. This is why you need to talk to server cause you already have the new input values for partial view on the fly. May be you want to display all saved item in a list in somewhere in the same page and after created item returned from server you have to add it manually. So if your page needs situation like that best way is using frameworks like angular. This way you can refresh your partial view and make a lot things with no effort. My Demo just for demonstration you can follow many design principles.

This is main view

<div ng-app="ItemApp" ng-controller="ItemController">
    <form name="newTopicForm" data-ng-submit="save()">
        <div class="row">
            <div class="col-md-12">
                @Html.Partial("_CurrentData", Model.CurrentItemDetails)
            </div>
        </div>
        <div class="row">
            <div class="col-md-2 col-md-offset-5">
                <div>
                    <input type="submit" class="btn btn-primary" value="Submit" id="btnSubmit" />
                    &nbsp;&nbsp;
                    <input type="button" class="btn btn-primary" value="Cancel" id="btnCancel" />
                    <br /><br />
                </div>
            </div>
        </div>
    </form>
</div>

Partial view

<div class="panel panel-default">
    <div class="panel-heading">
        <h3 class="panel-title">Editor</h3>
    </div>
    <div class="panel-body">
        <div class="row form-group">
            <div class="col-sm-4 control-label text-right">
                <strong>Name:</strong>
            </div>
            <div class="col-sm-8 control-label">
    @Html.TextBoxFor(m => m.Name, new { @class = "formcontrol",data_ng_model="item.name",data_ng_init="item.name="+"'"+@Model.Name+"'"})
            </div>
        </div>
    </div>
</div>

Textbox is binded to item.name with ng-model attribute so we no need to worry about refreshing view. When item.name changes view changes too. (two way data binding) Include angular js and this is custom js

var myApp = angular.module('ItemApp', []);
myApp.controller('ItemController', function ($scope, $http,$q) {
    $scope.itemList = {};
    $scope.save = function () {
        $http.post("mainview", $scope.item).
        then(function (result) {

         $scope.item.name = result.data.Name; //update from server
                                              //it is enoguh to refresh 
                                              //your partial view data
         itemList.splice(0, 0, result.data);//add list may be you need to
                                               //display in the view
        },
        function () {
            console.log(error);
        });
    };
});

And server side code

[HttpPost]
        public ActionResult MainView(ItemDetails SubmittedItem)
        {
            //do stuff with model like persistence
            SubmittedItem.ID = 1;

            return Json(SubmittedItem);
        }

You just need to deal with object all view operations are done by two way data bindig when using angular.

Yes , Either the main view is a plain HTML or comprised of multiple partial view + main view , when it renders in browser ,It will be consider as one single HTML not the parts .by saying that, you will have the access to the DOM's either it is in the partial view or Main View.So, from my personal experience it doesn't matter where we place the submit button if you have decided using the Jquery post method by constructing your own model/view model to help it.

but yes there are some situations you will be having partial update buttons at each level of the partial view by using

@using (Ajax.BeginForm

Solution 1 :

You can simply wrap input s in main page inside an Ajax form element and also call the @Html.Partial("_CurrentData", Model.CurrentItemDetails) inside it and everything will work fine.

Solution 2 :

Without using form tag with some JavaScript code to find target input s just after clicking on btnSubmit element ( define click event ) then serialize them to prepare for sending to server's action method.

Common part of both Solutions is writing an ajax method which responds to update the page without refresh like :

public JsonResult GetResponse(ItemDetails model) {            
    return Json(/*data*/, /*behavior*/);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM