I'm having trouble with an AJAX POST. I'm defining where I want the AJAX call to be posted, but it's posting elsewhere. Please help.
I'm using an MVC Telerik Grid. It probalby doesn't matter if you aren't familiar with it. I'm following the example at http://demos.telerik.com/aspnet-mvc/razor/grid/editingbatch
From that example, Important pieces to this Grid puzzle include:
.Editable(editing => editing.Mode(GridEditMode.InCell))
Also from that example, defining the url for the AJAX call:
.DataBinding(dataBinding => dataBinding.Ajax()
.Select("_SelectContactsBatchEditing", "Ajax", new {FirstName = #ViewData["FirstName"], LastName = #ViewData["LastName"]})
.Update("_SaveContactsBatchEditing", "Ajax", new {FirstName = #ViewData["FirstName"], LastName = #ViewData["LastName"]})
)
For both Select() and Update() methods, the first parameter is the Action and the second parameter is the Controller. I have a third optional parameter which contains the other data to send back in the post.
My grid is Master/Detail. I've taken out the Detail portion and I'm still having the issue. I've giving you my entire grid. For now please let's focus on the Master portion.
#(Html.Telerik().Grid<ContactView>()
.Name("ContactsGrid")
.Columns(columns =>
{
columns.Bound<int>(c => c.Id).Width(65).ReadOnly();
columns.Bound<string>(c => c.FirstName).Width(100);
columns.Bound<string>(c => c.LastName).Width(100);
columns.Bound<string>(c => c.Phone).Width(120);
columns.Bound<string>(c => c.Street).Width(200);
columns.Bound<string>(c => c.City).Width(100);
columns.Bound<string>(c => c.Province).Width(50).Title("Prov");
columns.Bound<string>(c => c.PostalCode).Width(80).Title("PC");
columns.Bound<string>(c => c.Email).Width(100);
columns.Bound<bool>(c => c.OkToContact).Width(40).Title("Ok")
.ClientTemplate("<input type='checkbox' disabled='disabled' name='OkToContact' <#=OkToContact? checked='checked' : '' #> />");
columns.Command(commands =>
{
commands.Delete();
}).Width(100);
})
.DetailView(details => details.ClientTemplate(
Html.Telerik().Grid<DonationView>()
.Name("Donations_<#= Id #>")
.Resizable(resizing => resizing.Columns(true))
.Editable(editing => editing.Mode(GridEditMode.InCell).DefaultDataItem(new DonationView(){Description = "Internal Cause"}))
.DataKeys(d => d.Add<int>(a => a.Id).RouteKey("Id"))
.Columns(columns =>
{
columns.Bound(o => o.Id).Width(65).ReadOnly();
columns.Bound(o => o.Description).Width(400);
columns.Bound(o => o.Amount).Width(80);
columns.Bound(o => o.Date).Format("{0:d}");
})
/*.ClientEvents(events => events.OnRowDataBound("cause_onRowDataBound"))*/
.DataBinding(dataBinding => dataBinding.Ajax()
.Select("_SelectDonationsHierarchyBatchEditing", "Ajax", new { ContactID = "<#= Id #>" })
.Update("_SaveDonationsHierarchyBatchEditing", "Ajax", new {ContactID = "<#= Id #>"})
)
.Sortable()
.ToolBar(commands => {
commands.Insert();
commands.SubmitChanges();
})
/*.Filterable()*/
.ToHtmlString()
))
.DataBinding(dataBinding => dataBinding.Ajax()
.Select("_SelectContactsBatchEditing", "Ajax", new {FirstName = #ViewData["FirstName"], LastName = #ViewData["LastName"]})
.Update("_SaveContactsBatchEditing", "Ajax", new {FirstName = #ViewData["FirstName"], LastName = #ViewData["LastName"]})
)
.Resizable(resizing => resizing.Columns(true))
//.Pageable(paging => paging.PageSize(25))
.Editable(editing => editing.Mode(GridEditMode.InCell))
.DataKeys(d => d.Add<int>(a => a.Id).RouteKey("Id"))
.Scrollable(scrolling => scrolling.Height(500))
.ToolBar(commands => {
commands.Insert();
commands.SubmitChanges();
})
//.HtmlAttributes(new { style = "width: 1200px" } )
.Sortable()
)
My Select() method calls correctly, however my Update() method does not. It simply posts to the same page the grid resides on. I had this working but didn't bother to check in (stupid), and broke it a few days later. No amount of Ctrl+Z has helped me.
Here is the action in my Ajax Controller. Details removed since they don't matter. The method just isn't getting called.
[GridAction]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult _SaveContactsBatchEditing([Bind(Prefix = "inserted")]IEnumerable<ContactView> insertedContacts,
[Bind(Prefix = "updated")]IEnumerable<ContactView> updatedContacts,
[Bind(Prefix = "deleted")]IEnumerable<ContactView> deletedContacts, string FirstName, string LastName)
{
ISession session = SessionManager.OpenSession();
ContactProvider cp = new ContactProvider(session);
if (insertedContacts != null)
{
//stuff
}
if (updatedContacts != null)
{
//stuff
}
if (deletedContacts != null)
{
//stuff
}
IList<ContactView> Contacts = new List<ContactView>();
ContactViewProvider Provider = new ContactViewProvider(SessionManager.OpenSession());
Contacts = Provider.GetContactsByName(FirstName, LastName);
//return View(new GridModel(Contacts));
return new LargeJsonResult
{
MaxJsonLength = int.MaxValue,
JsonRequestBehavior = System.Web.Mvc.JsonRequestBehavior.AllowGet,
Data = new GridModel<ContactView>
{
Data = Contacts
}
};
}
When I click the Save button in my grid's toolbar, I can use firebug to see the Select() method makes the proper AJAX call but the Update() method doesn't: (See http://i.stack.imgur.com/GPCS6.png)
In this image the first post url corresponds with the values passed into my Select() method. The second post url does not correspond with my Update() method.
What's going on here? Thanks in advance
So it turns out there is nothing wrong with what I did. The MVC project somehow became messed up.
I created a throwaway project to try to reproduced the issue but I couldn't - the throwaway was working. So I deleted the MVC project in my solution and copied the pieces into the new project one by one and sure enough, it works. I have no idea how it became discombopulated in the first place but at least the issue is rectified. For anyone having the same issue, I suggest you try this!
Related
By default it looks like Telerik Grid for MVC3 submits only the rows marked as "dirty" to my controller. I need to be able to submit all rows on a Telerik Grid to my controller. In other words I think I need to mark all rows as changed so the grid will send all rows to my controller.
I am using Ajax data binding as in:
.DataBinding(dataBinding => dataBinding
.Ajax()
.Select("GetData", "ModuleAccess", new { roleId = #ViewBag.RoleId, appId = #ViewBag.AppId })
.Update("SaveBatchEditing", "ModuleAccess")
#(Html.Telerik().Grid<BarcodeListModel>()
.Name("orders-grid")
.ClientEvents(events => events.OnDataBinding("onDataBinding"))
.DataKeys(keys =>
{
keys.Add(x => x.Id);
})
.ToolBar(commands =>
{
commands.SubmitChanges();
})
.DataBinding(dataBinding =>
dataBinding.Ajax()
.Select("BulkEditSelect", "ProductVariant")
.Update("BulkEditSaveBarcode", "ProductVariant")
.Delete("DeleteBarcode", "ProductVariant")
)
.Columns(columns =>
{
columns.Bound(x => x.Id).ReadOnly();
columns.Bound(x => x.SKU);
columns.Bound(x => x.barcode);
//columns.Bound(x => x.Id)
// .Template(x => Html.ActionLink(T("Admin.Common.View").Text, "DeleteBarcode", new { id = x.Id }))
// .ClientTemplate("" + "Delete" + "")
// .Width(50)
// .Centered()
// .HeaderTemplate("DeleteBarcode")
// .Filterable(false)
// .Title("Delete");
columns.Command(commands => commands.Delete()).Width(180);
})
.Pageable(settings => settings.PageSize(gridPageSize).Position(GridPagerPosition.Both))
.DataBinding(dataBinding => dataBinding.Ajax().Select("BarcodeList", "ProductVariant", Model))
.Editable(editing => editing.Mode(GridEditMode.InCell))
.EnableCustomBinding(true)
)
use like this code
I found the answer:
function ModuleAccessGridHasChanges() {
var grid = $("#ModuleAccessGrid").data("tGrid");
if (grid != null) {
var additionalValues = grid.data;
if (!$.telerik.trigger(grid.element, 'submitChanges', { values: additionalValues })) {
grid.sendValues($.extend({}, additionalValues), 'updateUrl', 'submitChanges');
}
}
}
Fiddler shows all the data for the grid coming accross:
I am having an issue where the READ operation for the Kendo Grid does not get invoked and hence the grid does not populate any data. I have followed these links
http://docs.kendoui.com/getting-started/using-kendo-with/aspnet-mvc/helpers/grid/troubleshooting#the-ajax-bound-grid-does-not-populate
Kendo UI Grid is not calling READ method
However the issue still exists.
/// CS File
public ActionResult GetItemsHome([DataSourceRequest] DataSourceRequest request , int page)
{
List<CustomItem> lst = new List<CustomItem>();
return Json(lst.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}
///cs html file
#(Html.Kendo().Grid<CustomItem>()
.Name("grid")
.Columns(columns =>
{
columns.Bound(o => o.No).Width("15%");
columns.Bound(o => o.ShortDesc).Width("15%");
columns.Bound(o => o.Category).Width("6%");
})
.Sortable()
.Pageable(p=>p.Refresh(true))
.Filterable()
.Scrollable()
.Editable(edit => edit.DisplayDeleteConfirmation("Are You Sure To Delete This ").Mode(GridEditMode.PopUp))
.ColumnMenu(col=>col.Sortable(false))
.Groupable()
.ToolBar(toolbar => toolbar.Create())
.Resizable(resize => resize.Columns(true))
.Reorderable(reorder => reorder.Columns(true))
//.ClientDetailTemplateId("template")
.HtmlAttributes(new { style = "height:430px;" })
.DataSource(dataSource => dataSource
.Ajax()
.PageSize(6)
.Read(read => read.Action("GetItemsHome", "det"))
.Model(model => {
model.Id(p => p.ID);
})
.Create(update => update.Action("EditingInline_Create", "det"))
// .Read(read => read.Action("EditingInline_Read", "Default1"))
.Update(update => update.Action("EditingInline_Update", "det"))
.Destroy(update => update.Action("EditingInline_Destroy", "det"))
)
)
the order in which the JS is loaded
Any ideas ?
Thanks
Your action GetItemsHome([DataSourceRequest] DataSourceRequest request , int page) requires page (non-null value) to be passed. You have 3 options:
Delete this argument (this makes sense since request contains everything you want)
Supply it like: .Read(read => read.Action("GetItemsHome", "det", new { page = 10}))
Make it nullable like: int? page
EDIT: After following any of above, return some data from controller action (I am creating some arbitrary data, you may return it from DB instead) to fill up your grid. Something like:
public ActionResult GetItemsHome([DataSourceRequest] DataSourceRequest request , int? page)
{
//List<CustomItem> lst = new List<CustomItem>();
// Dummy data
var data = new [] { new CustomItem(){ No = 1, ShortDesc = "xyz", Category = "abc"},
new CustomItem(){ No = 2, ShortDesc = "xyz", Category = "abc"} };
return Json(data.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}
If your controller and action names are spelled correctly in view, above code should work.
Some possibilities, if your function is not being called:
If your ActionResult Index() function is doing some other operations instead of simply return View() and exiting, it's possible your GetItemsHome() function may not be called - I had this issue once.
Try just naming the function "Read" instead of "GetItemsHome".
Does your controller have any other functions (i.e. Update, Destroy)? I would comment them out, in case there are syntax issues in them that are causing the issue.
"det", I hope, is the name of your controller.
Why pass in the extra page parameter at all? Try it without it, and use a public variable in your model to hold that value.
I am using Ajax binding and so I am assuming that if I want the total to update after the user edits a change, I need the ClientFooterTemplate as opposed to just the FooterTemplate which works.
Here is my grid which works with FooterTemplate:
#{
GridEditMode mode = (GridEditMode)ViewData["mode"];
GridButtonType type = (GridButtonType)ViewData["type"];
GridInsertRowPosition insertRowPosition = (GridInsertRowPosition)ViewData["insertRowPosition"];
Html.Telerik().Grid<RedFile.Models.QuickQuoteItemView>("items")
.Name("QuoteItems")
.DataKeys(k => k.Add(o => o.Id))
.ToolBar(commands => commands.Insert().ButtonType(type).ImageHtmlAttributes(new { style = "margin-left:0" }))
.Columns(c =>
{
c.Bound(o => o.Id).ReadOnly().Hidden();
c.Bound(o => o.ItemID);
c.Bound(o => o.Description);
c.Bound(o => o.ItemQty);
c.Bound(o => o.ItemPrice).Format("{0:c}");
c.Bound(o => o.LineTotal)
.Width(100)
.Aggregate(ag => ag.Sum())
.FooterTemplate(result => (result.Sum == null ? "0.00" : result.Sum.Format("{0:c}")))
.Format("{0:c}");
c.Command(s =>
{
s.Edit();
s.Delete();
});
})
.Editable(editing => editing.Mode(mode).InsertRowPosition(insertRowPosition))
.DataBinding(b => b.Ajax()
.Select("GridSelect", "QuickQuote")
.Insert("GridInsert", "QuickQuote", new { qqid = Model.Id })
.Update("GridUpdate", "QuickQuote", new { qqid = Model.Id })
.Delete("GridDelete", "QuickQuote", new { qqid = Model.Id })
)
.Footer(true)
.Render();
}
If I change the footer template to something like this: (I have tried multiple variations with the same result)
.ClientFooterTemplate("<#= $.telerik.formatString('{0:c}', Sum) #>")
The total simply disappears.
All I want is a total that updates after the user changes something. Any idea what I'm doing wrong?
Thanks
columns.Bound(p => p.ItemPrice)
.FooterTemplate(
#<text>
Total:#string.Format("{0:c}", Model.ItemPrice)
</text>
)
.Width(100)
.Format("{0:c}");
Refer to Teleriks MVC grid Documentation
I have the following markup.
#(Html.Telerik().Grid(Model)
.Name("Grid")
.DataKeys(keys => keys.Add(key => key.Id))
.Columns(columns =>
{
columns.Bound(c => c.FullNameWithEmail).ClientTemplate("<#= FullNameWithEmail #>").Title("Name and Email").Width(230);
columns.Bound(c => c.Notes);
})
.ClientEvents(events => events.OnRowDataBound("grid_onRowDataBound"))
.DetailView(checkInAppGridDetails => checkInAppGridDetails.ClientTemplate("<# if (RelatedCount > 0) { #>" +
Html.Telerik().Grid<ViewModel>()
.Name("GridDetails_<#= Id #>")
.Footer(false)
.Columns(columns =>
{
columns.Bound(c => c.FullNameWithEmail).ClientTemplate("<#= FullNameWithEmail #>").Title("Name and Email").Width(225);
columns.Bound(c => c.Notes);
columns.Bound(c => c.Actions).ClientTemplate("<#= Actions #>").Width(150);
})
.ClientEvents(events => events.OnRowDataBound("GridDetails_onRowDataBound"))
.DataBinding(dataBinding => dataBinding.Ajax()
.Select("GetRelated", "Controller", new
{
id = #ViewBag.EventKey,
ticketId = "<#= Id #>"
}))
.ToHtmlString() +
"<# } #>"
))
)
What i have here is that i am binding the main grid with Ajax call, and once rows got bound the details view gets bound with the DataBinding ajax call.
I already have in the Model a collection for the related records i wanted to show in the DetailView, i don't want the extra call to the server.
here is an example of the ViewModel
public class ViewModel
{
public string FirstProperty {get; set;}
.
.
.
public IEnumurable<ViewModel> RelatedRecords { get; set; }
}
Any idea how to bind the whole Grid with the DetailView with only single Ajax request?
Just used telerik support example to fix this, and it worked very well.Telerik Post
I am using free Telerik.Web.Mvc grid and following this example: http://demos.telerik.com/aspnet-mvc/grid/hierarchyajax
My Issue:
I am populating the grid with search results after user input some data and submit with a search button
In the DetailView() method I reference my 'SearchQuote_QuotesForHierarchyAjax' method, which is in defined in my Controller when DetailView executes data should be fetched, but this controller action does not execute for me.
If i load the grid first time page loads it execute. but not when the grid is loaded in a search button click
The Code in my project:
My SearchQuote.aspx View looks like this
<%= Html.Telerik().Grid(Model.QuoteSummaryList)
.Name("SearchQuoteGrid")
.Columns(columns =>
{
columns.Bound(q => q.QuoteId).Title("Quote #").Width(50);
columns.Bound(q => q.AxiomId).Title("Axiom Id").Width(180);
})
.ClientEvents(events => events.OnRowDataBound("quotes_onRowDataBound"))
.DetailView(details => details.ClientTemplate(
Html.Telerik().Grid(Model.QuoteSubSummaryList)
.Name("Quotes_<#= QuoteId #>")
.Columns(columns =>
{
columns.Bound(o => o.PositionCode).Width(101);
columns.Bound(o => o.Group).Width(140);
})
.DataBinding(dataBinding => dataBinding.Ajax()
.Select("SearchQuote_QuotesForHierarchyAjax", "SearchQuote", new
{quoteid ="<#= QuoteId #>"}))
.Pageable()
.Sortable()
.Filterable()
.ToHtmlString()
))
.DataBinding(dataBinding => dataBinding.Ajax()
.Select("SearchQuote_Select", "SearchQuote"))
.Sortable()
.Pageable(p => p.PageSize(3))
%>
<script type="text/javascript">
function expandFirstRow(grid, row) {
if (grid.$rows().index(row) == 0) {
grid.expandRow(row);
}
}
function quotes_onRowDataBound(e) {
var grid = $(this).data('tGrid');
expandFirstRow(grid, e.row);
}
</script>
And SearchQuoteController has this code.
[AcceptVerbs(HttpVerbs.Post)]
[GridAction]
public ActionResult SearchQuote_QuotesForHierarchyAjax(int quoteid)
{
List<QuoteLineSummaryDM> sublist = new List<QuoteLineSummaryDM>();
QuoteLineSummaryDM a = new QuoteLineSummaryDM();
a.PositionCode = "50";
a.Group = "1";
sublist.Add(a);
QuoteLineSummaryDM b = new QuoteLineSummaryDM();
b.PositionCode = "40";
b.Group = "2";
sublist.Add(b);
var qrows = (from r in sublist
select r).AsQueryable();
return View(new GridModel(qrows));
}
What am I missing? My version is even simpler than the demo. Any ideas?
Thanks.
I found another grid that does what I want to do. It's called jqGrid