I have a Grid and I'm doing AJAX inserts/updates/deletes on it. Insert and Update work great...the record is added/updated and the grid rebinds and I see the changes. Delete, however, deletes the record from the database and I'm 99% sure rebinds the grid (I'll explain in a minute), but the record is still present in the grid.
Now...I've gone through the other posts that said there were model validation errors which prevented the grid from rebinding. I used FireBug and am seeing absolutely no errors on the data coming back to the grid. The record that was deleted is listed in the items that are returned and there are no problems with it..other than it shouldn't be there still.
Here's what I did to see if the grid is rebinding. I added 2 records to the grid. I delete the first one and both records are still listed in the grid. I delete the second one and the first one disappears, but the second one is still there. Now this would seem to indicate to me that the grid is doing a rebind when I delete a record.
Call me crazy, but I can't seem to figure this out. Just for fun, I even inserted a System.Threading.Thread.Sleep(5000); line between the delete method and the rebind method. It didn't change anything.
Here's the response coming back from the Delete Ajax call. Id 12 is the one that was just deleted
{"data":[{"Id":1,"ReportId":"SCFR0006","ReportName":"Call Response","ReportDescription":"Call Response","ReportActive":true,"ReportSchedulable":true,"ReportLegend":true,"ReportSample":true,"ReportFaq":true},{"Id":12,"ReportId":"test","ReportName":"test","ReportDescription":null,"ReportActive":false,"ReportSchedulable":false,"ReportLegend":false,"ReportSample":false,"ReportFaq":false}],"total":2}
I also enclosed my database delete method in a if(ModelState.IsValid) {} block and it still executed...so it can't be the explanation I've seen in the forumns.
Any ideas?
8 Answers, 1 is accepted
I'm afraid that I'm not sure about the caused of the issue in question judging from the given details. Therefore, could it be possible to send us a small sample in which this behavior can be observed locally?
Regards,Rosen
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
Unfortunately it would be very difficult to send the entire project since it's wrapped in an Orchard CMS site and breaking it apart to get it under 35mb would I'm sure break it so that you couldn't test it. Let me post some of the pertinent code to see if there is something glaring you see that could be causing this behavior. If you wouldn't mind taking a look, that would be great.
here is the Model that this grid is retrieving data from
using
System;
using
System.ComponentModel;
using
System.ComponentModel.DataAnnotations;
using
System.Web.Mvc;
namespace
InfoSource.Models
{
public
class
ReportRecord
{
[ScaffoldColumn(
true
)]
[HiddenInput(DisplayValue =
false
)]
public
virtual
int
Id {
get
;
set
; }
[DisplayName(
"Fex ID"
)]
[Required]
public
virtual
string
ReportId {
get
;
set
; }
[DisplayName(
"Name"
)]
[Required]
public
virtual
string
ReportName {
get
;
set
; }
[DisplayName(
"Description"
)]
public
virtual
string
ReportDescription {
get
;
set
; }
[DisplayName(
"Active"
)]
public
virtual
bool
ReportActive {
get
;
set
; }
[DisplayName(
"Schedulable"
)]
public
virtual
bool
ReportSchedulable {
get
;
set
; }
[DisplayName(
"Legend"
)]
public
virtual
bool
ReportLegend {
get
;
set
; }
[DisplayName(
"Sample"
)]
public
virtual
bool
ReportSample {
get
;
set
; }
[DisplayName(
"FAQ"
)]
public
virtual
bool
ReportFaq {
get
;
set
; }
}
}
Here is the Controller and actions that are rendering the View
using
System.Web.Mvc;
using
Orchard;
using
Orchard.Localization;
using
Orchard.Themes;
using
InfoSource.Models;
using
InfoSource.Services;
using
Telerik.Web.Mvc;
namespace
InfoSource.Controllers
{
[Themed]
public
class
SetupController : Controller
{
public
IOrchardServices _orchardServices {
get
;
set
; }
public
readonly
ISetupService _setupService;
public
Localizer T {
get
;
set
; }
public
SetupController(IOrchardServices orchardServices, ISetupService setupService)
{
_orchardServices = orchardServices;
_setupService = setupService;
T = NullLocalizer.Instance;
}
public
ActionResult ReportList()
{
return
View();
}
[GridAction]
public
ActionResult _reportSelect()
{
return
View(
new
GridModel<ReportRecord>
{
Data = _setupService.GetReports()
});
}
[AcceptVerbs(HttpVerbs.Post)]
[GridAction]
public
ActionResult _reportInsert()
{
ReportRecord report =
new
ReportRecord();
if
(TryUpdateModel(report))
{
_setupService.CreateReport(report);
}
return
View(
new
GridModel<ReportRecord>
{
Data = _setupService.GetReports()
});
}
[AcceptVerbs(HttpVerbs.Post)]
[GridAction]
public
ActionResult _reportUpdate(
int
Id)
{
ReportRecord report = _setupService.GetReport(Id);
TryUpdateModel(report);
_setupService.UpdateReport(report);
return
View(
new
GridModel<ReportRecord>
{
Data = _setupService.GetReports()
});
}
[AcceptVerbs(HttpVerbs.Post)]
[GridAction]
public
ActionResult _reportDelete(
int
Id)
{
ReportRecord report = _setupService.GetReport(Id);
_setupService.DeleteReport(report);
return
View(
new
GridModel<ReportRecord>
{
Data = _setupService.GetReports()
});
}
}
}
The Controller is interacting with the database through this dependency
using
System.Collections.Generic;
using
InfoSource.Models;
using
Orchard;
namespace
InfoSource.Services
{
public
interface
ISetupService : IDependency
{
ReportRecord GetReport(
int
Id);
IEnumerable<ReportRecord> GetReports();
void
UpdateReport(ReportRecord report);
void
CreateReport(ReportRecord report);
void
DeleteReport(ReportRecord report);
}
}
which then connects to this service
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
InfoSource.Models;
using
Orchard;
using
Orchard.Data;
namespace
InfoSource.Services
{
public
class
SetupService : ISetupService
{
public
IOrchardServices _orchardServices {
get
;
set
; }
private
readonly
IRepository<ReportRecord> _reportRepository;
public
SetupService(IOrchardServices orchardServices, IRepository<ReportRecord> reportRepository)
{
_orchardServices = orchardServices;
_reportRepository = reportRepository;
}
public
ReportRecord GetReport(
int
Id)
{
ReportRecord report = _reportRepository.Get(Id);
return
report;
}
public
IEnumerable<ReportRecord> GetReports()
{
IEnumerable<ReportRecord> reports = from report
in
_reportRepository.Table
select report;
return
reports;
}
public
void
CreateReport(ReportRecord report)
{
_reportRepository.Create(report);
}
public
void
UpdateReport(ReportRecord report)
{
_reportRepository.Update(report);
}
public
void
DeleteReport(ReportRecord report)
{
_reportRepository.Delete(report);
}
}
}
Everything is then rendered in this View
@model IEnumerable<
ReportRecord
>
@using InfoSource.Models;
@using Telerik.Web.Mvc;
@{ Script.Require("Ifunctions"); }
@{ Style.Require("telerikcommon"); }
@{ Style.Require("telerikdefault"); }
@Html.AntiForgeryTokenOrchard()
@using (Script.Foot())
{
<
script
type
=
"text/javascript"
>
function gridLoad(e) {
$(this).find(".t-grid-add").first().text("Add a Report");
}
</
script
>
}
<
h2
class
=
"pagetitle facitweb"
>
Report List</
h2
>
<
div
class
=
"infoModule"
>
<
div
class
=
"infoModuleBottom"
>
<
ol
style
=
"list-style-type: decimal;"
>
<
li
>Click the pyramid icon to define benefits this report can be run for.</
li
>
<
li
>Click the shapes icon to define report types.</
li
>
<
li
>Click the gear icon to define report options.</
li
>
</
ol
>
</
div
>
</
div
>
<
div
>
@(Html.Telerik().Grid<
ReportRecord
>()
.Name("reportGrid")
.HtmlAttributes(new { @class = "grid_wrapper" })
.ToolBar(commands => commands.Insert())
.DataKeys(keys => keys.Add(o => o.Id))
.DataBinding(dataBinding => dataBinding.Ajax()
.OperationMode(GridOperationMode.Client)
.Select("_reportSelect", "Setup")
.Insert("_reportInsert", "Setup")
.Update("_reportUpdate", "Setup")
.Delete("_reportDelete", "Setup"))
.Columns(columns =>
{
columns.Bound(o => o.ReportId);
columns.Bound(o => o.ReportName);
columns.Bound(o => o.ReportActive)
.ClientTemplate("<
input
type
=
'checkbox'
disabled
=
'disabled'
name
=
'ReportActive'
<#= ReportActive?
checked
=
'checked'
: '' #> />")
.Filterable(false);
columns.Bound(o => o.ReportSchedulable)
.ClientTemplate("<
input
type
=
'checkbox'
disabled
=
'disabled'
name
=
'ReportSchedulable'
<#= ReportSchedulable?
checked
=
'checked'
: '' #> />")
.Filterable(false);
columns.Bound(o => o.ReportSample)
.ClientTemplate("<
input
type
=
'checkbox'
disabled
=
'disabled'
name
=
'ReportSample'
<#= ReportSample?
checked
=
'checked'
: '' #> />")
.Filterable(false);
columns.Bound(o => o.ReportLegend)
.ClientTemplate("<
input
type
=
'checkbox'
disabled
=
'disabled'
name
=
'ReportLegend'
<#= ReportLegend?
checked
=
'checked'
: '' #> />")
.Filterable(false);
columns.Bound(o => o.ReportFaq)
.ClientTemplate("<
input
type
=
'checkbox'
disabled
=
'disabled'
name
=
'ReportFaq'
<#= ReportFaq?
checked
=
'checked'
: '' #> />")
.Filterable(false);
columns.Command(commands =>
{
commands.Edit().ButtonType(GridButtonType.Image);
commands.Delete().ButtonType(GridButtonType.Image);
});
})
.Editable(editing => editing.Mode(GridEditMode.PopUp))
.Pageable(paging => paging.Style(GridPagerStyles.Status).PageOnScroll(true))
.Sortable()
.Selectable()
.Filterable()
.ClientEvents(events =>
{
events.OnDataBinding("bindToken");
events.OnSave("saveToken");
events.OnDelete("saveToken");
events.OnEdit("gridEdit");
events.OnLoad("gridLoad");
})
)
</
div
>
The ScriptRegistrar() tag for Telerik actually sites in the theme's Layout.cshtml file instead of the View. The style sheets are registered in a ResourceManifest.cs class file that I can then use Style.Require tags to include them in the View.
Finally, there is an IFunction.cs class file that contains some simple code for passing the anti-forgery token with the Grid requests. It is here
function
bindToken(e) {
e.data = { __RequestVerificationToken: $(
"input[name=__RequestVerificationToken]"
).val() };
}
function
saveToken(e) {
e.values[
"__RequestVerificationToken"
] = $(
"input[name=__RequestVerificationToken]"
).val();
}
function
gridEdit(args) {
$(args.form)
.closest(
".t-window"
)
.data(
"tWindow"
)
.center();
}
Hopefully that's not too much to look at. The code only contains information for the Grid in question so you shouldn't have to parse through too much extraneous info. Thanks again for taking a look.
[AcceptVerbs(HttpVerbs.Post)]
[GridAction]
public
ActionResult _reportDelete(
int
Id)
{
ReportRecord report = _setupService.GetReport(Id);
_setupService.DeleteReport(report);
return
View(
new
GridModel<ReportRecord>
{
Data = _setupService.GetReports2(Id)
});
}
GetReports2(Id) now runs this
public
IEnumerable<ReportRecord> GetReports2(
int
Id)
{
IEnumerable<ReportRecord> reports = from report
in
_reportRepository.Table
where report.Id != Id
select report;
return
reports;
}
Which makes everything work. So this tells me that the grid is indeed posting back. I'm just still at a loss why I have to exclude an Id that has already been deleted from the database. Could there perhaps be a caching issue? I tried adding
[OutputCache(Duration=0)]
to the ActionResults, but that didn't change anything.
Maybe there is a caching in your data access code/layer or some synchronization issue. Maybe the data context is not updated with the changes before the query for the updated data takes place.
Regards,Rosen
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
Controler Code
[HttpPost]
[GridAction]
public ActionResult DeleteConfirmed(string codigo,string tipo){
IRIS iris = db.Irides.Single(i => i.Codigo == codigo && i.Tipo == tipo);
db.Irides.DeleteObject(iris);
db.SaveChanges();
return View(new GridModel<IRIS>(db.Irides.ToList()));
}
I checked db.Irides count and watch the object and the item is really deleted only the rebind does not work
In View you can check the file , i tried with
.Delete("DeleteConfirmed", "IRIS") and with out it on the databind event the result is the same.
I have looked at the provided code snippets. The reason grid's data is not refreshed is that you are using a custom command instead of the built-in one. In this case you need to handle the onComplete event and the appropriate action of the command execution. However, looking at the provided code, I'm not sure why the custom command is used instead of the built-in one?
All the best,Rosen
the Telerik team
When there is more than one DataKey, the RouteKey setting should be used. Otherwise all keys will be posted as "id". For example:
.DataKeys(keys => keys.Add(c => c.OrderID))
.DataKeys(keys => keys.Add(c => c.OrderID).RouteKey(
"orderID"
))
will be posted as "orderID".
All the best,
Daniel
the Telerik team