Telerik Mvc Grid and AntiForgeryToken - telerik

I'm trying to set things up with my grid such that every action that every ajax post will include an antiforgery token. My gird is set up like so:
#(Html.Telerik().Grid(Model)
.Name("Folks")
.Sortable(x => x.SortMode(GridSortMode.SingleColumn))
.PrefixUrlParameters(false)
.Footer(true)
.Pageable(x => x.PageSize(25).Total((int)ViewData["total"]))
.DataBinding(dataBinding => dataBinding.Ajax())
.Columns(columns =>
{
columns.Bound(o => o.FirstName).Width(120).Title("First Name");
columns.Bound(o => o.LastName).Width(120).Title("Last Name");
})
.Selectable()
.ClientEvents(events =>
{
events.OnDataBinding("Test");
})
)
The handler for OnDataBinding (Test) looks like so:
<script type="text/javascript">
function Test(e) {
var valTokenValue = $("input[name=__RequestVerificationToken]").val();
e.data = { __RequestVerificationToken: valTokenValue };
}
</script>
I thought the argument (e) had a property called data which accepted a dictionary of values. However, FireBug keeps complaining saying that "data is undefined". Any ideas how I can include the token with every request? I'm using version 2011.Q2.712. Thanks.

It can't attach your token if there is no object to attach to. Create a Json object and set it to data if data is null/length=0/undefined (I know, overkill on the checking). I did the checking in a separate function so I wouldn't have to repeat the check every time I made an ajax call.
(function (TelerikGrid, $, undefined) {
TelerikGrid.OnDataBinding = function (e) {
e.data = AntiForgery.AddToken(e.data);
};})(window.TelerikGrid = window.TelerikGrid || {}, jQuery);
(function (AntiForgery, undefined) {
AntiForgery.AddToken = function (data) {
data = ((data == null || data.length == 0 || data == undefined) ? { } : data);
data.__RequestVerificationToken = $('#__AjaxAntiForgeryForm input[name=__RequestVerificationToken]').val();
return data;
};
})(window.AntiForgery = window.AntiForgery || {});

Related

how to add unique username in kendo ui and show alert or message after this insert duplicate username

I want to use kendo ui for manage the users in asp.net mvc and i need that kendo ui don't create duplicate username and display the error message that "the user name is duplicate"
this is my action for create
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddNewCountry([DataSourceRequest]DataSourceRequest request, CountryViewModel c,int countryId)
{
if (c != null && ModelState.IsValid)
{
countryService.Create(c);
}
return Json(new[] { c }.ToDataSourceResult(request, ModelState));
}
Thanks in advance for your help
I sent you a solution in your other post (see here). But here is how you handle SERVER side errors using the kendo CLIENT grid. Some of these steps could be changed. For example, you could popup an alert instead of displaying the error on the editor template.
1) Add a model state error to your action:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddNewCountry([DataSourceRequest]DataSourceRequest request, CountryViewModel c,int countryId)
{
if (countryService.UserExists(c.UserName) // You need to code this
{
ModelState.AddModelError("UserName", "User name already exists.");
}
if (c != null && ModelState.IsValid)
{
countryService.Create(c);
}
return Json(new[] { c }.ToDataSourceResult(request, ModelState));
}
Handle the error event on your DataSource:
#(Html.Kendo().Grid<OrderDetailViewModel>()
.Name("orderDetailsGrid")
/* Not relevant grid setup code... */
.DataSource(dataSource => dataSource
.Ajax()
.Read(builder => builder.Url("/api/CustomerOrderDetails/GetOrderDetails/" + Model.OrderId).Type(HttpVerbs.Get))
.Create(builder => builder.Url("/api/CustomerOrderDetails/CreateOrderDetail/" + Model.OrderId).Type(HttpVerbs.Put))
.Update(builder => builder.Url("/api/CustomerOrderDetails/UpdateOrderDetail").Type(HttpVerbs.Post))
.Destroy(builder => builder.Url("/api/CustomerOrderDetails/DeleteOrderDetail").Type(HttpVerbs.Delete))
.Model(model => {
model.Id(x => x.OrderDetailId);
model.Field(m => m.OrderDetailId).DefaultValue(0);
})
.Events(events => events.Error("OrderDetails_Error"))
))
3) Add a placeholder for the errors to your editor template:
<ul class="errors"></ul>
4) Setup a kendo template to process the errors:
<script type="text/x-kendo-template" id="orderDetailsValidationMessageTemplate">
# if (messages.length) { #
<li>#=field#
<ul>
# for (var i = 0; i < messages.length; ++i) { #
<li>#= messages[i] #</li>
# } #
</ul>
</li>
# } #
</script>
Write the js error handler that will look at the server errors returned and format them into a template that can be displayed on the editor page:
OrderDetails_Error = function(args) {
if (args.errors) {
var grid = $("#orderDetailsGrid").data("kendoGrid");
var validationTemplate = kendo.template($("#orderDetailsValidationMessageTemplate").html());
grid.one("dataBinding", function(e) {
e.preventDefault();
$.each(args.errors, function(propertyName) {
// take the template and insert it into the placeholder
var renderedTemplate = validationTemplate({ field: propertyName, messages: this.errors });
grid.editable.element.find(".errors").append(renderedTemplate);
});
});
}
};

How can I refresh the grid after I edit the Kendo UI grid?

I edit the grid using editable: "popup" as shown on Telerik's demo page. After I edit the grid, I want the grid to refresh. Does the grid have any event that is called after I edit the grid?
I tried to use the databound event. In this event I make the datasource read, but it tells me it is an infinite loop to refresh the grid. I tried to use the saveChanges event, but it is not working.
#(Html.Kendo().Grid<Kendo.Mvc.Examples.Models.ProductViewModel>()
.Name("grid")
.Columns(columns =>
{
columns.Bound(p => p.ProductName);
columns.Bound(p => p.UnitPrice).Width(100);
columns.Bound(p => p.UnitsInStock).Width(100);
columns.Bound(p => p.Discontinued).Width(100);
columns.Command(command => { command.Edit(); command.Destroy(); }).Width(160);
})
.ToolBar(toolbar => toolbar.Create())
.Editable(editable => editable.Mode(GridEditMode.PopUp))
.Pageable()
.Sortable()
.Scrollable()
.Events(events => events.Change("saveChanges "))
.HtmlAttributes(new { style = "height:430px;" })
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(20)
.Events(events => events.Error("error_handler"))
.Model(model => model.Id(p => p.ProductID))
.Create(update => update.Action("EditingPopup_Create", "Grid"))
.Read(read => read.Action("EditingPopup_Read", "Grid"))
.Update(update => update.Action("EditingPopup_Update", "Grid"))
.Destroy(update => update.Action("EditingPopup_Destroy", "Grid"))
))
You can subscribe to the Sync event of the grid's data source and call the read method of its data source.
.Events(events => events.Error("error_handler").Sync("sync_handler"))
function sync_handler(e) {
this.read();
}
Add Events into DataSource
.DataSource(dataSource => dataSource.Ajax(
.Events(e => e.RequestEnd("PowerPlantProduction.onRequestEnd"))**
)
Javascript:
onRequestEnd: function (e) {
if (e.type == "update") {
if (!e.response.Errors) {
e.sender.read();
}
}
},
The accepted answer can cause unexpected behaviour if you're using server side validation. The sync event triggers whenever an update is sent to the server regardless of whether the request was successful, so if the request triggers server side validation errors (or any other errors) the grid will still be updated and any changes lost. Still looking at the this but the best solution I've found is to use the data source's onRequestEnd() event and manually check for errors.
For example:
function onRequestEnd(e)
{
var grid = $("#grid").data("kendoGrid");
var data = grid.dataSource;
if (e.type == "create" || e.type == "update") {
if (!e.response.Errors)
data.read();
else console.log("I had some issues");
}
}
This will refresh the Grid
var grid = $("#Name").data("kendoGrid");
grid.dataSource.page(1);
if .page(1) doesn't work try .read, but it should
using AutoSync(true) in ajax mvc kendo grid having pop up edit mode causes the pop up to not show up at all.
So I use this
function onRequestEnd(e) {
if(e.type == "create" || e.type == "destroy" || e.type == "update") {
setTimeout(function myfunction() {
$("#mygrid").data("kendoGrid").dataSource.read();
}, 1000);
}
}
The time out is to make sure you dont over lap the crud operation.
In case someone else needs to know how to do this. You can include the "complete" function in your create as well as update bits.
transport: {
read: {
url: "http://myurl.json"
},
create: {
url: "http://mycreate.json",
type: "POST",
complete: function(e) {
$("#grid").data("kendoGrid").dataSource.read();
}
},
I agree this is very old question, but unfortunately I was also a victim of this error few days back. My scenario was
First time i was able to insert new record in database using popup method
If I add another record in same grid without refresh, grid is sending both the records to server, and unfortunately leads in duplicate value error.
Finally I think I got a solution for my problem, I was not setting primary key value to my record when I insert it into database and returning that object.
Below is my kendo grid code
#(Html.Kendo().Grid<TeamMemberViewModel>()
.Name("Grid")
.Columns(columns =>
{
columns.Bound(p => p.abcd);
columns.Bound(p => p.abcd_id).Hidden();
columns.Bound(p => p.abcd12_id).Hidden();
columns.Command(command =>
{
command.Edit();
command.Destroy();
});
})
.ToolBar(toolbar =>
{
if (ViewBag.IsAddAllowed)
{
toolbar.Create().Text("Add new");
}
// toolbar.Save().SaveText("Save Changes");
})
.Editable(editable => editable.Mode(GridEditMode.PopUp).TemplateName("ABCD")
)
.Pageable()
.Navigatable()
.Sortable()
.Scrollable()
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(20)
.ServerOperation(false)
.Events(events =>
{
events.Error("error_handler");
events.RequestEnd("request_end");
}
)
.Model(model =>
{
model.Id(p => p.primarykey_id);
model.Field(p => p.abcd);
})
.Create("ABCD_Create", "TeamMember", new { id = Model.abcd_id})
.Read("ABCD_Read", "TeamMember", new { id = Model.abcd_id })
.Update("ABCD_Update", "TeamMember", new { id = Model.abcd_id })
.Destroy("TeamMember_Destroy", "TeamMember", new { id = Model.hackathon_id })
)
)
Below is error handling code
function error_handler(e) {
if (e.errors) {
var message = "Errors:\n";
$.each(e.errors, function (key, value) {
if ('errors' in value) {
$.each(value.errors, function () {
message += this + "\n";
});
}
});
$(".errorMessage").text(message);
alert(message);
}
}
function request_end(e) {
switch (e.type) {
case "create":
if (e.Errors == undefined && e.response.Total > 0) {
// alert("Saved Successfully");
$(".errorMessage").text("Saved Successfully");
}
break;
case "update":
if (e.Errors == undefined && e.response.Total > 0) {
// alert("Updated Successfully");
$(".errorMessage").text("Updated Successfully");
}
break;
case "destroy":
if (e.Errors == undefined && e.response.Total > 0) {
// alert("Deleted Successfully");
$(".errorMessage").text("Deleted Successfully");
}
break;
default:
$(".errorMessage").text("");
break;
}
return true;
}
Server Code
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ABCD_Create([DataSourceRequest] DataSourceRequest request, MyViewModel my, short abcd_id)
{
if (my != null && ModelState.IsValid)
{
MY tm = Mapper.Map<MyViewModel>(my);
tm.abcd_id = abcd_id;
try
{
repo.Create(tm);
my.primarykey_id = tm.primarykey_id; ///This is most important
}
catch (Exception ex)
{
ModelState.AddModelError("Duplicate Value Found", string.Format("error: {0} already exists", my.abcd));
}
}
else
{
ModelState.AddModelError("Error", "Not valid please send data again");
}
return Json(new[] { my }.ToDataSourceResult(request, ModelState));
}
Hope this might help someone
Use this if you want to refresh the grid.
$("#WorkOrderDetails").data("kendoGrid").refresh();
You can call a function on you edit button click and inside that you can refresh the grid:
function EditRow(){
var grid = $("#YourGridName").data("kendoGrid");
grid.dataSource.read();
}
.sync: function (e) {
this.read();
},
I've been trying to figure out how to refresh the grid after creating a new item. Scenario is: Create an item in the client, send request to server, receive response and update client. (Alternatively, I wouldn't mind figuring out why the grid isn't using the item I'm returning it in the server-side create function)
This post mentions the requestEnd event, but it's not exposed in razor. This event seems to fire after a request is finished, that is, after the server processes the event, so new objects created on the client will already be sent to the server for processing; then the client can request the latest information without losing data. Since the grid datasource object was undefined on page load, I ended up using the .Change event to hook the requestEnd event.
#(Html.Kendo().Grid
.Name("user-grid")
...
.Pageable(pageable => pageable
...
.Events( e => e.Remove("grid_remove").Change("hook_request_end"))
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(20)
.Model(m =>
{
m.Id(vm => vm.DocumentId);
m.Field<DateTime>("LastModified").Editable(false);
})
.Read(a => a.Action("KList", "Controller"))
.Create(a => a.Action("KCreate", "Controller"))
.Update(a => a.Action("KUpdate", "Controller"))
)
and then the javascript:
var requestEndHooked = false;
function hook_request_end()
{
if (requestEndHooked == true)
{
return;
}
requestEndHooked = true;
$("#user-grid").data("kendoGrid").dataSource.bind("requestEnd", dataSource_requestEnd);
}
function dataSource_requestEnd(e)
{
try
{
if (e.type == "create")
{
$("#user-grid").data("kendoGrid").dataSource.read();
}
}
catch (e)
{
}
}
If there's a better way, I'd love to know.
To answer your question, there are events other than "create": "read", "update"
I know this is an old question, but there is a perfectly working example (at least for me!) on the Telerik forum: https://www.telerik.com/forums/refresh-grid-after-insert-update
I post this here because that forum question and answer is less than a year old, it might be that that solution wasn't available for the Kendo version at the time of the OP's question.
The solution mentioned there is to attach a dataBound handler function to the grid, which will be executed only once after the save event. In code:
function onGridEdit(e) {
e.sender.one("dataBound", function (e) {
e.sender.dataSource.read();
});
}
function bindDataAndRefresh(e) {
var grid = $("#upcoming-grid").data("kendoGrid");
grid.bind("dataBound", onGridEdit(e));
}
$(document).ready(function () {
var grid = $("#upcoming-grid").data("kendoGrid");
grid.bind("save", bindDataAndRefresh);
});
I used complete property of transport:update section while creating datasource for kendo.
My code
dsource = new kendo.data.DataSource({
transport: {
read: {
url: serverapiUrl + "/emp",
type: 'GET',
dataType: "json",
cache: true,
beforeSend: function (xhr, settings) {
xhr.setRequestHeader('api-key', 'auth key');
}
},
create: {
url: serverapiUrl + "/emp",
type: 'POST',
dataType: 'json',
beforeSend: function (xhr, settings) {
console.log('under create');
xhr.setRequestHeader('api-key', 'authkey');
xhr.setRequestHeader("content-type", "application/json");
console.log('settings', settings);
console.log(xhr);
}
},
update: {
url: serverapiUrl + "/emp",
type: 'PUT',
dataType: 'json',
beforeSend: function (xhr, settings) {
console.log('under update');
xhr.setRequestHeader('api-key', 'authkey');
xhr.setRequestHeader("content-type", "application/json");
console.log('settings', settings);
console.log(xhr);
},
complete: function (eve) {
console.log('update complete');
$("#griddiv").data("kendoGrid").dataSource.read();
}
}
rest follows the normal structure of kendo ui datasource creation documentation.

How to use local html5 storage to save grid preferences in Kendo Grid

My grid is:
#(Html.Kendo().Grid<Stuff>()
.Name("Grid")
.DataSource(source => source.Ajax().Events(events=>events.Error("onError"))
.Events(events=>events.RequestEnd("onRequestEnd"))
.Model(model =>
{
model.Field(p => p.PurchaseQuantity).Editable(false);
model.Field(p => p.PurchasePrice).Editable(false);
})
.Read("GetData", "Data"))
.Columns(columns =>
{
columns.Bound(o => o.PurchaseQuantity).Width(100);
columns.Bound(o => o.PurchasePrice).Format("{0:C}").Width(100);
})
.Sortable()
.Pageable(page=> page.PageSizes(new int[] { 10, 20, 50, 100 }).Refresh(true))
.Filterable(filterable => filterable.Extra(false))
.Events(boo=>boo.DataBound("onTest"))
.HtmlAttributes(new { style = "width:850px" })
)
and the javascript used to load data is:
<script type="text/javascript">
var storage = window.localStorage;
var storageLoaded = false;
function onError() {
$("#Grid").data("kendoGrid").dataSource.cancelChanges();
}
function onTest() {
if (!storageLoaded) {
console.log('loading size from storage ' + storage.pageSize);
storageLoaded = true;
console.log('marked storage loaded');
$("#Grid").data("kendoGrid").dataSource.pageSize(storage.PageSize);
console.log('set pagesize from storage ' + storage.pageSize);
var pagesize = $("#Grid").data("kendoGrid").dataSource.pageSize();
console.log('page size is ' + pagesize);
}
}
function onRequestEnd(e) {
if (storageLoaded) {
var pagesize = $("#Grid").data("kendoGrid").dataSource.pageSize();
storage.pageSize = pagesize;
console.log('setting size to storage ' + storage.pageSize);
}
}
firebug console shows:
loading size from storage 50 / marked storage loaded / set pagesize from storage 50 / page size is 10
Questions:
Why does the pagesize not save after set?
Is there a better way to accomplish this?
Is there a way to attach to the pagesize selector instead of using requestEnd?
Found a solution. Make the grid .AutoBind(false)
then
$(document).ready(function () {
storageLoaded = true;
$("#Grid").data("kendoGrid").dataSource._pageSize = storage.pageSize;
$("#Grid").data("kendoGrid").dataSource.read();
});
now this is making use of an _ variable inside the datasource which could break at any point in the future, but for now it does work.
I removed the databound event completely, a friend at Telerik was most helpful in getting me to the solution.
Hoping that in the future there will be something like:
.Pageable(page=> page.PageSizes(true).Refresh(true).Sticky("gridPageSizeDefault")
which will store the value in html5 local storage using the gridPageSizeDefaultkey.

Internal Server Error on kendo grid update with ajax

i m trying to update grid with ajax but i couldn't success in passing and getting values between controler and view with ajax
When i run program its output is like that
[object Object]++error++Internal Server Error
So i need help
HomeController Function
[HttpGet]
public ActionResult RssCek(string value)
{
XDocument rssXml = new XDocument();
switch (value)
{
case "Ekonomi":
{
rssXml = XDocument.Load("http://sozcu.com.tr/rss.php");
break;
}
case "Siyaset":
{
rssXml = XDocument.Load("http://www.milliyet.com.tr/D/rss/rss/Rss_4.xml");
break;
}
case "Yaşam":
{
rssXml = XDocument.Load("http://www.milliyet.com.tr/D/rss/rss/Rss_5.xml");
break;
}
default:
{
rssXml = XDocument.Load("http://sozcu.com.tr/rss.php");
}
break;
}
var feedler = from feed in rssXml.Descendants("item")
select new Rss
{
Baslik = feed.Element("title").Value,
Link = "Oku",
Aciklama = feed.Element("description").Value
};
var valueToReturn = new JsonResult { Data = feedler };
return valueToReturn;
}
IndexView Grid Code
#Html.Kendo().Grid(Model)
.Name("Grid").Pageable()
.Columns(columns =>
{
columns.Bound(p => p.Baslik).Groupable(false);
columns.Bound(p => p.Aciklama).Encoded(false);
columns.Bound(p => p.Link).Encoded(false);
})
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read.Action("RssCek", "Home"))
)
IndexView JavaScript Code
<script>
function select(e) {
var value = $(e.item).find("> .k-link").text();
$.ajax({
url: '#Url.Action("RssCek", "Home")',
type: 'GET',
contentType: 'application/json; charset=utf-8',
data: { value: value},
success: function (feedler)
{
document.write(feedler);
},
error: function (request, status, error)
{document.write(request+"++"+ status+"++"+ error);}
});
}
</script>
I found problem is caused by missing JsonRequestBehavior.AllowGet
return Json(feedler, JsonRequestBehavior.AllowGet);
instead of ;
var valueToReturn = new JsonResult { Data = feedler };
return valueToReturn;

Create options for each object of jquery plugin

I need your help again :)
I'm trying to do a plugin with jQuery specifications.
So I started reading this: http://docs.jquery.com/Plugins/Authoring
The document is cool and give nice patterns to follow.
But i have a problem with my plugin.
My plugin appends a div and bind some events to diferents features.
Sometimes i need to accés to the options var but... the problem is, if i do the opt var global it take the last object created options.
And if i put it in the init method, i can't use it in other actions.
I need each new object can acces only his own option set.
(function( $ ) {
//plugin methods
var methods = {
init : function( options ) {
//default options
var opt = $.extend({
'id' : 'test',
'title' : 'Test window',
'type' : 'normal',
'text' : 'test test! <br/> 123',
'shines' : '',
'head_shines' : '',
'body_shines' : '',
'bottom_bar' : true
}, options);
//shine or not shine? that's the matter
if (opt.shines != '') {
opt.shines = "shiny";
opt.head_shines = " shine_head";
opt.body_shines = " shine_body";
}
//maintaining Chainability
return this.each(function() {
var $this = $(this); // $this is now JQuery object
//creating the bottom bar
if (opt.bottom_bar == true && $("#bottom_bar").length == 0) {
$this.append('<div id="bottom_bar"></div>');
}
//creating the new window
$this.append("<div style='display: none;' class='window "+opt.shines+"' id='"+opt.id+"'>...boring html...</div>");
//append new window to the bar
$("#bottom_bar").append("<div style='display: none' class='section' id='s_"+opt.id+"'>"+opt.title+"</div>");
//get a object of the window to interact with
var $window = $("#"+opt.id);
//show the windows
$window.fadeIn().draggable();
$("#s_"+opt.id).fadeIn();
//attach the events to the windows
$window.find('.close').one('click.ventana', methods.close);
$window.find('.max').on('click.ventana', methods.maximize);
$window.find('.min').on('click.ventana', methods.minimize);
$("#s_"+opt.id).on('click.ventana', methods.minimizeBar);
});
},
close : function() {},
maximize : function() {}, //i want acces my opts here!
minimize : function() {},
minimizeBar: function() {} //or here... etc
}; //end methods
//creating the plugin
$.fn.ventana = function( method ) {
if ( methods[method] ) { //if we call a method...
return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ) );
} else if ( typeof method == 'object' || !method ) { //if not, we use init
return methods.init.apply( this, arguments);
} else { //method don't exists (console error)
$.error( 'Method ' + method + ' does not exists in jQuery.ventana');
}
};
}) ( jQuery );
The problem is, if i put where is the first comment:
//plugin methods
this:
//globals define
var opt;
I only get the last object opts...
Example creating new windows
$('body').ventana( {
'id' : 'master',
'title' : 'Afegir Finestres',
'text' : 'test'
});
$('body').ventana( {
'id' : 'master1',
'title' : 'Afegir Finestres1',
});
I just gonna get the master1 opts in both objects
You could use data to store the options object to be retrieved later.
// store it
$this.data("options", opt);
// ...
// use it later
var opt = $this.data("options");

Resources