This is a migrated thread and some comments may be shown as answers.

Rebind from Delete too quick?

8 Answers 62 Views
Grid
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Philip Senechal
Top achievements
Rank 1
Philip Senechal asked on 28 Jul 2011, 11:41 PM
Could this be possible...because I can't explain it any other way?

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

Sort by
0
Rosen
Telerik team
answered on 29 Jul 2011, 09:06 AM
Hi Philip Senechal,

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

0
Philip Senechal
Top achievements
Rank 1
answered on 29 Jul 2011, 05:32 PM
Hi Rosen...thanks for the reply.

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.
0
Philip Senechal
Top achievements
Rank 1
answered on 29 Jul 2011, 05:51 PM
Just as an added troubleshooting step, I changed the delete method to the controller to this
[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.
0
Rosen
Telerik team
answered on 01 Aug 2011, 08:10 AM
Hi Philip Senechal,

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

0
Filipe
Top achievements
Rank 1
answered on 05 Dec 2011, 04:25 PM
Same rebind problem    

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.

 

 

 

 

 


 

 


0
Rosen
Telerik team
answered on 06 Dec 2011, 05:29 PM
Hi Filipe,

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
If you want to get updates on new releases, tips and tricks and sneak peeks at our product labs directly from the developers working on the Telerik Extensions for ASP.MET MVC, subscribe to their blog feed now
0
Filipe
Top achievements
Rank 1
answered on 09 Dec 2011, 09:50 AM
I had one prob implementing built solution for the delete button my control method has 2 parameters that are the keys of the grid but only one is passing with value the other one is allways null.
0
Daniel
Telerik team
answered on 09 Dec 2011, 03:57 PM
Hi Filipe,

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))
will be posted as "id"(the default ASP.NET route parameter name). Whereas:
.DataKeys(keys => keys.Add(c => c.OrderID).RouteKey("orderID"))

will be posted as "orderID".


All the best,
Daniel
the Telerik team
If you want to get updates on new releases, tips and tricks and sneak peeks at our product labs directly from the developers working on the Telerik Extensions for ASP.MET MVC, subscribe to their blog feed now
Tags
Grid
Asked by
Philip Senechal
Top achievements
Rank 1
Answers by
Rosen
Telerik team
Philip Senechal
Top achievements
Rank 1
Filipe
Top achievements
Rank 1
Daniel
Telerik team
Share this question
or