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

Kendo UI Grid Foreign Key dropdownlist

2 Answers 1141 Views
Grid
This is a migrated thread and some comments may be shown as answers.
Johann
Top achievements
Rank 1
Johann asked on 21 Aug 2015, 10:31 AM

Hi There

I've been trying to get this right, and none of the demos or forums posts appear to really give me a clear answer.

I'm trying to populate a dropdownlist from a related table (Foreign Key), and I'm getting a "Value cannot be null" error.

 

Here's the scenario:

I have a Courses and Cities table, defined like this,

public class City
  {
      [Key]
      [ScaffoldColumn(false)]
      public int CityId { get; set; }
 
      [Required]
      [DisplayName("City Name")]
      public string CityName { get; set; }
 
      public virtual ICollection<Course> Courses { get; set; }
  }

and this:

public class Course
  {
      [Key][ScaffoldColumn(false)]
      public int CourseId { get; set; }
 
      [Required]
      public string CourseName { get; set; }
 
      [ForeignKey("City")]
      [UIHint("GridForeignKey")]
      public int CityId { get; set; }
      public virtual City City { get; set; }
 
      [Required]
      [DisplayName("Course Rating")]
      [Range(0, 10)]
      public double CourseRating { get; set; }
 
      [Required]
      [DisplayName("Course Par")]
      public double CoursePar { get; set; }
 
      [DisplayName("Course Map Co-ords")]
      public string CourseMap { get; set; }
 
      [DisplayName("Course Notes")]
      public string CourseNotes { get; set; }
 
      public virtual ICollection<GolfRound> GolfRounds { get; set; }
 
 
  }

So, clearly it's just a Golf Score app I'm using to help me learn.

 I've scaffolded the Controller and Views using Kendo Scaffolder, and ended up with this:

public class CourseController : Controller
  {
      private GolfContext db = new GolfContext();
 
      public ActionResult Index()
      {
          return View();
      }
 
      public ActionResult Courses_Read([DataSourceRequest]DataSourceRequest request)
      {
          IQueryable<Course> courses = db.Courses;
          DataSourceResult result = courses.ToDataSourceResult(request, course => new
          {
              CourseId = course.CourseId,
              CourseName = course.CourseName,
              CourseRating = course.CourseRating,
              CoursePar = course.CoursePar,
              CourseMap = course.CourseMap,
              CourseNotes = course.CourseNotes
          });
 
          return Json(result);
      }
 
      [AcceptVerbs(HttpVerbs.Post)]
      public ActionResult Courses_Create([DataSourceRequest]DataSourceRequest request, Course course)
      {
          if (ModelState.IsValid)
          {
              var entity = new Course
              {
                  CourseName = course.CourseName,
                  CourseRating = course.CourseRating,
                  CoursePar = course.CoursePar,
                  CourseMap = course.CourseMap,
                  CourseNotes = course.CourseNotes
              };
 
              db.Courses.Add(entity);
              db.SaveChanges();
              course.CourseId = entity.CourseId;
          }
 
          return Json(new[] { course }.ToDataSourceResult(request, ModelState));
      }
 
      [AcceptVerbs(HttpVerbs.Post)]
      public ActionResult Courses_Update([DataSourceRequest]DataSourceRequest request, Course course)
      {
          if (ModelState.IsValid)
          {
              var entity = new Course
              {
                  CourseId = course.CourseId,
                  CourseName = course.CourseName,
                  CourseRating = course.CourseRating,
                  CoursePar = course.CoursePar,
                  CourseMap = course.CourseMap,
                  CourseNotes = course.CourseNotes
              };
 
              db.Courses.Attach(entity);
              db.Entry(entity).State = EntityState.Modified;
              db.SaveChanges();
          }
 
          return Json(new[] { course }.ToDataSourceResult(request, ModelState));
      }

 

and for the View:


@(Html.Kendo().Grid<GolfScoreMVC.Models.Course>()
      .Name("grid")
      .Columns(columns =>
      {
          columns.Bound(c => c.CourseName);
          columns.Bound(c => c.CourseRating);
          columns.Bound(c => c.CoursePar);
          columns.Bound(c => c.CourseMap);
          columns.Bound(c => c.CourseNotes);
          columns.ForeignKey(c => c.City, ( System.Collections.IEnumerable ) ViewData["Cities"], "CityId", "CityName");
          columns.Command(command => { command.Edit(); command.Destroy(); }).Width(180);
      })
      .ToolBar(toolbar =>
      {
          toolbar.Create();
      })
      .Editable(editable => editable.Mode(GridEditMode.PopUp))
      .Pageable()
      .Sortable(sortable =>
      {
          sortable.SortMode(GridSortMode.SingleColumn);
      })
      .Filterable()
      .Scrollable()
      .DataSource(dataSource => dataSource
          .Ajax()
          .Model(model => model.Id(p => p.CourseId))
          .Read(read => read.Action("Courses_Read", "Course"))
          .Create(create => create.Action("Courses_Create", "Course"))
          .Update(update => update.Action("Courses_Update", "Course"))
          .Destroy(destroy => destroy.Action("Courses_Destroy", "Course"))
      )
)

Now, initially the CityId column was not scaffolded at all, but in the Create popup, I got a CityId input field.

I added the "columns.ForeignKey(c => c.City, ( System.Collections.IEnumerable ) ViewData["Cities"], "CityId", "CityName");" part to try and produce a dropdownlist, but I'm not getting it right.

 

I'm using the default GridForeignKey template template file, and when rendering this, is where the error comes in.

 Please help me. The standard demo here confuses me even more.

Am I supposed to create a list of the Cities first, like this?

private GolfContext db = new GolfContext();
 
      public ActionResult Index()
      {
          IList<City> myCities = db.Cities.ToList();
 
          ViewData["Cities"] = myCities;
 
 
          return View();
      }

That doesn't work either. I'm clearly missing some obvious and simple step.

 

Regards

JohannS

 

 

 

 

2 Answers, 1 is accepted

Sort by
0
Johann
Top achievements
Rank 1
answered on 21 Aug 2015, 12:34 PM

I've now changed the EditorTemplate to a custom one like this:

@model Int32
 
@(Html.Kendo().DropDownListFor(m => m)
    .DataValueField("CityId")
    .DataTextField("CityName")
    .OptionLabel("- Choose City -")
    .DataSource(ds => ds.Read("Cities_Read", "City"))
)

and changed the Model class's [UIHint] annotation to point to the new Editor. This now allows the form to render. But now I can't submit any new records, nor does it display any values in the Dropdownlist that is rendered in the Edit window.

 

 

0
Boyan Dimitrov
Telerik team
answered on 25 Aug 2015, 07:32 AM

Hello Johann,

 

The main idea is to bind the ForeignKey to the CityId field of the model. This field stores/holds the id value of the City object. 

 

I noticed that in the provided code the ForeignKey column is bound to City field of the model instead of the CityId. 

 

Regards,
Boyan Dimitrov
Telerik
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 Feedback Portal and vote to affect the priority of the items
Tags
Grid
Asked by
Johann
Top achievements
Rank 1
Answers by
Johann
Top achievements
Rank 1
Boyan Dimitrov
Telerik team
Share this question
or