如何在KendoUI中绑定模型?

How to bind model in Kendo UI?

使用 Kendo UI 和 Angular 创建操作后绑定模型出现问题。

在调试模式下创建请求后,我在 PoController 中成功实现了所需的操作调用,但是控制器必须接受的对象是空的。

在 Fiddler 中,我可以使用正文观看请求“/PO/Create”:

models=%5B%7B%22id%22%3Anull%2C%22po_number%22%3A%221%22%2C%22note%22%3A%22ojklj%22%2C%22valid_start%22%3A%222016-08-09T10%3A06%3A46.703Z%22%2C%22valid_end%22%3A%222016-08-09T10%3A06%3A46.703Z%22%7D%5D

有人可以帮助进行模型绑定吗?可能是 Kendo UI 数据源配置错误?

app.js

var app = angular.module("app", ["kendo.directives"]);

poDataSource.js

'use strict';

app.factory('poDataSource',
    function () {
        return new kendo.data.DataSource({
            transport: {
                type: "odata",
                read: {
                    url: '/PO/GetAll',
                    datatype: 'jsonnp',
                    type: 'get',
                },
                create: {
                    url: "/PO/Create",
                    dataType: "jsonp",
                    type: "post"
                    },
                parameterMap: function (options, operation) {
                        if (operation !== "read" && options.models) {
                            return { models: kendo.stringify(options.models) };
                        }
                    }
                },
                batch: true,
                pageSize: 5,
                schema: {
                    model: {
                        id: "id",
                        fields: {
                            id: { editable: false, nullable: true },
                            po_number: { type: "string" },
                            note: { type: "string" },
                            valid_start: { type: "date" },
                            valid_end: { type: "date" }
                        }
                    }
                }

            });
    });

Index.cshtml

<kendo-grid k-data-source="dataSource"
            k-columns="gridColumns"
            k-editable="'inline'"
            k-toolbar="['create']"
            k-sortable="true"
            k-pageable="true"
            k-resizeable="true">
</kendo-grid>

_Layout.cshtml

<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title - SWE Team Dashboard</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
    <link href="@Url.Content("~/Content/kendo/2016.1.226/kendo.common-material.min.css")" rel="stylesheet" type="text/css" />
    <link href="@Url.Content("~/Content/kendo/2016.1.226/kendo.mobile.all.min.css")" rel="stylesheet" type="text/css" />
    <link href="@Url.Content("~/Content/kendo/2016.1.226/kendo.dataviz.min.css")" rel="stylesheet" type="text/css" />
    <link href="@Url.Content("~/Content/kendo/2016.1.226/kendo.material.min.css")" rel="stylesheet" type="text/css" />
    <link href="@Url.Content("~/Content/kendo/2016.1.226/kendo.dataviz.material.min.css")" rel="stylesheet" type="text/css" />
    <script src="@Url.Content("~/Scripts/kendo/2016.1.226/jquery.min.js")"></script>
    <script src="@Url.Content("~/Scripts/kendo/2016.1.226/angular.min.js")"></script>
    <script src="@Url.Content("~/Scripts/kendo/2016.1.226/jszip.min.js")"></script>
    <script src="@Url.Content("~/Scripts/kendo/2016.1.226/kendo.all.min.js")"></script>
    <script src="~/Content/app/app.js"></script>
    <script src="~/Content/app/services/appService.js"></script>
    <script src="~/Content/app/services/poDataSource.js"></script>
    <script src="~/Content/app/controllers/homeController.js"></script>
</head>
<body ng-app="app" ng-controller="homeController as app">
    <header>
        <div class="content-wrapper">
            <div class="float-left">
                <p class="site-title">@Html.ActionLink("SWE Team Dashboard", "Index", "Home")</p>
            </div>
            <div class="float-right">
                <nav>
                    <ul id="menu">
                        <li>@Html.ActionLink("PO", "Index", "Home")</li>
                        <li>@Html.ActionLink("TMT Tasks", "Tasks", "Home")</li>
                        <li>@Html.ActionLink("Task to PO mapping", "TaskPOReferences", "Home")</li>
                    </ul>
                </nav>
            </div>
        </div>
    </header>
    <div id="body">
        @RenderSection("featured", required: false)
        <section class="content-wrapper main-content clear-fix">
            @RenderBody()
        </section>
    </div>

    <footer>
        <div class="content-wrapper">
            <div class="float-left">
                <p>&copy; @DateTime.Now.Year - My Telerik MVC Application</p>
            </div>
        </div>
    </footer>
</body>
</html>

POController.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Dashy.DB.Model;
using Dashy.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Threading.Tasks;

namespace Dashy.Controllers
{
    public class POController : Controller
    {
        // GET: PO/GetAll
        public async Task<ActionResult> GetAll()
        {
            var allItems = new PODAL().GetAll();

            return Json(allItems, JsonRequestBehavior.AllowGet);
        }

        public ActionResult Create()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Create(PO po)
        {
            try
            {
                new PODAL().AddPo(po);
                return RedirectToAction("Index");
            }
            catch (Exception exception)
            {
                return View();
            }
        }




        // GET: PO/GetTaskToPoMapping
        public string GetTaskToPoMapping()
        {
            var allItems = new PODAL().GetTaskToPoMapping();
            var jsonResult = JsonConvert.SerializeObject(allItems,
                new JsonSerializerSettings()
                {
                    ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
                });
            return jsonResult;
        }
    }
}

PO.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using NHibernate;

namespace Dashy.DB.Model
{
    public class PO
    {
        public virtual string note { get; set; }
        public virtual int id { get; set; }
        public virtual DateTime valid_start { get; set; }
        public virtual DateTime valid_end { get; set; }
        public virtual string po_number { get; set; }
        public virtual IList<POLine> po_lines { get; set; }

        public virtual void AddPOLine(POLine line)
        {
            line.po = this;
            po_lines.Add(line);
        }
        public PO()
        {
            po_lines = new List<POLine>();
        }
    }
}

batch 设置为 true,这意味着 Kendo UI 数据源将通过以下方式在单个请求中发送所有新项目:

models: [
    { FieldName1: "value 1.1", FieldName2: "value 2.1" },
    { FieldName1: "value 1.2", FieldName2: "value 2.2" }
]

服务器端代码目前似乎不希望这样。

要么更改服务器实现,要么禁用批处理操作。还要注意您的 parameterMap 功能,因为它也直接影响项目的提交方式。

http://docs.telerik.com/kendo-ui/api/javascript/data/datasource#configuration-batch

http://docs.telerik.com/kendo-ui/api/javascript/data/datasource#configuration-transport.parameterMap

解码你的 URI 后看起来如下,

"[{"id":null,"po_number":"1","note":"ojklj",
"valid_start":"2016-08-09T10:06:46.‌​703Z","valid_end":"2016-08-09T10:06:46.703Z"}]"

这里你向服务器发送了一个列表,但是在 POST 创建操作中我可以看到它的 PO ,所以它应该是 List<PO> 或者你的客户端代码需要修改以它应该发送单个对象的方式。

我建议你的是,你也可以在参数中设置一个叫做 DatasourceRequest 的东西,这样你就可以接收所有 kendo 支持的参数。

有关 DatasourceRequest 的更多信息 here and here

以前的答案帮助我正确地解决了这个问题。如果 batch 设置为 true 它 return 的项目列表,这意味着我需要重新实现我的控制器,它可以接收 List<PO>.

但是这里还有另外一个大问题。事实上这个控制器 return 不是 http 响应,而是 return 视图和更好的决定是实现 WEB API。基本上我需要重新实现程序。

这里有一些变化

POController.cs

using Dashy.DB.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using Dashy.Models;
using System.ComponentModel.DataAnnotations;
using FluentNHibernate.Conventions.Inspections;
using System.Web.Mvc;

namespace Dashy.Controllers
{
    public class TestController : ApiController
    {
        private PODAL _podal = new PODAL();

        public IQueryable<PO> GetPOs()
        {
            return _podal.GetAll().AsQueryable();
        }

        public HttpResponseMessage PostPO([Bind(Exclude="id,po_lines")]PO po)
        {
            po.po_lines = new List<POLine>();

            if (ModelState.IsValid)
            {
                _podal.AddPo(po);
                HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, po);
                response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = po.id }));
                return response;
            }
            else
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            }
        }
}

poDataSource.js

'use strict';

app.factory('poDataSource',
    function () {
        return new kendo.data.DataSource({

            transport: {
                    type: "odata",
                    read: {
                        url: '/api/po',
                        type: 'get',
                    },
                    update: {
                        url: '/api/po',
                        dataType: "json",
                        type: "PUT",
                        contentType: "application/json"
                    },
                    create: {
                        url: "/api/po",
                        dataType: "json",
                        type: "POST",
                        contentType: "application/json"
                    },
                    parameterMap: function (options, operation) {
                            if (operation !== "read") {
                                debugger;
                                return JSON.stringify(options);

                        }
                    }
                },
                pageSize: 5,
                schema: {
                    model: {
                        id: "id",
                        fields: {
                            id: { editable: false, nullable: true },
                            po_number: { type: "string" },
                            note: { type: "string" },
                            valid_start: { type: "date" },
                            valid_end: { type: "date" },
                            po_lines : { editable: false, nullable: true}
                        }
                    }


                },
            });
    });

homeController.js

app.controller('homeController', function ($scope, $http, poDataSource, poLinesDataSource) {

    $scope.onChange = function (e) {

        $scope.showPoLines = true;
        var grid = e.sender;
        var selectedItem = grid.dataItem(grid.select());
        var selectedItemId = selectedItem.id;

        $http({
            method: 'get',
            url: 'api/polines/getlines',
            params: { id: selectedItemId }
        })
            .success(function (data) {
                // new push new data to grid dataSource 
                $('#PoLinesGrid').data('kendoGrid').dataSource.data(data);
                var grid2 = $('#PoLinesGrid').data('kendoGrid');
                grid2.dataSource.transport.options.create.url = "/api/polines/PostPO?=" + selectedItemId;

            })
            .error(function (data) {
                console.log(data);
            });

    };
    $scope.dataSource = poDataSource;

    $scope.gridColumns = [
            { field: "id", title: "ID" },
            { field: "po_number", title: "PO nr" },
            { field: "valid_start", title: "Start date" },
            { field: "valid_end", title: "End date" },
            { field: "note", title: "Note" },
            {
                command: [{ template: "<button class='k-button' ng-click=''>PO lines</button>", }],
                title: "PO lines"
            },
            { template: "<input type='text' ng-value='calculateTotal(dataItem)' />", title: "Total" },
            {
                command: [{ template: "<button class='k-button' ng-click='showDetails(dataItem)'>Show details</button>", }],
                title: "Show details"
            },

            { command: ["edit", "destroy"], title: " " }
    ];


    $scope.dataSourceOfLines = poLinesDataSource;

    $scope.gridColumnsOfLines = [
            { field: "id", title: "ID" },
            { field: "total", title: "Total" },
            { field: "note", title: "Note" },
            { command: ["edit", "destroy"], title: " " }
    ];
});

Index.cshtml

<kendo-grid id="#PoGrid" k-data-source="dataSource"
            k-columns="gridColumns"
            k-editable="'inline'"
            k-toolbar="['create']"
            k-sortable="true"
            k-pageable="true"
            k-resizeable="true"
            k-on-change="onChange(kendoEvent)"
            k-selectable="true">
</kendo-grid>
<div ng-show="showPoLines">
    <kendo-grid id="PoLinesGrid" k-data-source="dataSourceOfLines"
                k-columns="gridColumnsOfLines"
                k-editable="'inline'"
                k-toolbar="['create']"
                k-sortable="true"
                k-pageable="true"
                k-resizeable="true"
                @*k-on-change="onChange(kendoEvent)"*@
                k-selectable="true">
    </kendo-grid>
</div>

希望这个问题的解决也能帮助到其他人。我还要感谢帮助我找到这个答案的人。