Stanislav Machel Stanislav Machel - 3 months ago 13
AngularJS Question

How to bind model in Kendo UI?

I have problems with binding model after create action using Kendo UI with Angular.

After create request in debug mode I successfully acheved needed action call in PoController, but object which controller must accept is empty.

In Fiddler I can watch request '/PO/Create' with body:


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


Can somebody help with model binding? May be Kendo UI datasource is wrong configured?

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

Answer

Previous answers helps me get correct desicion of this issue. If batch is set as true it returns list of items, it means that I need re-implement my controller that it can recive List<PO>.

But here is also other big problem. In fact this controller return not http response, but return view and better decision is implement WEB API. Bassicaly I needed to re-implement programm.

Here is some changes

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>

I hope that solving of this problem can help also other people. Also I thank people who help me find this answer.

Comments