I am using Kendo UI (Telerik UI for ASP.NET MVC R3 2018) and I attempt to load data into it but the grid appears only showing header columns without the data. I have also tried debugging but I can't figure what the problem is. I also tried this thread but it doesn't solve my problem.
Below is what I have done and I am expecting the grid to show the data.
Model
public partial class PlacementType
{
public byte Id { get; set; }
[Display(Name = "Placement Name")]
public string PlacementName { get; set; }
[DataType(DataType.Date)]
[Display(Name = "Date Created")]
public DateTime? DateCreated { get; set; }
[Display(Name = "Created By")]
public string CreatedBy { get; set; }
public string Description{get; set;}
}
View
#(Html.Kendo().Grid<PlacementType>()
.Name("Grid")
.Columns(columns =>
{
columns.Bound(c => c.PlacementName);
columns.Bound(c => c.DateCreated);
columns.Bound(c => c.CreatedBy);
columns.Bound(c => c.Description);
}
)
.HtmlAttributes(new { style = "height: 550px;" })
.Scrollable()
.Groupable()
.Sortable()
.Pageable(pageable => pageable.Refresh(true).PageSizes(true))
.DataSource(dataSource => dataSource
.Ajax()
.Read(read => read.Action("Index", "PlacementType"))
.PageSize(20)
)
)
Controller Action
public ActionResult Index()
{
List<PlacementType> types = db.PlacementTypes.ToList();
return View(types);
}
Your controller should have a method which returns a Json result.
E.g.
public JsonResult GetPlacementTypes()
{
var types = db.PlacementTypes.ToList();
return Json(types, JsonRequestBehavior.AllowGet);
}
And update your view to use this method. (Assume your controller is called "PlacementTypeController")
.Read(read => read.Action("GetPlacementTypes", "PlacementType"))
You define the following Read Action:
.Read(read => read.Action("Index", "PlacementType"))
Therefore make sure your Controller is named PlacementTypeController (with standard convention). The method needs to be named Index. That`s how you have configured it above.
If Index is already used by your view, you need to change read.Action Index to SomethingElse. Make sure, you Controller Action is also called SomethingElse Then.
Then the following Code should work:
public ActionResult Index([DataSourceRequest] DataSourceRequest request)
{
// var breakPoint = db.PlacementTypes.ToList(); // uncomment and set a breakpoint to see if you have data
return Json(db.PlacementTypes.ToDataSourceResult(request));
}
Note the use of the DataSourceRequest Attribute and the ToDataSourceResult method.
If it`s still not working, uncomment the comment, and set a breakpoint. Is your database actualy returning data?
Also take a look in the Browser Console CTRL+F12 and show if there are any errors. Also take a look at the Network tab.
Related
I'm trying to set up a Dropdown list in Kendo UI Grid using HTML helpers.
When I click to edit the grid, the dropdown appears and I can select a value. However, this does not save in the database when I click update (though the simple string WordName field does).
I would also like the CatId value from the WordViewModel to also be displayed as a word/dropdown when you're not editing the fields.
As far as I can tell, I have nothing which links the int CatId to the GetCategories list. How do I go about connecting those two? I've read a little about column.ForeignKey, but I don't understand it. Below is all my relevant code.
My WordViewModel (which loads from a similar, slightly more complex database model)
public class WordViewModel
{
public int WordId { get; set; }
[Required]
public string WordName { get; set; }
public Nullable<int> CatId { get; set; }
}
My Category model (generated by the database)
public partial class Category
{
public Category()
{
this.Words = new HashSet<Word>();
}
public int CatId { get; set; }
public string CategoryName { get; set; }
public bool IsActive { get; set; }
public virtual ICollection<Word> Words { get; set; }
}
Here's my razor code for the grid in Index.cshtml
#(Html.Kendo().Grid<WordViewModel>
()
.Name("wordGrid")
.DataSource(dataSource => dataSource
.Ajax()
.Model(model =>
{
model.Id(word => word.WordId); // Specify the property which is the unique identifier of the model
model.Field(word => word.WordId).Editable(false); // Make the ID property not editable
})
.Read(read => read.Action("Read", "Words")) //Populate the grid with Words
.Update(update => update.Action("Update", "Words")) // Action invoked when the user saves an updated data item
)
.Editable(editable => editable.Mode(GridEditMode.InLine)) // Use inline editing mode
.Columns(columns =>
{
columns.Bound(c => c.WordName);
columns.Bound(c => c.CatId).EditorTemplateName("_CategoryDropdown"); //link to EditorTemplate with the same name
columns.Command(commands =>
{
commands.Edit(); // The "edit" command will edit and update data items
}).Title("Commands").Width(200);
})
.Filterable()
)
Editor Template _CategoryDropdown.cshtml
#(
Html.Kendo().DropDownList()
.Name("Category") //is this Name important?
.DataTextField("CategoryName")
.DataValueField("CategoryId")
.DataSource(source =>
{
source.Read(read => { read.Action("GetCategories", "Words"); });
})
.OptionLabel("Select a category")
)
My function to get the drop down list from the database.
public JsonResult GetCategories()
{
var items = db.Categories.ToList().Select(c => new Category
{
CatId = c.CatId,
CategoryName = c.CategoryName
});
return Json(items, JsonRequestBehavior.AllowGet);
}
Here is a working solution. Rather than using column.ForeignKey, I ended up manually connecting the CatId with the CategoryName and including both in the WordViewModel.
My final files:
public class WordViewModel
{
public int WordId { get; set; }
[Required]
public string WordName { get; set; }
public string CategoryName { get; set; } //I added this field which is actually displayed on the grid
public Nullable<int> CatId { get; set; } //only used temporarily to transfer data
}
I did not end up referencing the Category model almost at all.
In my Grid I changed the binding on CategoryId to bind on CategoryName instead. Essentially with my solution, I only referenced Category Name in the view, and just matched up CategoryName with CategoryId in the Read/Update functions in the controller.
//The Title string below needs to be the same as the Name field in the EditorTemplate and possibly the same as the name in the model
columns.Bound(c => c.CategoryName).Title("CategoryName").EditorTemplateName("_CategoryDropdown");
The location of this file is important.
Views/Shared/EditorTemplates/_CategoryDropdown.cshtml:
#(
Html.Kendo().DropDownList()
.Name("CategoryName") //This name has to be the same as the Title on the main grid page
.DataTextField("CategoryName")
.DataValueField("CategoryName")
.DataSource(source =>
{
source.Read(read => { read.Action("GetCategories", "Words"); });
})
.OptionLabel("Select a category")
)
The Words/GetCategories function was correct.
I had to do some work in Words/Read to get the category name from the category ID
public ActionResult Read([DataSourceRequest] DataSourceRequest request)
{
var items = db.Words.Select(w => new WordViewModel
{
WordId = w.WordId,
CatId = w.CatId,
CategoryName = "",
WordName = w.WordName
}).ToList(); //need .ToList to be able to iterate through it
//finish building the word
foreach(var item in items)
{
if(item.CatId!=null)
{
//add CategoryName corresponding to each CatId
//In my database I have a table for Categories which matches up CatId to CategoryName
Category cat = db.Categories.Select(c => c).Where(c => c.CatId == item.CatId).FirstOrDefault();
item.CategoryName = cat.CategoryName;
}
}
return Json(items.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}
and some stuff in Words/Update to do the reverse Name->Id:
public ActionResult Update([DataSourceRequest]DataSourceRequest request, [Bind(Prefix = "models")] WordViewModel word)
{
if (ModelState.IsValid)
{
// Create a new Product entity and set its properties from the posted ProductViewModel
var entity = new Word
{
WordId = word.WordId,
CategoryName = word.CategoryName,
WordName = word.WordName
};
if (word.CategoryName != "")
{
//match CategoryWord to CatID
Category cat = db.Categories.Select(c => c).Where(c => c.CategoryName == word.CategoryName).FirstOrDefault();
entity.CatId = cat.CatId;
}
// Attach the entity
db.Words.Attach(entity);
// Change its state to Modified so Entity Framework can update the existing product instead of creating a new one
db.Entry(entity).State = EntityState.Modified;
// Update the entity in the database
db.SaveChanges();
}
// Return the updated product. Also return any validation errors.
return Json(new [] { word }.ToDataSourceResult(request, ModelState));
}
There might be some minor errors since this is a little simplified from my real code, but all the important pieces are there. Figuring out all the linkages and what I could depend on Kendo for vs what I had to manually was pretty difficult to figure out. Good luck to anyone else trying to use Kendo Grid, and I hope this example helps!
Nullable CatId is the problem. Check out the fix here Kendo MVC dropdown lists inside inline Kendo MVC grids. Second option is following but this one only works with InLine.
function onSave(e) {
// kendo nullable dropdown bug workaround
$("#wordGrid tbody [data-role=dropdownlist]").each(function () {
var kd = $(this).data("kendoDropDownList");
if (kd) {
var v = kd.value();
var p = kd.list.attr('id').replace('-list', '');
if(p) e.model.set(p, v);
}
})
}
There are also a suggestion to use default value but it never worked for me. see here
I have an entity Document:
public class Document : EntityBase
{
public Guid ID { get; set; }
public string Description { get; set; }
public string SourceLink{ get; set; }
public bool IsFile { get; set; }
}
and I am using the Kendo Grid InLine Edit Mode.
And now I want to make the Property string SourceLink editable, depending on bool IsFile.
That means the SourceLink should be editable if IsFile==false.
_documentsView.cshtml:
.DataSource(dataSource => dataSource
.Ajax()
.Events(events => events.Error("error"))
.Model(model =>
{
model.Id(o => o.ID);
model.Field(o => o.SourceLink).DefaultValue("");
model.Field(o => o.Description).DefaultValue("");
if (model.Field(o => o.IsFile) == true) {
model.Field(o => o.SourceLink).Editable(false)
}
else
{
model.Field(o => o.SourceLink).Editable(true)
}
}
)
//.Create(update => update.Action("GridEditingInlineCreate", "Document", new { area = "" }))
//.Read(...)
//...
)
Is there a possibility to get this if statement in the .Model statement working?
Or is it generally possible to use such a depending Editable feature?
Maybe in another way?
It sounds like you decided to go a different direction. You might consider using a template for that column that either disables the field or writes it as a label based on the IsFile. Otherwise, I think you're stuck with your current workaround since editability is set on the datasource and not at a row level.
One other consideration though - you might be able to use a shared editor template to write out the label instead of an Editor...
I am client-server, SQL programmer (RAD guy) and the company decided that we must move to .NET environment. We are examining the platform now.
I studied the MVC4 and the Entities Framework this week and I have read a lot about KendoUI. I was skeptical because most of the examples come with KendoGrid+WebApi. I know awfully little about WebApi but I really liked the Entities thing a lot so I do not think I should give it a chance.
I want to ask some question which may seem naive but the answers will help me a lot
Once I create entities from an existing database, can I have the results in Json format and with this to feed a KendoGrid?
If yes, how? I mean:
How I can convert the results in Json inside the Controller?
In the transport property of the KendoGrid I should put the URL of the Controller/Action?
and the most naive one
Does Telerik have any thoughts of providing a visual tool to create-configure the kendoGrid? To make it more RAD because now need TOO MUCH coding. Maybe a wizard that you can connect entities with Grid columns, datasource, transport selectors etc..
I hope you choose the Kendo Entities path, there will be a learning curve though. No, on question 4. But let me give you a jump start using the Razor view engine and answer 1, 2, and 3.
First, EF is creating business objects. You 'should' convert these to Models in MVC. In this example Person is from EF. I think of this as flattening because it removes the depth from the object, though it i still available so you could reference something like Person.Titles.Name if your database was setup like that. You can also drop in DataAnnotations, which just rock.
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Project.Business;
namespace Project.Web.Models
{
public class PersonModel
{
public int Id { get; set; }
[Required(ErrorMessage = "Last Name is required.")]
public string LastName { get; set; }
[Required(ErrorMessage = "First Name is required.")]
public string FirstName { get; set; }
[Display(Name = "Created")]
public System.DateTime StampCreated { get; set; }
[Display(Name = "Updated")]
public System.DateTime StampUpdated { get; set; }
[Display(Name = "Enabled")]
public bool IsActive { get; set; }
public PersonModel()
{}
public PersonModel(Person person)
{
Id = person.Id;
FirstName = person.FirstName;
LastName = person.LastName;
StampCreated = person.StampCreated;
StampUpdated = person.StampUpdated;
IsActive = person.IsActive;
}
public static IList<PersonModel> FlattenToThis(IList<Person> people)
{
return people.Select(person => new PersonModel(person)).ToList();
}
}
}
Moving along...
#(Html.Kendo().Grid<PersonModel>()
.Name("PersonGrid")
.Columns(columns => {
columns.Bound(b => b.Id).Hidden();
columns.Bound(b => b.LastName).EditorTemplateName("_TextBox50");
columns.Bound(b => b.FirstName).EditorTemplateName("_TextBox50");
columns.Bound(b => b.StampUpdated);
columns.Bound(b => b.StampCreated);
columns.Bound(b => b.IsActive).ClientTemplate("<input type='checkbox' ${ IsActive == true ? checked='checked' : ''} disabled />").Width(60);
columns.Command(cmd => { cmd.Edit(); cmd.Destroy(); }).Width(180);
})
.ToolBar(toolbar => toolbar.Create())
.Pageable()
.Filterable()
.Sortable()
.Selectable()
.Editable(editable => editable.Mode(GridEditMode.InLine))
.DataSource(dataSource => dataSource
.Ajax()
.Events(events => events.Error("error_handler"))
.Model(model =>
{
model.Id(a => a.Id);
model.Field(a => a.StampCreated).Editable(false);
model.Field(a => a.StampUpdated).Editable(false);
model.Field(a => a.IsActive).DefaultValue(true);
})
.Create(create => create.Action("CreatePerson", "People"))
.Read(read => read.Action("ReadPeople", "People"))
.Update(update => update.Action("UpdatePerson", "People"))
.Destroy(destroy => destroy.Action("DestroyPerson", "People"))
.PageSize(10)
)
)
Those _TextBox50 are EditorTemplates named _TextBox50.cshtml that MUST go either in a subfolder relative to your view or relative to your Shared folder - the folder must be called EditorTemplates. This one looks like this...
#Html.TextBox(string.Empty, string.Empty, new { #class = "k-textbox", #maxlength = "50" })
Yes, thats all. This is a simple example, they can get much more complicated. Or you don't have to use them initially.
And finally, what I think you are really looking for...
public partial class PeopleController : Controller
{
private readonly IPersonDataProvider _personDataProvider;
public PeopleController() : this(new PersonDataProvider())
{}
public PeopleController(IPersonDataProvider personDataProvider)
{
_personDataProvider = personDataProvider;
}
public ActionResult Manage()
{
>>> Left in as teaser, good to apply a special Model to a View to pass goodies ;)
var model = new PeopleViewModel();
model.AllQualifications = QualificationModel.FlattenToThis(_qualificationDataProvider.Read());
return View(model);
}
[HttpPost]
public JsonResult CreatePerson([DataSourceRequest]DataSourceRequest request, Person person)
{
if (ModelState.IsValid)
{
try
{
person = _personDataProvider.Create(person);
}
catch (Exception e)
{
ModelState.AddModelError(string.Empty, e.InnerException.Message);
}
}
var persons = new List<Person> {person};
DataSourceResult result = PersonModel.FlattenToThis(persons).ToDataSourceResult(request, ModelState);
return Json(result, JsonRequestBehavior.AllowGet);
}
public JsonResult ReadPeople([DataSourceRequest]DataSourceRequest request)
{
var persons = _personDataProvider.Read(false);
DataSourceResult result = PersonModel.FlattenToThis(persons).ToDataSourceResult(request);
return Json(result, JsonRequestBehavior.AllowGet);
}
[HttpPost]
public JsonResult UpdatePerson([DataSourceRequest]DataSourceRequest request, Person person)
{
if (ModelState.IsValid)
{
try
{
person = _personDataProvider.Update(person);
}
catch (Exception e)
{
ModelState.AddModelError(string.Empty, e.InnerException.Message);
}
}
var persons = new List<Person>() {person};
DataSourceResult result = PersonModel.FlattenToThis(persons).ToDataSourceResult(request, ModelState);
return Json(result, JsonRequestBehavior.AllowGet);
}
[HttpPost]
public JsonResult DestroyPerson([DataSourceRequest]DataSourceRequest request, Person person)
{
if (ModelState.IsValid)
{
try
{
person = _personDataProvider.Destroy(person);
}
catch (Exception e)
{
ModelState.AddModelError(string.Empty, "There was an error deleting this record, it may still be in use.");
}
}
var persons = new List<Person>() {person};
DataSourceResult result = PersonModel.FlattenToThis(persons).ToDataSourceResult(request, ModelState);
return Json(result, JsonRequestBehavior.AllowGet);
}
}
Notice that, in this case, each method takes the EF Person as a parameter, it would be better to use PersonModel but then I would have to show the opposite of the Flatten. This works becuase they are practically identical. If the model was different or you were using a class factory it gets a bit more tricky.
I intentionally showed you all the CRUD operations. If you don't pass the result back to the grid it will act funny and give you dupicates or not show updates correctly on CREATE and UPDATE. It is passed back on DELETE to pass the ModelState which would have any errors.
And finally the data provider, so as to leave nothing to the imagination...
(Namespace declaration omited.)
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using Project.Business;
public class PersonDataProvider : ProviderBase, IPersonDataProvider
{
public Person Create(Person person)
{
try
{
person.StampCreated = DateTime.Now;
person.StampUpdated = DateTime.Now;
Context.People.Attach(person);
Context.Entry(person).State = EntityState.Added;
Context.SaveChanges();
return person;
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
throw;
}
}
public IList<Person> Read(bool showAll)
{
try
{
return (from q in Context.People
orderby q.LastName, q.FirstName, q.StampCreated
where (q.IsActive == true || showAll)
select q).ToList();
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
throw;
}
}
...
}
Note the Interface and ProviderBase inheritance, you have to make those. Should be simple enough to find examples.
This may seem like a lot of coding, but once you get it down, just copy paste.
Happy coding.
yes you can send the JSON back kendo UI using the JsonResult or using the JSON with allow get specified. you can set the url in the transport and specify the json as the type.
About your last question there is no visual tools right now but there are helper methods available for kendo UI
OK...I've spent too much time floundering on this one, so I'm passing it on to the experts -> YOU.
My VERY simple ASP.NET MVC (v3 with Razor View Engine) page uses a Telerik Rad Grid control to show some type lists and then I have the associated codes showing in the DetailsView of the grid.
Doing the population is easy. I have a ViewModel for my TypeCodeList type and send it to the strongly typed view to populate the grid. This works GREAT...and the grid looks great - thanks Telerik. However, I added the DetailsView to then populate the child TypeCodes in the same manner. The bad thing is that when my grid populates, I select the triangle on the left to expand the tree and see the child records, nothing is there. BUT, if I select the "Refresh" button on the bottom of the grid, THEN I can hit the triangle and the child records display.
So (in summary), the child records do not show up on the initial load. Only when I select an AJAX refresh of the grid I get the children. Otherwise, it works as required.
I have been trying to see if I can programmatically kick off the refresh via javascrip upon page load. OR if I can get the thing to populate by itself when selected without doing a refresh first - that would be preferable.
Below is my code:
Pertinent Controller Code (I've taken out the update, delete, insert, logging and data access methods)
[HandleErrorWithElmah]
public partial class HostController : Controller
{
/// <summary>
/// Index - Home for HostController
/// </summary>
/// <returns></returns>
public ActionResult Index()
{
return View();
}
#region Type List Section
/// <summary>
/// Gets the list of TypeLists - yea...say that again
/// </summary>
[GridAction]
public ActionResult TypeCodeList()
{
var model = GetActiveTypeLists();
// Get all of the type lists and send them to the view
return View(model);
}
/// <summary>
/// The ajaxified Select
/// </summary>
/// <returns></returns>
[AcceptVerbs(HttpVerbs.Post)]
[GridAction]
public ActionResult _TypeCodeList()
{
var model = GetActiveTypeLists();
return Json(new GridModel(model));
}
/// <summary>
/// Simply a wrapper to get all of the current type list values.
/// </summary>
/// <returns></returns>
private IEnumerable<TypeCodeListViewModel> GetActiveTypeLists()
{
var model = from p in entityRepository.Find<TypeList>(p => p.IsActive == true)
select new TypeCodeListViewModel
{
TypeListId = p.TypeListId,
Name = p.Name,
Description = p.Description,
IsActive = p.IsActive
};
return model;
}
#endregion
#region Type Code Section
[AcceptVerbs(HttpVerbs.Post)]
[GridAction]
public ActionResult _TypeCodeForTypeListAjax(int typeListId)
{
var model = GetActiveTypeCodes(typeListId);
return Json(new GridModel(model));
}
/// <summary>
/// Simply a wrapper to get all of the current type Code values.
/// </summary>
/// <returns></returns>
private IEnumerable<TypeCodeViewModel> GetAllActiveTypeCodes()
{
var model = from p in entityRepository.Find<OurLeaguePlay.Models.TypeCode>(p => p.IsActive == true).OrderBy(ord => ord.CodeName)
select new TypeCodeViewModel
{
TypeCodeId = p.TypeCodeId,
TypeListId = p.TypeListId,
CodeName = p.CodeName,
CodeValue = p.CodeValue,
Description = p.Description,
IsActive = p.IsActive
};
return model;
}
/// <summary>
/// Simply a wrapper to get all of the current type Code values.
/// </summary>
/// <returns></returns>
private IEnumerable<TypeCodeViewModel> GetActiveTypeCodes(int typeListId)
{
var model = from p in entityRepository.Find<OurLeaguePlay.Models.TypeCode>(p => p.IsActive == true &&
p.TypeListId == typeListId).OrderBy(ord => ord.CodeName)
select new TypeCodeViewModel
{
TypeCodeId = p.TypeCodeId,
TypeListId = p.TypeListId,
CodeName = p.CodeName,
CodeValue = p.CodeValue,
Description = p.Description,
IsActive = p.IsActive
};
return model;
}
#endregion
}
Here is my View Code:
(I've taken out all of my failed javascript attempts to try and force the load on page load.)
#model IEnumerable<TypeCodeListViewModel>
#using Telerik.Web.Mvc.UI
#using Telerik.Web.Mvc
#using OurLeaguePlay.ViewModels
#{Html.Telerik().Grid<TypeCodeListViewModel>(Model)
.Name("TypeLists")
.DetailView(details => details.ClientTemplate(
Html.Telerik().Grid<TypeCodeViewModel>()
.Name("TypeCode_<#= TypeListId #>")
.DataKeys(keys => keys.Add(k => k.TypeCodeId))
.Columns(columns =>
{
columns.Bound(o => o.CodeName).Width(40);
columns.Bound(o => o.CodeValue).ReadOnly(true).Width(40);
columns.Bound(o => o.Description).Width(100);
})
.DataBinding(dataBinding =>
{
dataBinding.Ajax().Select("_TypeCodeForTypeListAjax", "Host", new { typeListId = "<#= TypeListId #>" })
.Enabled(true);
}
)
.Pageable()
.Sortable()
.NoRecordsTemplate("No Type Codes exist for the selected Type List")
.ToHtmlString()
)
)
.DataKeys(keys => keys.Add(k => k.TypeListId))
.Columns(columns =>
{
columns.Bound(o => o.Name).Width(100);
columns.Bound(o => o.Description).Width(150);
columns.Command(commands =>
{
commands.Edit().ButtonType(GridButtonType.Image);
commands.Delete().ButtonType(GridButtonType.Image);
}
).Width(30);
})
.DataBinding(dataBinding =>
{
dataBinding.Ajax().Select("_TypeCodeList", "Host")
.Update("UpdateTypeList", "Host")
.Insert("InsertTypeList", "Host")
.Delete("DeleteTypeList", "Host")
.Enabled(true);
dataBinding.Server().Select("TypeCodeList", "Host", new { ajax = ViewData["ajax"] });
}
)
.Editable(editable => editable.Enabled(true).Mode(GridEditMode.InLine))
.Pageable(page => page.PageSize(10))
.Sortable()
.Selectable()
.Scrollable(scroll => scroll.Enabled(false))
.NoRecordsTemplate("No Type Lists can be retrieved from the database")
.ToolBar(commands => commands.Insert())
.Render();
}
Finally...here are the ViewModel classes:
public class TypeCodeListViewModel
{
[ScaffoldColumn(false)]
public int TypeListId { get; set; }
[Required(ErrorMessage = "Required")]
[StringLength(25, ErrorMessage = "Max Length is 25")]
public string Name { get; set; }
[Required(ErrorMessage = "Required")]
[StringLength(25, ErrorMessage="Max Length is 25")]
public string Description { get; set; }
[ScaffoldColumn(false)]
public bool IsActive { get; set; }
}
public class TypeCodeViewModel
{
[ScaffoldColumn(false)]
public int TypeCodeId { get; set; }
[ScaffoldColumn(false)]
public int TypeListId { get; set; }
[Required(ErrorMessage = "Required")]
[StringLength(25, ErrorMessage = "Max Length is 25")]
[DisplayName("Name")]
public string CodeName { get; set; }
[Required(ErrorMessage = "Required")]
[StringLength(25, ErrorMessage = "Max Length is 25")]
[DisplayName("Value")]
public string CodeValue { get; set; }
[StringLength(500, ErrorMessage = "Max Length is 500")]
public string Description { get; set; }
[ScaffoldColumn(false)]
public bool IsActive { get; set; }
}
Well...I think I figured it out on my own...it was as simple as just letting the grid bind itself and not forcing data into it via the non-ajax method that gets called upon initial display of the page.
The
Public ActionResult TypeCodeList()
function should simply be updated to the following:
Public ActionResult TypeCodeList()
{
return View();
}
with no [GridAction] decorator.
If you don't force values into the grid, it will bind itself using the Ajax method and then the child grids will populate upon expansion.
Let me preface this by saying I'm fairly new to ASP.NET MVC. I've decided to use Telerik's ASP.NET MVC extensions http://www.telerik.com/products/aspnet-mvc.aspx
I would like to hear from you a recommendation how to handle the following situation.
I have a model POCO class called Print.
public class Print
{
public int Id { get; set; }
public DateTime Date { get; set; }
public PrintStatus Status { get; set; }
}
I'm passing collection of objects of this class to view in order to show it on the Grid.
The view looks as follows:
...
#{
var grid = Html.Telerik().Grid(Model)
.Name("Grid")
.DataKeys(keys =>
{
keys.Add(o => o.Id);
})
.Columns(columns =>
{
columns.Bound(o => o.Date).Title(ModRes.Print.Date);
columns.Bound(o => o.Status)).Title(ModRes.Print.Status);
})
.DataBinding(dataBinding =>
{
dataBinding.Server().Select("Index", "Print")
.Insert("Insert", "Print")
.Update("Save", "Print")
.Delete("Delete", "Print");
})
.Sortable()
.Pageable()
.Filterable()
.Groupable()
.Footer(true);
}
#grid
...
The relevant line is this:
columns.Bound(o => o.Status)).Title(ModRes.Print.Status);
As you can see the grid is going to use Status property, which is an enumeration. However this leads to a question on how to localize it i.e. How to show different translations of the Status property.
My thought is to inherit from Print class and allow additional string property which would hold the tranlation and alow to create Print class from it in the background (I heard that Automapper library might be helpful with this). This, however, seems like an ugly solution for me.
Thank you for your input.
Create an instance of a ResourceManager and use the print status as a lookup key to a resource file. Or if you are localizing in a database do the same thing to the DB. If you need it to be more specific of a key then add a prefix of some sort.
This link might help:
http://msdn.microsoft.com/en-us/library/c6zyy3s9.aspx