如何在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>© @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 支持的参数。
以前的答案帮助我正确地解决了这个问题。如果 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>
希望这个问题的解决也能帮助到其他人。我还要感谢帮助我找到这个答案的人。
使用 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>© @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 支持的参数。
以前的答案帮助我正确地解决了这个问题。如果 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>
希望这个问题的解决也能帮助到其他人。我还要感谢帮助我找到这个答案的人。