Three ways to populate selected value in DropDownList on Edit or Update views - MVC
I
have been asked this question many times that ‘how to populate/activate selected
value/item (which I selected while inserting/adding new record) in Edit/Update
mode’. I’m going to address few possible approaches here.
So, we are going to create this (look at the image) where I’m able to see the selected value on Edit page.
So, we are going to create this (look at the image) where I’m able to see the selected value on Edit page.
Let’s
start with the best conventional way to do this:
First Approach
This
approach is very-very easy and most suggested to this when you are working with
code first to generate initial database and views using Entity Framework.
Always
design conceptual model classes this way:
public class Student
{
public int Id { get; set; }
public string StudentName { get; set; }
public int SubjectId { get; set; }
public Subject Subject { get; set; }
}
public class Subject
{
public int Id { get; set; }
public string SubjectName { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
public class StudentContext : DbContext
{
public StudentContext()
: base("name=DDLinEditModeConnection")
{
}
public DbSet<Student> Students { get; set; }
public DbSet<Subject> Subjects { get; set; }
}
In
above code, look at the highlighted part, Student class has StudentId as a
field/property and Subject as a navigation property.
Please
maintain the naming convention (like I used ‘StudentId’) so that by looking at the
conceptual model EF generates the right view (with working DropDownList) for
you and populates it with right data (subjects).
Once
you have conceptual model classes designed by above suggested convention, you
can go ahead and add CRUD views using Entity Framework to get fully functional
DropDownList even in Edit/Update mode on the fly.
Second Approach
You
can use this approach when you have database already or you are working with
database first or database design has no such conceptual settings (relationships)
like I discussed in above approach.
public class Student
{
public int Id { get; set; }
public string StudentName { get; set; }
public string SubjectName { get; set; }
}
public class Subject
{
public int Id { get; set; }
public string SubjectName { get; set; }
}
public class StudentContext : DbContext
{
public StudentContext()
: base("name=DDLinEditModeConnection")
{
}
public DbSet<Student> Students { get; set; }
public DbSet<Subject> Subjects { get; set; }
}
By
looking at the above model classes design anyone can say it has no relation or
navigation properties, right. So, above model will generate following database
for sure.
Now
generate CRUD views using Entity Framework based on above models, you will face
following Create and Edit pages.
I
don’t have DropDownList up in above pages, even after adding few subjects.
When
I opened Create and Edit views, I noticed following helper.
@Html.EditorFor(model => model.SubjectName)
This
is just fine, the main problem is with model class designs. We failed to
provide good model class convention to EF, now what to do?
What
Next?
Let’s
do workaround.
Step 1
Open
Student controller and make following changes (changes are highlighted) in
Create action.
private StudentContext db = new StudentContext();
public ActionResult Create()
{
ViewBag.SubjectName = new SelectList(db.Subjects, "SubjectName",
"SubjectName");
return View();
}
In
above code I just added a ViewBag.SubjectName that will contain the list of
SubjectNames and we will bind this on the Create.cshtml view as given below.
<div class="editor-field">
@*@Html.EditorFor(model => model.SubjectName)*@
@Html.DropDownList("SubjectName")
@Html.ValidationMessageFor(model => model.SubjectName)
</div>
Step 2
Open
Student controller and make following changes (changes are highlighted) in Edit
action.
private StudentContext db = new StudentContext();
public ActionResult Edit(int id = 0)
{
string selected = (from sub in db.Students
where sub.Id == id
select
sub.SubjectName).First();
ViewBag.SubjectName = new SelectList(db.Subjects, "SubjectName",
"SubjectName", selected);
Student student = db.Students.Find(id);
if (student == null)
{
return HttpNotFound();
}
return View(student);
}
In
above code, I’m checking what the selected value was using LINQ query and then
using that value inside SelectList. Now, DropDownList will look at the provided
default selected value and displays it.
<div class="editor-field">
@*@Html.EditorFor(model => model.SubjectName)*@
@Html.DropDownList("SubjectName")
@Html.ValidationMessageFor(model => model.SubjectName)
</div>
Step 3
Run
the application, you will get same experience like we had in first approach.
You will have working DDL everywhere.
Third Approach
This
approach will be very similar to second one, here we will use Enum instead of
Subject model class. This approach will be useful if you don’t want another
database table to store list of subjects and to go simple.
Step 1
Design
model class this way:
public class Student
{
public int Id { get; set; }
public string StudentName { get; set; }
public string SubjectName { get; set; }
}
//public
class Subject
//{
// public int Id { get; set; }
// public string SubjectName { get; set; }
//}
public enum SubjectEnum
{
Computer_Science, Mathematics, Chemistry,
Physics, Biology
}
public class StudentContext : DbContext
{
public StudentContext()
: base("name=DDLinEditModeConnection")
{
}
public DbSet<Student> Students { get; set; }
//public
DbSet<Subject> Subjects { get; set; }
}
In
above code, you can see I commented out Subject class and its DbSet and used a
new SubjectEnum to store the list of subjects. Don’t worry about the underscore
(_) signed I used with subject name, I’ll replace it with white space in
controller action.
Step 2
Once
you have above model class, generate the CRUD views and make following changes
in Create action method:
public ActionResult Create()
{
var subjects = from SubjectEnum s in Enum.GetValues(typeof(SubjectEnum))
select new { Name =
s.ToString().Replace('_', ' ') };
ViewBag.SubjectName = new SelectList(subjects, "Name", "Name");
return View();
}
In
above controller action, I used LINQ query to query the Enum and replaced the
underscore (_) character with white space.
Now,
on the Create.cshtml view page, use following:
<div class="editor-field">
@*@Html.EditorFor(model => model.SubjectName)*@
@Html.DropDownList("SubjectName",
"")
@Html.ValidationMessageFor(model => model.SubjectName)
</div>
Step 3
Make
following changes in Edit action method:
public ActionResult Edit(int id = 0)
{
var subjects = from SubjectEnum s in Enum.GetValues(typeof(SubjectEnum))
select new { Name =
s.ToString().Replace('_', ' ') };
string selected = (from sub in db.Students
where sub.Id == id
select
sub.SubjectName).First();
ViewBag.SubjectName = new SelectList(subjects, "Name", "Name",
selected);
Student student = db.Students.Find(id);
if (student == null)
{
return HttpNotFound();
}
return View(student);
}
One
thing new here, to populating the previous selection as a selected value in DDL
use following on Edit.cshtml view page:
<div class="editor-field">
@*@Html.EditorFor(model => model.SubjectName)*@
@Html.DropDownList("SubjectName",
"")
@Html.ValidationMessageFor(model => model.SubjectName)
</div>
Step 4
Run
the application, you will get same experience like in first and second
approach. You will have working DDL everywhere.
You
can also do this by taking advantage of Razor extension methods.
Hope
this helps.
Thank you for great article. It was very helped me.
ReplyDeleteWhen using ddl like this @Html.DropDownList("SubjectName", "") in view cant store to db.
ReplyDeletewhen using in this syntax @Html.DropDownListFor(m => m.Color, new SelectList(ViewBag.Colors, "Value", "Text"), "") storing value to db but when enum with "_" symbol also doesnt work. why?
Got an idea.
ReplyDeleteFirst method is not working, it creates an editFor for the subjectId. I'm following all the name conventions and I'm using visual studio 2013 and MVC 4.
ReplyDeleteReading the second method, since it mirrors what I have already in an application, and I'm noticing that you don't specify in the Create() how to access the data for the ViewBag. What am I specifically missing here?
ReplyDeleteExcellent it solved my purpose
ReplyDeleteExcellent solution
ReplyDeleteExcellent solutions... Thank you
ReplyDeleteHi, i've followed the second approach but it is not working. what's the problem with my codes? any suggestions thanks :)
ReplyDeletehere's my code
Model:
public class JobRequestList
{
public int ID { get; set; }
public string Status { get; set; }
}
public class StatusList
{
public int ID { get; set; }
public string Status { get; set; }
public string statusDes { get; set; }
}
controller:
public ActionResult Edit(int? id = 0)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
string selected = (from sub in db.RequestModels
where sub.ID == id
select sub.Status).First();
ViewBag.Status = new SelectList(db.StatusList, "Status", "statusDes", selected);
JobRequestList jobRequestList = db.RequestModels.Find(id);
if (jobRequestList == null)
{
return HttpNotFound();
}
return View(jobRequestList);
}
View :
@Html.LabelFor(model => model.Status, htmlAttributes: new { @class = "control-label col-md-3" })
@Html.DropDownList("Status", (IEnumerable)ViewBag.Status, new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.Status, "", new { @class = "text-danger" })
This is what i m finding from last many days and its works for me thanks man..!
ReplyDelete