从父视图提交部分视图数据

8

如何从父视图提交部分视图数据。

我是MVC的新手,已创建一个包含编辑控件(文本框等)的部分视图 _CurrentData,并在主视图中添加了“提交”按钮:

<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; }
}

视图

<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>

现在,当点击'btnSubmit'按钮时,我想要将_CurrentData视图中的数据提交到服务器并刷新局部视图,
如何完成此操作?


2
希望我理解了你的问题。你尝试过使用ajax post方法吗?你可以构建一个模型并将其发送到控制器。http://api.jquery.com/jquery.post/ - threeleggedrabbit
1
也许这可以帮到你:如何从局部视图发送数据 - Martin
1
这是正确的做法。 - Inspector Squirrel
@Sippy,Martin:这将导致整个页面重新加载。 - Nitin Sawant
@Hsakarp, 将提交代码写在局部视图之外是一种好的实践吗?我的意思是,控件位于局部视图中,而我们将编写 HTTP POST 代码放在主视图中。 - Nitin Sawant
抱歉,我没有看到您想要刷新部分内容,我上班后会发布答案。 - Inspector Squirrel
4个回答

13

你所需要的

你所需要的功能叫做 AJAX。AJAX 请求是“异步”的,这意味着 HTTP 请求可以在不刷新页面的情况下发起和响应。

正如有人在评论中写道,jQuery 可以用于进行 AJAX 请求,并提供了一种很好的方式,但是对于只为了 AJAX 请求而包含整个 jQuery 库的做法可能会让很多人感到惋惜。

JavaScript

因此,在 JavaScript 中,这就有点复杂了,这里有一些示例(链接)。我现在没有太多时间,不会向您展示如何在 JavaScript 中实现它,但我可能会在以后更新答案。如果可能的话,我建议你研究一下这种方法。

jQuery

在 jQuery 中,这很容易。 AJAX 请求的文档在这里

基本上,你需要做的就是向服务器发送请求,以便更新你的部分视图数据,然后返回新的部分视图,来替换当前 HTML。代码看起来会像这样:

$.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); }
});

假设你的控制器方法类似这样:

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

这基本上就是如何联系控制器。为了从您的网页调用该ajax,您需要在表单内部的部分视图中有一个按钮,并且可以使用event.preventDefault()覆盖它。


或者,您可以简单地使用$.post('@Url.Action("_CurrentData", "yourControllerName")', $('#partialViewForm').serialize(), function(response) { $('#partialViewDiv').html(response); }); - user3559349

4
实际上,在浏览器端看情况时,不存在“部分视图”或“父视图”的说法。浏览器只看到一个HTML文档。尤其是PartialViews,它们只在服务器端有意义,并且确实帮助你。它使您能够在多个页面上重复使用部分视图,并在一个地方修改所有内容。当Razor渲染此cshtml文件时,从上到下开始渲染,遇到@Html.Partial("something")时,执行返回HTML编码字符串的方法并显示返回的字符串。最后,Razor返回一个完整的HTML页面。因此,当您从HTML提交数据时,唯一重要的是哪个输入类型具有哪个名称属性。
解决方案1:无需Ajax 根据您的主视图,您的获取方法如下。
// 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);
        }

我假设您已经有了表单标签,只需将按钮类型更改为提交。
@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>
}

并将您的帖子操作添加到控制器中,这是完全没有问题的。
[HttpPost]
        public ActionResult MainView(ItemDetails submittedItem)
        {
            //do stuff with model like persistence
            var pvm = new ProductionViewModel();
            pvm.CurrentItemDetails = submittedItem;
            return View(pvm);
        }

这将返回带有新项目的相同视图。

解决方案2:Ajax使用jQuery 此解决方案已经给出。您将有两个选项:从服务器返回部分视图并用返回的内容替换旧内容,或者返回JSON并通过DOM操作更改内容。这两种方法都有缺点。 Sippy的答案很完美,我想要补充的是,与其使用jQuery Ajax方法,使用load方法更合理,以返回静态视图。

$("#partialViewDiv").load('@Url.Content("~/Controller/_CurrentData")');
解决方案3:使用双向数据绑定或类似Angular的框架 当您想要刷新部分视图时,您可能需要一些额外的信息,例如新创建的项的ID。这就是为什么您需要与服务器通信,因为您已经在运行中拥有了新的输入值。也许您想在同一页的某个位置显示所有保存的项目,并在从服务器返回创建的项目后手动添加它。因此,如果您的页面需要这种情况,最好使用像Angular这样的框架。这样,您可以轻松刷新部分视图并进行许多操作。我的演示仅用于演示,您可以遵循许多设计原则。

这是主视图

<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>

局部视图

<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>

文本框通过ng-model属性绑定到item.name,所以我们不需要担心刷新视图。当item.name发生变化时,视图也会随之改变。(双向数据绑定) 包含angular js和自定义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);
        });
    };
});

还有服务器端代码

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

            return Json(SubmittedItem);
        }

使用Angular时,您只需要处理对象,所有视图操作都通过双向数据绑定完成。


1

是的,无论主视图是纯HTML还是由多个部分视图+主视图组成,当它在浏览器中呈现时,它将被视为单个HTML而不是部分。因此,您将可以访问DOM,无论它是在部分视图还是主视图中。所以,从我的个人经验来看,如果您已经决定使用Jquery post方法通过构建自己的模型/视图模型来帮助它,那么放置提交按钮的位置并不重要。

但是,在某些情况下,您会在每个部分视图的每个级别上使用部分更新按钮。

@using (Ajax.BeginForm

这是对这个问题的简单易懂的答案。 - Venkata K. C. Tata

0

解决方案1:

您可以简单地将主页面中的input元素包装在Ajax form元素中,并在其中调用@Html.Partial("_CurrentData", Model.CurrentItemDetails),一切都会正常工作。

解决方案2:

不使用form标签,而是使用一些JavaScript代码,在单击btnSubmit元素(定义单击事件)后查找目标input元素,然后序列化它们以准备发送到服务器的操作方法。

两种解决方案的共同部分是编写一个Ajax方法,响应更新页面而无需刷新,例如:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接