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

时间:2014-12-03 09:28:13

标签: javascript jquery asp.net-mvc razor

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

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

视图模型

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 视图中的数据提交到服务器,然后刷新局部视图,
如何做到这一点?

4 个答案:

答案 0 :(得分:12)

你要求的是

您要求的功能是AJAX。 AJAX请求是“异步”,在最基本的级别意味着可以启动和响应HTTP请求,而无需刷新页面。

正如有人写评论你的问题,jQuery可以使用,并提供了一个很好的方式来做AJAX请求,但如果你只是为了一个AJAX请求包含整个jQuery库,很多人可能会哭。

的JavaScript

所以在JavaScript中这是一个更复杂的 liiiiiittle ,有一些例子here。我不打算告诉你如何在JavaScript中完成它只是因为我现在没有很多时间,但我可能会在稍后更新答案。如果可以的话,我可能会建议你这样做。

的jQuery

在jQuery中这很容易。 AJAX请求的文档是here

基本上您需要做的是向服务器发出请求,以便它可以更新您的部分视图数据,然后返回新的部分视图,以便用您替换当前的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()覆盖的按钮。

答案 1 :(得分:4)

实际上,当您查看浏览器端的情况时,没有类似部分视图父视图的声明。浏览器只能看到一个html文档。 Html.Partial,尤其是 PartialViews 仅在服务器端有意义,他们确实可以为您提供帮助。它使您能够在多个页面和一个地方重用部分视图以修改所有部分视图。当 Razor 呈现此cshtml文件时,开始从上到下呈现,当遇到@Html.Partial("something")时,它会执行返回 Html的方法编码 字符串 并显示返回的字符串。毕竟,Razor会返回一个完整的html页面。因此,当你从html中 提交 数据时,唯一重要的是哪个输入类型具有哪个名称属性。

解决方案1:没有Ajax 根据您的主视图,您的get方法就是这样。

// 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: 使用Jquery的Ajax 已经给出了这个解决方案。你有两个选择;从服务器返回部分视图并将旧内容替换为从服务器返回的内容或返回json并通过dom操作更改内容。两种方法都有缺点。 Sippy的答案是完美的,我想要添加的是jquery ajax方法,加载方法对于返回静态视图更合理。

$("#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更改视图更改时。(双向数据绑定) 包括角度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时通过双向数据绑定完成的。

答案 2 :(得分:1)

是的,主视图是纯HTML或由多个局部视图+主视图组成,当它在浏览器中呈现时,它将被视为一个单独的HTML而不是部分。通过说,您将拥有访问权限对DOM来说,它是在局部视图还是主视图中。因此,根据我的个人经验,如果您决定使用Jquery post方法构建自己的提交按钮,那么放置提交按钮的位置并不重要。模型/视图模型来帮助它。

但是在某些情况下,您会在部分视图的每个级别使用

获得部分更新按钮
@using (Ajax.BeginForm

答案 3 :(得分:0)

Solution 1:

You can simply wrap inputs 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 inputs 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*/);
}