Remote validation for kendowindow - asp.net-mvc

I implement remote validation. It works for usual fields correctly, but if field is situated in kendowindow jquery validation does not work.
How can I solve this problem?

This can be achieved using Kendo UI validator as demonstrated below:
Model with "Remote" annotation attribute:
public class ProductViewModel
{
[Editable(false)]
public int ProductID { get; set; }
[Required]
[Remote("UniqueName", "Home", ErrorMessage = "The entered name already exists.")]
public string ProductName { get; set; }
}
Controller with "UniqueName" Action:
public ActionResult UniqueName(string productName)
{
var context = new NorthwindEntities();
return Json(!context.Products.Any(p => p.ProductName == productName), JsonRequestBehavior.AllowGet);
}
Script to add custom validation rule to the Kendo UI validation rules for the "Remote" validation attribute (can be placed anywhere on the page before Grid initialization code):
<script>
(function ($, kendo) {
$.extend(true, kendo.ui.validator, {
rules: {
//define custom validation rule to match remote validation:
mvcremotevalidation: function (input) {
if (input.is("[data-val-remote]") && input.val() != "") {
var remoteURL = input.attr("data-val-remote-url");
var valid;
$.ajax({
async: false,
url: remoteURL,
type: "GET",
dataType: "json",
data: validationData(input, this.element),
success: function (result) {
valid = result;
},
error: function () {
valid = false;
}
});
return valid;
}
return true;
}
},
messages: {
mvcremotevalidation: function (input) {
return input.attr("data-val-remote");
}
}
});
function validationData(input, context) {
var fields = input.attr("data-val-remote-additionalFields").split(",");
var name = input.prop("name");
var prefix = name.substr(0, name.lastIndexOf(".") + 1);
var fieldName;
var data = {};
for (var i = 0; i < fields.length; i++) {
fieldName = fields[i].replace("*.", prefix);
data[fieldName] = $("[name='" + fieldName + "']", context).val();
}
return data;
}
})(jQuery, kendo);
</script>
Grid initialization code:
#(Html.Kendo().Grid<KendoUIMVC5.Models.ProductViewModel>()
.Name("grid")
.Columns(columns =>
{
columns.Command(comm =>
{
comm.Edit();
});
columns.Bound(p => p.ProductID);
columns.Bound(p => p.ProductName);
})
.Pageable()
.Sortable()
.Filterable()
.DataSource(dataSource => dataSource
.Ajax()
.Model(model =>
{
model.Id(p => p.ProductID);
})
.Read(read => read.Action("Read", "Home"))
.Update(update => update.Action("Update", "Home"))
)
)

Related

KendoValidation with Remote validation

This is almost killing me. I've never wasted so much time on an issue.
I've got a field that needs to be validated with a call to a REST API since it needs to check the presence of some data on the DB. The problem I've is that calling the validator.validate returns true even if the call to json api returns false.
Here's the code (I use the Kendo MVC helpers but it's not related to that the problem)
<div id="divValidator1">
<div class="form-group">
#Html.LabelFor(m => m.Email)
#(Html.Kendo().TextBoxFor(m => m.Email)
.HtmlAttributes(new { placeholder = "you#domain.com", type = "email", #class = "k-textbox required",data_bind="value: XXX" })
)
</div>
<footer class="col-xs-12 form-group text-right">
#(Html.Kendo().Button()
.Name("Next1")
.Content("Next")
.HtmlAttributes(new { #class = "k-primary", data_bind = "enabled: isEnabled" })
.Events(ev => ev.Click("onNextClick")))
</footer>
var kendoValid = $("#divValidator1").kendoValidator({
validateOnBlur: false,
rules: {
remote: function (input) {
if (input.val() == "" || !input.attr("data-val-remote-url")) {
return true;
}
if (input.attr("data-val-remote-recieved")) {
input.attr("data-val-remote-recieved", "");
return !(input.attr("data-val-remote"));
}
var url = input.attr("data-val-remote-url");
var postData = {};
postData[input.attr("data-val-remote-additionalfields").split(".")[1]] = input.val();
var validator = this;
var currentInput = input;
input.attr("data-val-remote-requested", true);
$.ajax({
url: url,
type: "POST",
data: JSON.stringify(postData),
dataType: "json",
traditional: true,
async:false,
contentType: "application/json; charset=utf-8",
success: function (data) {
if (data == true) {
input.attr("data-val-remote", "");
}
else {
input.attr("data-val-remote", false);
}
input.attr("data-val-remote-recieved", true);
// validator.validateInput(currentInput);
},
error: function () {
input.attr("data-val-remote-recieved", true);
validator.validateInput(currentInput);
}
});
return true;
}
},
messages: {
remote: function (input) {
return input.attr("data-val-remote");
}
}
}).data("kendoValidator");
var viewModel1 = kendo.observable({
XXX:null,
isEnabled: function () {
var self = this;
self.get("XXX");
var x = $("#divValidator1").data("kendoValidator");
console.log(x.validate());
}
});
kendo.bind($("#divValidator1"), viewModel1);
and here's the controller
public ActionResult IsEmailJustPresent(string email)
{
var res = email == "something";
return Json(res, JsonRequestBehavior.AllowGet);
}
And the ViewModel
public class RegisterViewModel
{
[Required]
[EmailAddress]
[Display(Name = "Email")]
[Remote("IsEmailJustPresent", "Home")]
public string Email { get; set; }
}
I've also used a kendo.observable so that I can enable/disable the next button based on the validation value.
In the isEnabled function you see I do var x = $("#divValidator1").data("kendoValidator"); but it returns always true (seems to only check for the required attribute).
To reach that solution I started from here
If you want there's a more complex example I've created on git that includes the wizard I'll need in my final project
Could this commented line be the problem?
// validator.validateInput(currentInput);
Is the attribute "data-val-remote" correctly set?

How to use select tag in kendo ui grid in ASP.NET MVC 5?

I trying to use kendo ui for first time,i want to create kendo ui that has a list of some roles for users.so i need to have a row with UserName and ... list of roles.but i do not know how to create this row!
this is my usermodel:
public class UserViewModel
{
public string password { get; set; }
public string ConfirmPassword { get; set; }
public string UserName { get; set; }
public List<IdentityRole> Roles { get; set; }
}
and this is user service:
private ApplicationDbContext db = new ApplicationDbContext();
private IList<UserViewModel> GetAll()
{
var allusers = HttpContext.Current.Session["AllCountries"] as
IList<UserViewModel>;
if (allusers == null)
{
allusers = db.Users.Select(s => new UserViewModel
{
UserName = s.UserName,
}).ToList();
HttpContext.Current.Session["AllPerson"] = allusers;
}
return allusers;
}
public IEnumerable<UserViewModel> Read()
{
return GetAll();
}
public void Create(UserViewModel myuser)
{
var store = new UserStore<ApplicationUser>(db);
var manager = new ApplicationUserManager(store);
var CustomEmail = new Guid().ToString() + "#gmail.com";
manager.Create(new ApplicationUser
{
Id = new Guid().ToString(),
UserName = myuser.UserName,
Email = CustomEmail
}, myuser.password);
db.SaveChanges();
}
public void Update(UserViewModel vwusers)
{
if (vwusers.UserName!=null)
{
var store = new UserStore<ApplicationUser>(db);
var manager = new ApplicationUserManager(store);
var objCountry = manager.FindByName(vwusers.UserName);
if (objCountry != null)
{
objCountry.UserName = vwusers.UserName;
db.Entry(objCountry).State =
System.Data.Entity.EntityState.Modified;
db.SaveChanges();
}
}
}
and my view:
...
#(Html.Kendo().Grid<UserViewModel>()
.Name("Grid").Sortable()
.Filterable(ftb => ftb.Mode(GridFilterMode.Row))
.Columns(col =>
{
col.Bound(x => x.UserName).Filterable(ftb => ftb.Cell(cell =>
cell.Operator("contains").SuggestionOperator(FilterType.Contains)));
col.Bound(x => x.password).Visible(false);
col.Bound(x => x.ConfirmPassword).Visible(false);
col.Command(e => e.Edit().Text("Edit"));
col.Command(e => e.Destroy().Text("Delete"));
})
.Editable(editable => editable.Mode(GridEditMode.PopUp))
.ToolBar(s => s.Create().Text("AddCountry"))
.Pageable(page =>
page.Refresh(true).PageSizes(true).ButtonCount(5))
.ClientDetailTemplateId("Test")
.DataSource(ds =>
ds.Ajax()
.Model(m => {
m.Id(a => a.UserName);
m.Field(p => p.Roles).DefaultValue(new List<IdentityRole>());
})
.PageSize(10)
.Events(events => events.Error("error_handler"))
.Read(r => r.Action("ReadMasters", "User"))
.Create(c => c.Action("AddNewMaster", "User").Type(HttpVerbs.Post))
.Update(c => c.Action("UpdateMaster", "User"))
.Destroy(c => c.Action("DeleteMaster", "User"))
)
.Events(e => e.DataBound("dataBound"))
)
but i dont know how to display roles as a list for create and update!
Thanks in advance for your help

Custom Paging for ASP.Net MVC Kendo Grid

I have a MVC Kendo Grid as follows. It is working fine with default paging.
Now, I want to do custom paging. In the controller action we need to know the current page index. Also it should set the “total” count for the grid. [The actual data source will have only 2 records at a time even if there are 100 records in the database. So the grid must know the total number of records in database using “total” attribute.]
The query should return only 2 records from the database at a time.
How can we do this custom server paging using the MVC wrapper for Kendo Grid?
#using (Html.BeginForm())
{
#(Html.Kendo().Grid<KendoUIMvcSample.Models.Sample>()
.Name("ssgrid222")
.Columns(columns => {
columns.Bound(p => p.SampleDescription).Filterable(false).Width(100);
columns.Bound(p => p.SampleCode).Filterable(false).Width(100);
columns.Bound(p => p.SampleItems).Filterable(false).Width(100);
})
.AutoBind(false)
.Pageable()
.Sortable()
.Scrollable()
.Filterable()
.HtmlAttributes(new { style = "height:430px;" })
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(2)
.Read(read => read.Action("Orders_Read", "Sample")
)
)
)
}
Controller
public ActionResult Orders_Read([DataSourceRequest]DataSourceRequest request)
{
int currentPageNumber = request.Page;
return Json(GetOrders().ToDataSourceResult(request));
}
It is defined in the kendo site
CONTROLLER CODE
//Paging and Sorting
int currentPage = request.Page;
int pageSize = request.PageSize;
string sortDirection = "ASC";
string sortField = "UpdatedDateTime";
if (request.Sorts != null && request.Sorts.Count > 0)
{
sortField = request.Sorts[0].Member;
sortDirection = request.Sorts[0].SortDirection.ToString();
}
//Setting the TOTAL
var result = new DataSourceResult()
{
Data = orders,
Total = total // Total number of records
};
return Json(result);
VIEW
<div class="GridSearch">
#(Html.Kendo().Grid<MVC.Models.TransactionHistoryModel>()
.Name("TransactionHistroyGrid")
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(25)
.ServerOperation(true)
.Read(read => read
.Action("TransactionHistorySearch_Read", "TransactionHistoryResults")
.Data("additionalData")
)
)
.Columns(columns =>
{
columns.Bound(p => p.UserId).Filterable(false).Width(40).Title("Userid");
columns.Bound(p => p.Reviewed).Template(#<text></text>).ClientTemplate("<input id='checkbox' class='chkbx' type='checkbox' />").Filterable(false).Width(30).Title("Reviewed");
columns.Bound(p => p.CreatedOnEnd).Format("{0:MM/dd/yyyy}").Filterable(false).Width(50).Title("Created On");
columns.Bound(p => p.UpdatedOnEnd).Format("{0:MM/dd/yyyy}").Filterable(false).Width(50).Title("Updated On");
columns.Bound(p => p.Comment).Filterable(false).Width(50).Title("Comment");
})
.Pageable()
.Sortable()
.Scrollable()
.Filterable()
.HtmlAttributes(new { style = "height:325px;" })
)
</div>
Here is a custom paging solution we have implemented for Kendo ListView. With minor modification it should work for the grid. The solution consists of a custom DataSoure Object and a custom JSonResult class.
The custom data source:
public class MyDataSource
{
public object AggregateResults { get; set; }
public object Data { get; set; }
public object Errors { get; set; }
public int Total { get; set; }
}
The custom ActionResult:
public class JsonNetResult : ActionResult
{
public Encoding ContentEncoding { get; set; }
public string ContentType { get; set; }
public object Data { get; set; }
public JsonSerializerSettings SerializerSettings { get; set; }
public Formatting Formatting { get; set; }
public JsonNetResult()
{
SerializerSettings = new JsonSerializerSettings();
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
HttpResponseBase response = context.HttpContext.Response;
response.ContentType = !string.IsNullOrEmpty(ContentType)
? ContentType
: "application/json";
if (ContentEncoding != null)
response.ContentEncoding = ContentEncoding;
if (Data != null)
{
var writer = new JsonTextWriter(response.Output) { Formatting = Formatting };
JsonSerializer serializer = JsonSerializer.Create(SerializerSettings);
serializer.Serialize(writer, Data);
writer.Flush();
}
}
A Typical use in an action method would be:
public ActionResult Orders_Read([DataSourceRequest] Object request)
{
int count = 0;
var ds = (DataSourceRequest)request;
var ListOfItemsToDisplay = GetItemsWithPagingInfo
(
MySearchParameters,
ds.PageSize,
ds.Page,
out count
);
return new JsonNetResult
{
Formatting = Formatting.Indented,
Data = new MyDataSource
{
Data = ListOfItemsToDisplay
Total = count,
AggregateResults = null,
Errors = null
}
};
}

Custom Ajax Binding does not work properly

I have following code for Custom Ajax Binding. This has following problems even though it is displaying data for the first page.
• The request.Sorts is coming as NULL in to the Orders_Read method
• The request.PageSize is coming as 0 to the Orders_Read method
• The request.Page is coming as 1 to the Orders_Read method (even if I click on the page 2)
What changes need to be done here to get proper sort and pagesize values?
Note: I am using MVC Wrapper for Kendo Grid.
VIEW
#Scripts.Render("~/bundles/jquery")
<script type ="text/javascript">
$(document).ready(function (){
$('#Submit1').click(function () {
alert('1');
$('#grid12').data('kendoGrid').dataSource.read();
});
});
</script>
#model KendoPratapSampleMVCApp.Models.Sample
#{
ViewBag.Title = "CustomAjaxbind";
}
<h2>CustomAjaxbind</h2>
#using (Html.BeginForm("PostValues", "CustomAjaxBinding", FormMethod.Post))
{
<input id="Submit1" type="button" value="SubmitValue" />
#(Html.Kendo().Grid<KendoPratapSampleMVCApp.Models.Sample>()
.Name("grid12")
.EnableCustomBinding(true)
.Columns(columns => {
columns.Bound(p => p.SampleDescription).Filterable(false).Width(100);
columns.Bound(p => p.SampleCode).Filterable(false).Width(100);
columns.Bound(p => p.SampleItems).Filterable(false).Width(100);
})
.Pageable()
.Sortable()
.Scrollable()
.AutoBind(false)
.Filterable()
.HtmlAttributes(new { style = "height:430px;" })
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(2)
.Read(read => read.Action("Orders_Read", "CustomAjaxBinding"))
)
)
}
Controller
public class CustomAjaxBindingController : Controller
{
//
// GET: /CustomAjaxBinding/
public ActionResult Index()
{
return View("CustomAjaxbind");
}
public ActionResult Orders_Read([DataSourceRequest(Prefix = "grid12")]DataSourceRequest request)
{
string sortField = "SampleDescription";
string sortDirection = string.Empty;
if (request.Sorts != null)
{
foreach (SortDescriptor sortDescriptor in request.Sorts)
{
sortField = sortDescriptor.Member;
if (sortDescriptor.SortDirection == ListSortDirection.Ascending)
{
sortDirection = "Ascending";
}
else
{
sortDirection = "Descending";
}
}
}
int total = 1;
int myPageSize = 2;
if(request.PageSize !=0)
{
myPageSize = request.PageSize;
}
IEnumerable<Sample> currentSamples = GetSubsetEmployees(request.Page - 1, myPageSize, out total, sortField, sortDirection);
var result = new DataSourceResult()
{
Data = currentSamples,
Total = total // Total number of records
};
return Json(result);
}
public IEnumerable<Sample> GetSubsetEmployees(int pageIndex, int pageSize, out int itemCount, string sortField, string sortDirection)
{
IEnumerable<Sample> samples = GetSamples();
itemCount = samples.ToList().Count;
var selector = new Func<Sample, object>(e => e.GetType().GetProperty(sortField).GetValue(e, null));
var query = sortDirection.Equals("descending", StringComparison.OrdinalIgnoreCase)
? samples.OrderByDescending(selector)
: samples.OrderBy(selector);
List<Sample> currentPageEmployees = query
.Skip(pageIndex * pageSize)
.Take(pageSize)
.ToList();
return currentPageEmployees;
}
public static IEnumerable<Sample> GetSamples()
{
List<Sample> sampleAdd = new List<Sample>();
Sample s12 = new Sample();
s12.SampleCode = "1";
s12.SampleDescription = "A";
s12.SampleItems = "newone";
Sample s2 = new Sample();
s2.SampleCode = "2";
s2.SampleDescription = "B";
s2.SampleItems = "oldone";
Sample s3 = new Sample();
s3.SampleCode = "3";
s3.SampleDescription = "C";
s3.SampleItems = "latestone";
Sample s4 = new Sample();
s4.SampleCode = "4";
s4.SampleDescription = "D";
s4.SampleItems = "latestoneitem";
sampleAdd.Add(s12);
sampleAdd.Add(s2);
sampleAdd.Add(s3);
sampleAdd.Add(s4);
return sampleAdd;
}
}
Model
namespace KendoUIMvcSample.Models
{
public class SampleModel
{
public List<Sample> samples;
}
public class Sample
{
public string SampleDescription { get; set; }
public string SampleCode { get; set; }
public string SampleItems { get; set; }
}
}
I had the same problem as yours and finally found the solution recently after consuming days on investigating the problem. I post it here if someone else faced the same issue.
You need to remove Prefix from your parameter:
public ActionResult Orders_Read([DataSourceRequest(Prefix = "grid12")]DataSourceRequest request)
Converted to:
public ActionResult Orders_Read([DataSourceRequest]DataSourceRequest request)
I don't know if this is a bug from Kendo or not! But in this scenario grid can't be found by Prefix defined.
You can find an example here

How to update Chosen dropdownlist's items(cascade dropdownlist)?

I use Chosen plugin. I want to refresh Category (Chosen) dropdownlist, when change Section dropdownlist.
Here is view:
#model CategoryInputModel
#Html.DropDownListFor(model => model.SectionId, ViewBag.SectionList as IEnumerable<SelectListItem>, new { id = "SectionId" })
#Html.ListBoxFor(model => model.CategoryIdSet, ViewBag.AllCategoryList as MultiSelectList
, new
{
#class = "chzn-select",
data_placeholder = "Choose Categories...",
#style = "width : 500px;",
id = "CategoryIdSet"
})
CategoryInputModel is like:
public class CategoryInputModel
{
public string Name { get; set; }
public int SectionId{ get; set; }
public List<int> CategoryIdSet{ get; set; }
}
I can create cascade dropdownlist for simple lists, but could not create it for multiple select. I tried this :
<script type="text/javascript">
$(function () {
$("#SectionId").change(
function () {
loadLevelTwo(this);
});
loadLevelTwo($("#SectionId"));
});
function loadLevelTwo(selectList) {
var selectedId = $(selectList).val();
$.ajax(
{
url: "#Url.Action("GetCategoriesBySectionId", "Project")",
type: "GET",
data: { id: selectedId },
success: function (data) {
$("#CategoryIdSet").html($(data).html());
},
error: function (xhr) {
alert("Something went wrong, please try again");
}
});
}
</script>
In controller:
public ActionResult GetCategoriesBySectionId(int id)
{
var result = MyService.GetCategoriesBySectionId(id);
// **its problem to create partial view that return chosen dropdownlist I need**
}
How can I create cascade Chosen dropdownlist?
I think you need to add a little more to your ajax callback. I replaced success method with done. Try this, it works for me:
function loadLevelTwo(selectList) {
var selectedId = $(selectList).val();
$.ajax(
{
url: "#Url.Action("GetCategoriesBySectionId", "Project")",
type: "GET",
data: { id: selectedId },
error: function (xhr) {
alert("Something went wrong, please try again");
}
}).done(function (data) {
$("#CategoryIdSet").children().each(function (index, option) {
$(option).remove();
});
//blank option
var items = "<option selected value=\"\"></option>";
$.each(data,
function () {
items += "<option value=\"" + this[0] + "\">" + this[1] + "</option>";
});
$("#CategoryIdSet").html(items)
$("#CategoryIdSet").trigger("liszt:updated");
$("#CategoryIdSet").change();
});
}
controller action could look like this:
public ActionResult GetCategoriesBySectionId(int id)
{
var result = MyService.GetCategoriesBySectionId(id);
//build JSON.
var modelDataStore = from m in result
select new[] { m.YourValueProperty.ToString(),
m.YourTextProperty };
return Json(modelDataStore, JsonRequestBehavior.AllowGet);
}

Resources