ASP Web API - Kendo Grid and Model State - asp.net

I'm using Kendo Grid and ModelState.IsValid condition on my Web API post method. When I create a new record on the grid (in fact I'm using the popup option of the grid to create a new record), it's sending the Id of my class as null, then when it comes to my controller the ModelState is always invalid because it expects the Id of my class to be 0. I solved it by changing the value of the Id on the parameterMap of the datasource when the operation is 'create' (see code below), but I really don't know if it's the best solution as it seems to me like a poor way. Is there another option to solve this issue? Thanks.
View:
$(document).ready(function () {
var dataSource = new kendo.data.DataSource({
transport: {
read: {
url: "/api/products",
dataType: "json"
},
update: {
url: function (data) {
return "/api/products/" + data.id;
},
dataType: "json",
type: "PUT"
},
destroy: {
url: function (data) {
return "/api/products/" + data.id;
},
dataType: "json",
type: "DELETE"
},
create: {
url: "/api/products",
dataType: "json",
type: "POST"
},
parameterMap: function (options, operation) {
// THIS IS MY FIX FOR NOW
if (operation === "create") {
options.id = 0;
}
return kendo.stringify(options);
},
type: "json"
},
batch: false,
pageSize: 20,
schema: {
model: {
id: "id",
fields: {
id: { editable: false, nullable: true },
name: { validation: { required: true } },
description: { validation: { required: true } }
}
}
}
});
$("#grid").kendoGrid({
dataSource: dataSource,
pageable: true,
height: 550,
toolbar: ["create"],
columns: [
{ field: "name", title: "Name" },
{ field: "description", title: "Description" },
{ command: ["edit", "destroy"], title: " ", width: "250px"
}],
editable: "popup"
});
});
Controller (I put only the post method as it was the one that got the issue):
[HttpPost]
public IHttpActionResult CreateProduct(Product product)
{
if (!ModelState.IsValid)
return BadRequest();
_productRepository.CreateProduct(product);
_productRepository.SaveProduct();
return Ok(product);
}
Model:
public class Product
{
public int Id { get; set; }
[Required]
[StringLength(100)]
public string Name { get; set; }
[Required]
[StringLength(255)]
public string Description { get; set; }
}
Repository:
public void CreateProduct(Product product)
{
_context.Products.Add(product);
}
public void SaveProduct()
{
_context.SaveChanges();
}

It might be that id field is nullable: true.
Could you remove it and add type: "number"?
fields: {
id: { editable: false, type: "number" },
name: { validation: { required: true } },
description: { validation: { required: true } }
}

Related

Asp Core net Kendo ui Cannot pass decimal value to model

I'm using kendo ui to create a grid on my project. My problem is that i cannot pass a decimal value to my c# class model.
My class:
public class BlocCoefficientSettings
{
public int BlocCoefficientKey { get; set; }
public string BlocName { get; set; }
public string Category { get; set; }
public string MinMaxFloor { get; set; }
public int Rooms { get; set; }
public decimal CoefficientValue { get; set; }
public int GroupNumber { get; set; }
}
And this is my code that renders the grid
#section Scripts{
<script>
function grid_init() {
var dataSearch = {
classifierSearchKey: document.getElementById('classifierSearchKey').value
}
if (!dataSearch.classifierSearchKey == "") {
var dataSource = new kendo.data.DataSource({
transport: {
read: {
url: "/BlocCoefficientsSettings?handler=Json",
dataType: "json",
data: dataSearch
},
update: {
url: "/Common/UpdateBlocCoefficientsSettings",
type: "POST",
dataType: "json"
}
},
batch: true,
sort: [{ field: "groupNumber", dir: "asc" }, { field: "rooms", dir: "asc" }],
schema: {
data: "results",
total: "total",
model: {
id: "blocCoefficientKey",
fields: {
blocName: { editable: false },
rooms: { editable: false, type: "number" },
minMaxFloor: { editable: false },
coefficientValue: { editable: true, type: "number", nullable: true }
}
},
},
page: 1,
serverPaging: false,
group: { field: "category" }
});
$("#grid").empty();
$("#grid").kendoGrid({
dataSource: dataSource,
editable: true,
height: 700,
sortable: true,
groupable: false,
toolbar: [{ name: "save", text: "Сохранить" }],
columns: [
{ field: "blocName", title: "Блок", width: "200px" },
{ field: "minMaxFloor", title: "Этаж", width: "70px" },
{ field: "rooms", title: "Комнат", width: "50px" },
{ field: "coefficientValue", title: "Коэффициент этажности", width: "50px" },
{ field: "category", hidden: true, groupHeaderTemplate: "Категория недвижимости: #= value #" }
]
});
}
else {
alert("Выберите застройку!");
}
}
$("#btnSearch").click(function () {
grid_init();
});
</script>
All works fine when put a whole number in the coefficientValue field. The whole number is passed to my model. But when i put a decimal number to my model is passed 0(In my example the value should be 1.5 for models[1])
How can i pass a decimal number?
I'm not sure how you are prompting for a number here, but be careful with culture settings. JSON does not support comma decimal separation, only point. Thus, you the JSON being posted has to show the value as 1.5, not 1,5 or it isn't going to parse correctly on server side.

ASP Web API Kendo UI Grid value cannot be null: entity

I'm using the Grid component from Kendo UI on my Web API application. My records are being loaded correctly and even the delete is working, but unfortunately the Post and Update are not working. I got the error message on the response of the request: message: "An error has occurred.", exceptionMessage: "Value cannot be null. ↵Parameter name: entity",…}
Bellow part of my view and controller. What am I missing? Trying lots of things. *The field names are lower case because I'm using CamelCase.
$(document).ready(function () {
var dataSource = new kendo.data.DataSource({
transport: {
read: {
url: "/api/products",
dataType: "json"
},
update: {
url: function (data) {
return "/api/products/" + data.id;
},
dataType: "json",
type: "PUT"
},
destroy: {
url: function (data) {
return "/api/products/" + data.id;
},
dataType: "json",
type: "DELETE"
},
create: {
url: "/api/products",
dataType: "json",
type: "POST"
},
parameterMap: function (options, operation) {
if (operation !== "read" && options.models) {
return { models: kendo.stringify(options.models) };
}
}
},
batch: false,
pageSize: 20,
schema: {
model: {
id: "id",
fields: {
id: { editable: false, nullable: true },
name: { validation: { required: true } },
description: { validation: { required: true } }
}
}
}
});
$("#grid").kendoGrid({
dataSource: dataSource,
pageable: true,
height: 550,
toolbar: ["create"],
columns: [
{ field: "name", title: "Name" },
{ field: "description", title: "Description" },
{ command: ["edit", "destroy"], title: " ", width: "250px"
}],
editable: "popup"
});
And this is part of my controller and repository:
public IHttpActionResult GetProducts()
{
var products = _productRepository.GetProducts();
return Ok(products);
}
[HttpPost]
public IHttpActionResult CreateProduct(Product product)
{
_productRepository.CreateProduct(product);
_productRepository.SaveProduct();
return Ok();
}
[HttpPut]
public IHttpActionResult UpdateProduct(int id, Product product)
{
var productInDb = _productRepository.GetProduct(id);
if (productInDb == null)
return NotFound();
_productRepository.UpdateProduct(product);
_productRepository.SaveProduct();
return Ok();
}
public Product GetProduct(int id)
{
return _context.Products.SingleOrDefault(p => p.Id == id);
}
public void CreateProduct(Product product)
{
_context.Products.Add(product);
}
public void UpdateProduct(Product product)
{
_context.Entry(product).State = EntityState.Modified;
}
public void SaveProduct()
{
_context.SaveChanges();
}
UPDATE
I think parameterMap function was wrong in the first place because when Posting or Updating it was never entering in the condition, so here it goes the parameterMap updated. The POST worked after that change (it's not just closing the window and repopulating the grid, I don't know why). But unfortunately the Update is still not working as I receive the following error inside controller "Attaching an entity of type 'Models.Product' failed because another entity of the same type already has the same primary key value. ". What am I missing in this situation?
parameterMap: function (options) {
return kendo.stringify(options);
},
type: "json"
I managed to solve it with the help in the comments (basically the main problem was the parameterMap, and then a fill tweeks were needed as well as passing back the entity in the return of the controller methods). I'm putting the updated code below (only the part that was changed).
View:
$(document).ready(function () {
var dataSource = new kendo.data.DataSource({
transport: {
read: {
url: "/api/products",
dataType: "json"
},
update: {
url: function (data) {
return "/api/products/" + data.id;
},
dataType: "json",
type: "PUT"
},
destroy: {
url: function (data) {
return "/api/products/" + data.id;
},
dataType: "json",
type: "DELETE"
},
create: {
url: "/api/products",
dataType: "json",
type: "POST"
},
parameterMap: function (options) {
return kendo.stringify(options);
},
type: "json"
},
batch: false,
pageSize: 20,
schema: {
model: {
id: "id",
fields: {
id: { editable: false, nullable: true },
name: { validation: { required: true } },
description: { validation: { required: true } }
}
}
}
});
$("#grid").kendoGrid({
dataSource: dataSource,
pageable: true,
height: 550,
toolbar: ["create"],
columns: [
{ field: "name", title: "Name" },
{ field: "description", title: "Description" },
{ command: ["edit", "destroy"], title: " ", width: "250px"
}],
editable: "popup"
});
Controller:
public IHttpActionResult GetProducts()
{
var products = _productRepository.GetProducts();
return Ok(products);
}
[HttpPost]
public IHttpActionResult CreateProduct(Product product)
{
_productRepository.CreateProduct(product);
_productRepository.SaveProduct();
return Ok(product);
}
[HttpPut]
public IHttpActionResult UpdateProduct(int id, Product product)
{
_productRepository.UpdateProduct(product);
_productRepository.SaveProduct();
return Ok(product);
}

ASP.NET WebAPI KendoUI, can't update, create, delete data, 405 Method not allowed

I'm using ASP.NET WebApi in conjunction with KendoUI. Json is successfully displayed in the grid, so GET works. But I can't UPDATE, CREATE or DELETE data. Any idea what I am missing? Even in the Telerik forum I couldn't find anything that points me into the right direction. And I also looked through their examples. Must I somehow pass values to PUT, POST, and DELETE?
<script type="text/javascript">
var remoteDataSource = new kendo.data.DataSource({
transport: {
read: { url: '/api/NorthwindProductWebApi', dataType: "json", type: "GET" },
update: { url: '/api/NorthwindProductWebApi', dataType: "json", type: "PUT"},
create: { url: '/api/NorthwindProductWebApi', dataType: "json", type: "POST" },
destroy: { url: '/api/NorthwindProductWebApi', dataType: "json", type: "DELETE" },
parameterMap: function (options, operation) {
if (operation !== "read" && options.models) {
return { models: kendo.stringify(options.models) }
;
}
}
},
pageSize: 20,
batch: true,
schema: {
model: {
id: "ProductID",
fields: {
ProductID: { type: "number" },
ProductName: { type: "string" },
SupplierID: { type: "number" },
CategoryID: { type: "number" },
QuantityPerUnit: { type: "string" },
UnitPrice: { type: "string" },
UnitsInStock: { type: "number" },
UnitsOnOrder: { type: "number" },
ReorderLevel: { type: "number" },
Discontinued: { type: "string" }
}
}
}
});
$('#grid').kendoGrid({
dataSource: remoteDataSource,
heigth: 100,
groupable: true,
sortable: true,
pageable: {
refresh: true,
pageSizes: true,
buttonCount: 5
},
toolbar: ["create"],
columns: [{
command: ["edit", "destroy"], title: " ", width: "200px"
},
{
field: "ProductID",
title: "ProductID",
width: 200
}, {
field: "ProductName",
title: "ProductName",
width: 250
}, {
field: "SupplierID",
title: "SupplierID",
width: 200
}, {
field: "CategoryID",
title: "CategoryID",
width: 200
}, {
field: "QuantityPerUnit",
title: "QuantityPerUnit",
width: 200
}, {
field: "UnitPrice",
title: "UnitPrice",
width: 250
}, {
field: "UnitsInStock",
title: "UnitsInStock",
width: 200
}, {
field: "UnitsOnOrder",
title: "UnitsOnOrder",
width: 250
}, {
field: "ReorderLevel",
title: "ReorderLevel",
width: 200
}, {
field: "Discontinued",
title: "Discontinued",
width: 250
}],
editable: "popup",
save: function(){
this.refresh();
},
scrollable: true,
filterable: {
extra: false,
operators: {
string: {
startswith: "beginnt mit",
eq: "exakt",
neq: "enthält nicht"
},
number: {
//???contains: "contains",
eq: "exakt",
//???doesnotcontain: "Is not equal to"
}
},
}
});
</script>
Update:
Chrome gives me a 405 Method not allowed method on PUT and a 500 (Internal Server Error) on POST. Here is a snippet from the scaffold WebApi Controller and the chrome output, which is the same for both errors:
POST http://localhost:123/api/NorthwindProductWebApi 500 (Internal Server Error) jquery-1.10.2.js:8720
send jquery-1.10.2.js:8720
jQuery.extend.ajax jquery-1.10.2.js:8150
ct.extend.create kendo.all.min.js:11
(anonymous function) kendo.all.min.js:11
jQuery.extend.Deferred jquery-1.10.2.js:3274
lt.extend._promise kendo.all.min.js:11
lt.extend._send kendo.all.min.js:11
lt.extend.sync kendo.all.min.js:11
j.extend.saveRow kendo.all.min.js:23
(anonymous function) kendo.all.min.js:22
jQuery.event.dispatch jquery-1.10.2.js:5109
elemData.handle jquery-1.10.2.js:4780
// POST api/NorthwindProductWebApi
[ResponseType(typeof(Product))]
public IHttpActionResult PostProduct(Product product)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Products.Add(product);
db.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = product.ProductID }, product);
}
Attempt to change the Url in the DataSource:
create: {
url: function(options) {
return '/api/NorthwindProductWebApi/PostProduct' + options.ProductID
},
type: "POST",
dataType: "json"
Normally you decorate your controller with
[HttpGet]
[HttpPost]
If you decided to use full set of REST request methods ,Get,Put,Delete,Post then you must handle them by decorating on the controller method to tell the compiler which method will be processing which type of request.
[HttpGet]
public ActionResult HelloWorld()
{}
[HttpPost]
public ActionResult HelloWorld(Model model)
{}
[HttpPut]
public ActionResult HelloWorld(Model model)
{}
[HttpDelete]
public ActionResult HelloWorld(int Id)
{}
For more information Link: PUT vs POST in REST
Ok, so, your controller is named NorthwindProductWebApiController and your POST method in the controller is named PostProduct. The solution is one of two choices. You can either rename PostProduct to Post - removing the Product part in the name, or change the url in your Kendo DataSource create definition to api/NorthwindProductWebApi/PostProduct.
Remember that ASP.NET WebApi is based on convention. You do not have to fully name your controller methods. Typically, the HTTP verb is sufficient. It knows which method to call based on the verb and number of arguments. If you do however fully name the method, you must fully name it in the URL.

After edit of Grid cell, the value is overlapped with a zero

When I edit a cell in my grid, a zero ("0") is placed in the cell, overlapping the cell value. This zero does not show when the grid loads, and it does not save to the database when the update happens. If I navigate away and come back, the zero is gone. It only happens if I edit the cell; if I only click in the cell and initiate the inline editing, no zero appears. This happens in every cell, even the dates.
My page is an SPA.
This is the code that builds the grid:
function fnLoadStorageVaults(storageid) {
var ds = new kendo.data.DataSource({
transport: {
read: {
url: URL_GETVAULTS,
dataType: "json",
type: "GET",
data: { StorageID: storageid }
},
update: { dataType: "json", url: URL_UPDATEVAULTS, type: "POST" },
destroy: { url: URL_DELETEVAULT, type: "POST" },
create: { url: URL_INSERTVAULT, type: "POST" },
parameterMap: function (data, type) {
return kendo.stringify(data);
}
},
autoSync: true,
schema: {
model: {
id: "StorageVaultID",
fields: {
VaultNumber: { type: "string", editable: true },
Section: { type: "string", editable: true },
Row: { type: "string", editable: true },
DateFrom: { type: "date", editable: true },
DateTo: { type: "date", editable: true },
WarehouseID: { type: "number", editable: true }
}
}
}
});
$("#VaultGrid").kendoGrid({
dataSource: ds
, sortable: true
, editable: true
, navigable: true
, columns: [
{ field: "WarehouseID", title: "Warehouse", width: "60px" }
,{ field: "VaultNumber", title: "Vault Nbr.", width: "60px" }
, { field: "Section", title: "Section" }
, { field: "Row", title: "Row" }
, { field: "DateFrom", title: "Date In" }
, { field: "DateTo", title: "Date Out" }
]
});
}
My apologies, the update was not working after all. The zero was the response from the server. Still curious behavior though.

Getting jQuery Validation Plugin to work with WordPress form

I am running into problems while making a front-end user registration form as part of a custom WordPress theme, and I need to be able to check if an e-mail exists with an ajax request before allowing the user to register.
Here is the JS:
I am using the jQuery Validate plugin, and I am using addMethod to insert into the .validate call. Here is the code:
function chk_email(value){
var response;
$.ajax({
async: false,
url: ajaxurl,
type: 'POST',
data: {action: 'chk_email', email: value},
dataType: "text",
success: function(msg) {
if (msg>0) {
response = true;
} else{
response = false;
}
}
})
console.log(response);
return response;
}
$.validator.addMethod('chk_email', chk_email, "This email address has already been registered");
$("#adduser").validate({
// debug: true,
rules: {
user_login: {
required: true,
minlength: 3,
nowhitespace: true,
alphanumeric: true
},
first_name: {
required: true,
},
last_name: {
required: true,
},
user_email: {
required: true,
email: true,
nowhitespace: true,
// remote: { url: ajaxurl, type: 'post' }
chk_email: true
},
tel: {
required: true,
phoneUS: true
},
street_address: {
required: true
},
locality: {
required: true
},
region: {
required: true
},
postal_code: {
required: true
},
},
messages: {
user_login: {
required: "Required",
user_login: "A username needs to be atleast 3 charachters long."
},
user_email: {
required: "We need your email address to contact you",
user_email: "Your email address must be in the format of name#domain.com",
nowhitespace: "yeah"
},
},
errorElement: 'span',
errorClass: 'help-inline',
errorPlacement: function(error, element) {
error.insertAfter(element);
},
highlight: function(element) {
var parent = $(element).parents('.control-group');
$(element).addClass('error');
$(parent).addClass('error');
},
unhighlight: function(element) {
var parent = $(element).parents('.control-group');
$(element).removeClass('error');
$(parent).removeClass('error');
}
// debug: true
});
And here is the PHP I am using within the functions.php file:
add_action('wp_ajax_nopriv_chk_email', 'chk_email');
function chk_email(){
if (email_exists($_POST['email']) ){
// return TRUE;
echo 'true';
} else {
// return FALSE;
echo 'false';
}
}
I am not quite sure what I am doing wrong here. I would appreciate any thoughts.
http://docs.jquery.com/Plugins/Validation/Methods/remote
Check out the overview and the examples.
So instead of chk_email(), you would add to the remote option:
remote: {
url: ajaxurl,
type: "post"
}

Resources