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

Demo of Batch Editing with Enum Columns?

4 Answers 345 Views
Grid
This is a migrated thread and some comments may be shown as answers.
Nick
Top achievements
Rank 1
Nick asked on 13 Feb 2013, 11:31 AM
I'm just evaluating the Kendo grid for an upcoming project and I'm hunting for demos for the functionality that I need.

I have created a grid in an asp.net razor view that takes a viewmodel.  A couple of the model properties are enums which display nicely but when clicking into the cell just render a text box with the enum value (1,2,3,etc).

Does anyone have a demo where the edit field is an appropriate dropdown rather than the raw value of the enum?

Thanks in advance :)

=================================================================================

For reference the model and view I'm using are:
public class HomeMonitorViewModel {
 
  public int Id { get; set; }
  [Required, StringLength(255)]
  public string Name { get; set; }
  [Required, StringLength(128)]
  public string HostSystem { get; set; }
  public string Description { get; set; }
  public Data.MonitorClassification Classification { get; set; }
  public DateTime DateAdded { get; set; }
  public bool HasBeenAdministered { get; set; }
  public Data.MonitorSource Source { get; set; }
  public int MonitorAliasId { get; set; }
  public string MonitorAliasName { get; set; }
 
}
 
public enum MonitorClassification {
  Default = 1,
  Standard = 2,
  Bespoke = 3
}
 
public enum MonitorSource {
  Policy = 1,
  Adhoc = 2,
  Unknown = 3
}
@(Html.Kendo().Grid<ProjectBlackSun.Models.Home.HomeMonitorViewModel>()
  .Name("MonitorGrid")
  .Columns(c => {
    c.Bound(m => m.Name);
    c.Bound(m=>m.MonitorAliasName);
    c.Bound(m=>m.Description);
    c.Bound(m=>m.HostSystem);
    c.Bound(m=>m.Classification);
    c.Bound(m=>m.Source);
  })
  .ToolBar(t => {
    t.Create();
    t.Save();
  })
  .Editable(e => e.Mode(GridEditMode.InCell))
  .Pageable()
  .Sortable()
  .DataSource(d => d
    .Ajax()
    .Batch(true)
    .ServerOperation(false)
    .Events(e => e.Error("error_handler"))
    .Model(model => model.Id(monitor => monitor.Id))
    .Create("MonitorGridCreate", "Home")
    .Read("MonitorGridRead", "Home")
    .Update("MonitorGridUpdate", "Home")
    .Destroy("MonitorGridDestroy", "Home")
  )
)
 
<script type="text/javascript">
    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";
                    });
                }
            });       
            alert(message);
        }
    }
</script>



4 Answers, 1 is accepted

Sort by
0
Vladimir Iliev
Telerik team
answered on 15 Feb 2013, 07:07 AM
Hi Nick,

 
Please note that KendoUI for ASP.NET MVC installation comes with offline demos which contains such example in the "Editing custom editor" demo. These demos can be found under the installation folder:

  • ...\Telerik\Kendo UI for ASP.NET MVC Q3 2012\wrappers\aspnetmvc\Examples\

Kind Regards,
Vladimir Iliev
the Telerik team
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
0
Nick
Top achievements
Rank 1
answered on 15 Feb 2013, 10:26 AM
Hi Vladimir,

Yeah, I found those yesterday and have changed my view model to get a dropdown list as the editor for one of my columns. Unfortunately this raised a new issue.

public class HomeMonitorViewModel {
 
  public int Id { get; set; }
  [Required, StringLength(255)]
  public string Name { get; set; }
  [Required, StringLength(128)]
  public string HostSystem { get; set; }
  public string Description { get; set; }
  public Data.MonitorClassification Classification { get; set; }
  public DateTime DateAdded { get; set; }
  public bool HasBeenAdministered { get; set; }
  public Data.MonitorSource Source { get; set; }
   
  [UIHint("MonitorAlias")]
  public AliasListItemViewModel MonitorAlias { get; set; }
 
}
 
public class AliasListItemViewModel {
  public int AliasId { get; set; }
  public string AliasName { get; set; }
}
I have changed the MonitorAlias property to be a viewmodel that contains Id and Name so this can be edited from a dropdown.  The grid declaration now looks like this:

<!-- Grid in view -->
@(Html.Kendo().Grid<ProjectBlackSun.Models.Home.HomeMonitorViewModel>()
  .Name("MonitorGrid")
  .Columns(c => {
    c.Bound(m => m.Name);
    c.Bound(m => m.MonitorAlias).ClientTemplate("#=MonitorAlias.AliasId#");
    c.Bound(m=>m.Description);
    c.Bound(m=>m.HostSystem);
    c.Bound(m=>m.Classification);
    c.Bound(m=>m.Source);
  })
  .ToolBar(t => {
    t.Create();
    t.Save();
  })
  .Editable(e => e.Mode(GridEditMode.InCell))
  .Pageable()
  .Sortable()
  .DataSource(d => d
    .Ajax()
    .Batch(true)
    .ServerOperation(false)
    .Events(e => e.Error("error_handler"))
    .Model(model => model.Id(monitor => monitor.Id))
    .Create("MonitorGridCreate", "Home")
    .Read("MonitorGridRead", "Home")
    .Update("MonitorGridUpdate", "Home")
    .Destroy("MonitorGridDestroy", "Home")
  )
)
 
<!-- Custom editor template -->
@(Html.Kendo().DropDownList()
              .Name("MonitorAlias")
              .DataValueField("AliasId")
              .DataTextField("AliasName")
              .BindTo((System.Collections.IEnumerable)ViewData["aliases"])
)
This work great in edit mode, the dropdown appears with my Aliases listed and I can change the value.

My new problem is now that column displays the Id value in the grid and not the text.

Is there some attribute or function I've missed to tell the grid to display AliasName in read mode, not AliasId?

Thanks,
Nick

EDIT:

This change also seems to have broken the Add Item functionality,  Clicking the Add New Item button now simply results in a client error "Uncaught ReferenceError: MonitorAlias is not defined"

Does the add functionality not use the same editor template as the edit function?


0
Accepted
Vladimir Iliev
Telerik team
answered on 15 Feb 2013, 10:50 AM
Hi Nick,


I would suggest to flatter your model to contain only the AliasId and use the ForiegnKeyColumn functionality of the grid to match the text to the value. For convenience (and better understand this functionality) I created small demo and attached it to the current thread. 

Kind regards,
Vladimir Iliev
the Telerik team
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
0
Nick
Top achievements
Rank 1
answered on 15 Feb 2013, 12:45 PM
Hi Vladimir,

Thanks for that, the ForeignKey function works much better for me than the custom editor.

For reference and anyone else who's interested I ended up with the following:

Viewmodels:
public class HomeMonitorViewModel {
  public int Id { get; set; }
  [Required, StringLength(255)]
  public string Name { get; set; }
  [Required, StringLength(128)]
  public string HostSystem { get; set; }
  public string Description { get; set; }
  public Data.MonitorClassification Classification { get; set; }
  public bool HasBeenAdministered { get; set; }
  public Data.MonitorSource Source { get; set; }
  public int MonitorAliasId { get; set; }
}
 
public class ClassificationListItemViewModel {
  public int Id { get; set; }
  public string Name { get; set; }
}
 
  public class AliasListItemViewModel {
  public int AliasId { get; set; }
  public string AliasName { get; set; }
}

View:
@(Html.Kendo().Grid<ProjectBlackSun.Data.Monitor>()
  .Name("MonitorGrid")
  .Columns(c => {
    c.Bound(m => m.Name);
    c.ForeignKey(m=>m.MonitorAliasId,(System.Collections.IEnumerable)ViewData["aliases"],"AliasId","AliasName");
    c.Bound(m=>m.Description);
    c.Bound(m=>m.HostSystem);
    c.ForeignKey(m=>m.Classification,(System.Collections.IEnumerable)ViewData["classifications"],"Value","Text");
    c.ForeignKey(m=>m.Source,(System.Collections.IEnumerable)ViewData["sources"],"Value","Text");
  })
  .ToolBar(t => {
    t.Create();
    t.Save();
  })
  .Editable(e => e.Mode(GridEditMode.InCell))
  .Pageable()
  .Sortable()
  .DataSource(d => d
    .Ajax()
    .Batch(true)
    .ServerOperation(false)
    .Events(e => e.Error("error_handler"))
    .Model(model => model.Id(monitor => monitor.Id))
    .Create("MonitorGridCreate", "Home")
    .Read("MonitorGridRead", "Home")
    .Update("MonitorGridUpdate", "Home")
    .Destroy("MonitorGridDestroy", "Home")
  )
)
And the corresponding controller actions:
public class HomeController : Controller {
 
  private Data.MonitorContext _monitorContext;
 
  public HomeController() {
    _monitorContext = new Data.MonitorContext();
  }
 
  public ActionResult Index() {
 
    PopulateAliases();
    PopulateClassifications();
    PopulateSources();
    return View();
  }
 
  public ActionResult MonitorGridRead([DataSourceRequest] DataSourceRequest request) {
    // We need to drop into a view model to prevent circular reference errors when json serializing.
    var data = _monitorContext.Monitors.Select(x => new HomeMonitorViewModel() {
      Classification = x.Classification,
      Description = x.Description,
      HasBeenAdministered = x.HasBeenAdministered,
      HostSystem = x.HostSystem,
      Id = x.Id,
      MonitorAliasId = x.MonitorAliasId,
      Name = x.Name,
      Source = x.Source
    });
    var retval = data.ToDataSourceResult(request);
    return Json(retval);
  }
 
  [HttpPost]
  public ActionResult MonitorGridCreate([DataSourceRequest] DataSourceRequest request, [Bind(Prefix = "models")]IEnumerable<HomeMonitorViewModel> monitors) {
 
    var results = new List<Data.Monitor>();
 
    if (monitors != null && ModelState.IsValid) {
      foreach (var monitor in monitors) {
 
        Data.Monitor data = new Data.Monitor {
          Classification = monitor.Classification,
          Description = monitor.Description,
          HasBeenAdministered = true,
          HostSystem = monitor.HostSystem,
          MonitorAliasId = monitor.MonitorAliasId,
          Name = monitor.Name,
          Source = monitor.Source
        };
         
        _monitorContext.Monitors.Add(data);
        results.Add(data);
      }
      _monitorContext.SaveChanges();
    }
    return Json(results.ToDataSourceResult(request, ModelState));
  }
 
  private void PopulateAliases() {
    ViewData["aliases"] = _monitorContext.MonitorAliases
      .OrderBy(a => a.Name)
      .Select(a => new Models.Home.AliasListItemViewModel {
        AliasId = a.Id,
        AliasName = a.Name
      });
  }
 
  private void PopulateClassifications() {
    IEnumerable<SelectListItem> data = Enum.GetValues(typeof(Data.MonitorClassification))
                                           .Cast<Data.MonitorClassification>()
                                           .Select(v => new SelectListItem {
                                             Text = v.ToString(),
                                             Value = ((int)v).ToString()
                                           });
    ViewData["classifications"] = data;
  }
 
  private void PopulateSources() {
    IEnumerable<SelectListItem> data = Enum.GetValues(typeof(Data.MonitorSource))
                                           .Cast<Data.MonitorSource>()
                                           .Select(v => new SelectListItem {
                                             Text = v.ToString(),
                                             Value = ((int)v).ToString()
                                           });
    ViewData["sources"] = data;
  }
 
}
Please bear in mind this is dirty proof of concept stuff, tightly coupled to the EF DbContext.  Don't do this in production code!  :)



Tags
Grid
Asked by
Nick
Top achievements
Rank 1
Answers by
Vladimir Iliev
Telerik team
Nick
Top achievements
Rank 1
Share this question
or