ASP.NET Core - MVC. Drop down populate issue - asp.net-mvc

I'm using vs 2017 and chrome.
I have an ASP.Net Core MVC app. It has a drop down that isn't showing the items correctly. The items displayed should be: Comedy, Western and Romantic.
Here's the debug image. The items shows the array and the text {MvcMovie.Modesl.Genre} and as I click each, the item text shows as I want.
I select the genres from the database and return them as as List and cast it to a SelectList as that is what is it is rendered as HTML a element with the collection of SelectListItem objects.
However, when I look at the Raw View, I only see the text {MvcMovie.Modesl.Genre} which is what is being shown in the drop down.
I populate the movieGenreVM and return it as a view in the Index action method.
public IActionResult Index(string movieGenre, string searchStringEntered)
{
// A list of genre objects.
SelectList genresList;
// A list of movie objects.
List<Movie> moviesList;
// Instantiate the View model.
var movieGenreVM = new MovieGenreViewModel();
// Get a list of genres from the database.
genresList = new SelectList(GetGenres(movieGenre));
// Get a list of movies from the database.
moviesList = GetMovies(searchStringEntered);
// Sets the models property which is then used in the dropdown of Genres.
movieGenreVM.genres = genresList;
// Creates a List object.
// Movie is populated from the database and used to generate an HTML table of loaded movies.
movieGenreVM.movies = moviesList;
// Passing the MovieGenreViewModel.
// Return the IActionResult - the Index.cshtml. A view template to generate an HTML response to the browser.
return View(movieGenreVM);
}
namespace MvcMovie.Models
{
public class MovieGenreViewModel
{
// A list of movies.
public List<Movie> movies;
// A SelectList containing the list of genres.
public SelectList genres;
// Contains the selected genre.
public string movieGenre { get; set; }
}
}
The genre models is:
public class Genre
{
public string MovieGenre { get; set; }
// Constructor.
public Genre()
{
}
public Genre(string a_MovieGenre)
{
MovieGenre = a_MovieGenre;
}
}
Here's the population of the genre list code:
// Create a list of genres.
private List<Genre> _genre = new List<Genre>();
public List<Genre> Genre
{
get
{
return _genre;
}
}
public List<Genre> GetGenres(string movieGenre)
{
Boolean errorSw = false;
// Declare the reader and initialize.
SqlDataReader GenresDataReader = null;
try
{
// Open the connection.
dbFunc.OpenDB();
// Get the list of distinct Genres by executing a stored procedure.
SqlCommand GenresCmd = new SqlCommand("dbo.SelectGenres", dbFunc.objConn);
GenresCmd.Parameters.Clear();
GenresCmd.CommandType = CommandType.StoredProcedure;
GenresCmd.Parameters.Add("#SearchText", SqlDbType.VarChar).Value = movieGenre;
// Set the reader.
GenresDataReader = GenresCmd.ExecuteReader();
// Loop thru the results returned.
while (GenresDataReader.Read())
{
// Add to the list of genres - creates a new row for the collection.
Genre.Add(new Genre(GenresDataReader["Genre"].ToString()));
}
}
catch (Exception ex)
{
errorSw = true;
}
finally
{
if (GenresDataReader != null)
{
GenresDataReader.Close();
}
dbFunc.CloseDB();
}
// Return the list of genre objects.
return Genre;
}
Here's the view:
#model MvcMovie.Models.MovieGenreViewModel
#{
ViewData["Title"] = "Index";
}
<h2>List of Movies</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<form asp-controller="Movies" asp-action="Index" method="get">
<p>
#* A dropdown. *#
<select asp-for="movieGenre" asp-items="Model.genres">
<option value="">All</option>
</select>
Title: <input type="text" name="searchStringEntered">
<input type="submit" value="Filter" />
</p>
</form>
#* Shows the list of movies. *#
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.movies[0].Title)
</th>
<th>
#Html.DisplayNameFor(model => model.movies[0].ReleaseDate)
</th>
<th>
#Html.DisplayNameFor(model => model.movies[0].Genre)
</th>
<th>
#Html.DisplayNameFor(model => model.movies[0].Price)
</th>
<th>
#Html.DisplayNameFor(model => model.movies[0].Rating)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.movies) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
<td>
#Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
#Html.DisplayFor(modelItem => item.Price)
</td>
<td>
#Html.DisplayFor(modelItem => item.Rating)
</td>
<td>
<a asp-action="Edit" asp-route-id="#item.ID">Edit</a> |
<a asp-action="Details" asp-route-id="#item.ID">Details</a> |
<a asp-action="Delete" asp-route-id="#item.ID">Delete</a>
</td>
</tr>
}
</tbody>
</table>
This tutorial is using Entity Framework but I am converting it to using ADO.net and stored procedures. The EF version of the drop down works fine.
Here is the the EF versions Index action method. The genre is just the text - no Id associated with it.
public async Task<IActionResult> Index(string movieGenre, string searchStringEntered)
{
IQueryable<string> genreQuery = from m in _context.Movie
orderby m.Genre
select m.Genre;
var movies = from m in _context.Movie
select m;
if (!String.IsNullOrEmpty(searchStringEntered))
{
movies = movies.Where(s => s.Title.Contains(searchStringEntered));
}
if (!String.IsNullOrEmpty(movieGenre))
{
movies = movies.Where(x => x.Genre == movieGenre);
}
// Instantiate the model.
var movieGenreVM = new MovieGenreViewModel();
// The SelectList of genres is created by projecting the distinct genres.
// Sets the models property which is then used in the dropdown of Genres.
movieGenreVM.genres = new SelectList(await genreQuery.Distinct().ToListAsync());
// Creates a List object.
// Movie is populated from the database and used to generate an HTML table of loaded movies.
movieGenreVM.movies = await movies.ToListAsync();
return View(movieGenreVM);
}

From your screenshot, it is clear that your SelectList is missing the DataTextField and DataValueField. So the SELECT tag helper do not know which property should be used for the text and which should be used for Value.
The solution is to specifiy it when you create the SelectList object.Since your Genre entity class has only one property MovieGenre, you can use that for both Text and Value
var generesList = new SelectList(GetGenres(movieGenre),"MovieGenre","MovieGenre");
var vm=new MovieGenreViewModel { genres= generesList};
return View(vm);
Now in your view, you can use Select tag helper with this genres property
#model MovieGenreViewModel
<select asp-for="movieGenre" asp-items="#Model.genres"></select>
The select tag helper will use the DataValueField property value for the option value attribute and DataTextField property value for the option text.
Or Since you only have one property in your enter code hereGenre class, you can pass the list of strings to the SelectList constructor. The below will also work.
var gList=GetGenres(movieGenre);
var generesList = new SelectList(gList.Select(a=>a.MovieGenre));
var vm=new MovieGenreViewModel { genres= generesList};
return View(vm);
Here is a post explaining different options to use the SELECT tag helper, for your reference
Select Tag Helper in ASP.NET Core MVC

This is an example of how I do it:
var items = GetItemsFromDB();
var vals = new List<SelectListItem> {new SelectListItem {Selected = true, Text = "--Select an Item--", Value = "0"}};
vals.AddRange(items.Select(item => new SelectListItem
{
Selected = false, Text = item.Type, Value = item.Id.ToString()
}));
var result = new SelectList(vals, "Value", "Text");
As you can see when i convert it to a SelectList I specify the Value and Text as dataValueField and dataTextField.
In your case you need properties for these values and specify them when you "cast it" using the SelectList constructor.
In my view I do this:
<select asp-for="Model.ItemId" asp-items="Model.MyItemSelectList"></select>
Where Model.MyItemSelectList can be a List of SelectListItem
Another way to bind it to a collection is like this:
<select asp-for="Model.MyItemId">
<option value="">-- Select Item --</option>
#{
foreach (var item in Model.MyItems)
{
<option value="#item.Key">#item.Value</option>
}
}
</select>
Where item has Key and Value properties. The properties can be names whatever you want. In this case "item" has those properties.

Related

MVC DropDownList lagging

I am posting the id of a dropdownlist back to the index (index2 view). but is lagging behind. After a second time pressing Select it shows me the correct list.
http://www.jeroenchristens.be/CountriesWorld
(the first page is only for showing the complete list, after selecting from the dropdownlist,, it gets to index2, a shorter list) And then after choosing another Selection from the dropdownlist, you have to try this twice each time.
I successfully copied this from the id the value and pass this on, why is it lagging behind.
Index2 Viewpage
#using System.Collections
#using System.Web.UI.WebControls
#model IEnumerable<CVtje.Models.Countries>
<h2>Index</h2>
#using (Html.BeginForm("Index2", "CountriesWorld", new { #id = Request.Form["SelectedContinent"] }, FormMethod.Post))
{
<div class="form-group">
#Html.DropDownList("SelectedContinent",
new SelectList((IEnumerable) ViewData["continentsList"], "Continent", "Continentomschrijving"))
<button type="submit" class="btn btn-primary">Select</button>
</div>
}
<table id="countriesworld" class="table table-active table-hover">
<thead>
<tr>
<th>Vlag</th>
<th>
Code
</th>
<th>
Land
</th>
<th>Continent</th>
</tr>
</thead>
#foreach (var item in Model)
{
<tr>
<td>
<img src="#string.Format("../../images/countries/{0}.png", item.Code)" width="25" HEIGHT="15" />
</td>
<td>
#item.Code
</td>
<td>
#item.Country
#*#Html.ActionLink("Details", "Index", "ReizensDetails", new { id = item.ReizenId }, null)*#
#*|
#Html.ActionLink("Details", "Details", new { id = item.Id }) |
<button data-myprofile-id="#item.Id" class="btn-link js-delete">Delete</button>*#
</td>
<td>#item.Continents.Continentomschrijving</td>
</tr>
}
</table>
my controller:
public ActionResult Index(int? id)
{
List<Continents> continentsList = new List<Continents>();
continentsList = _context.Continents.ToList();
ViewData["continentsList"] = continentsList;
var countriesWorld = _context.Countries.OrderBy(e => e.Country).ToList();
return View(countriesWorld);
}
[HttpPost]
public ActionResult Index2(int id)
{
//return View(db.MyProfiles.ToList());
List<Continents> continentsList = new List<Continents>();
continentsList = _context.Continents.ToList();
ViewData["SelectedContinent"] = id.ToString();
ViewData["continentsList"] = continentsList;
var countriesWorld = _context.Countries.Where(e => e.Continent == id).OrderBy(e => e.Country).ToList();
return View(countriesWorld);
You have added a route value using new { #id = Request.Form["SelectedContinent"] } in your BeginForm() method.
Assuming the initial value is 0, then it generates action = "/CountriesWorld/Index2/0". Lets assume you select the option with value="1" and you now post the form. The id attribute is bound to 0 and you filter the Countries based on .Where(e => e.Continent == 0) - no where have you ever used the value of the selected option which is bound to a non-existent property named SelectedContinent.
Now you return the view and the forms action attribute is now action = "/CountriesWorld/Index2/1" (because Request.Form["SelectedContinent"] is 1). If you select the option with value="2", the same thing occurs - you ignore the value of the selected option and the filter the Countries based on .Where(e => e.Continent == 1) because the id parameter is 1.
Always bind to a model, which in your case will be
public class CountriesVM
{
public int? SelectedContinent { get; set }
public IEnumerable<SelectListItem> ContinentsList { get; set; }
public IEnumerable<Country> Countries { get; set; }
}
and in the view, strongly bind to your model (note the FormMethod.Get and the 3rd parameter in DropDownListFor())
#model CountriesVM
#using (Html.BeginForm("Index", "CountriesWorld", FormMethod.Get))
{
#Html.DropDownListFor(m => m.SelectedContinent, Model.ContinentsList, "All")
<button type="submit" class="btn btn-primary">Select</button>
}
<table ... >
....
#foreach(var country in Model.Countries)
{
....
}
</table>
and you need only one method
public ActionResult Index(int? selectedContinent)
{
var countries = _context.Countries.OrderBy(e => e.Country);
if (selectedContinent.HasValue)
{
countries = countries.Where(e => e.Continent == selectedContinent.Value);
}
continentsList = _context.Continents.Select(x => new SelectListItem
{
Value = x.Continent.ToString(),
Text = x.Continentomschrijving
});
var model = new CountriesVM
{
SelectedContinent = selectedContinent,
ContinentsList = continentsList,
Countries = countries
};
return View(model);
}
Note you might also want to consider caching the Continents to avoid repeated database calls assuming they do not change often (and invalidate the cache if their values are updated)

Why list of checkbox selections always posted as null in ASP.NET MVC-5 [duplicate]

This question already has answers here:
Post an HTML Table to ADO.NET DataTable
(2 answers)
Closed 5 years ago.
I am new to ASP .NET MVC. My problem is - I want to 'POST' a collection of the items , so that controller can process it.
My model is collection of -
public class CheckedRentalProperty
{
public bool IsSelected { get; set; }
public int Id { get; set; }
public String Address { get; set; }
}
My controller is defined like this -
public class RentalPropertiesController : Controller
{
public ActionResult Index()
{
List<CheckedRentalProperty> checkHsList = new List<CheckedRentalProperty>();
// Fill the list
return View(checkHsList);
}
[HttpPost]
public ActionResult Save(IEnumerable<CheckedRentalProperty> checkHsList)
{
// why checkHsList is coming as null ??
}
}
And the view is like this -
#model IEnumerable<XXX.Models.CheckedRentalProperty>
#using (Html.BeginForm("Save", "RentalProperties", FormMethod.Post))
{
<div class="form-horizontal">
<div class="form-group">
<table class="table">
<tr>
<th>
</th>
<th>
#Html.DisplayNameFor(model => model.Address)
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>#Html.CheckBoxFor(modelItem => item.IsSelected)</td>
<td>
#Html.DisplayFor(modelItem => item.Address)
</td>
</tr>
}
</table>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
My expectations was - when I hit the "Save" button, the Model, which is IEnumerable<CheckedRentalProperty> item, will be passed to the Save() action of the controller. However, I find that the passed parameter is "null" all the time. What am I missing?
Model that are solely IEnumerable are not too friendly as MVC Model.
There are many issues arise here, but in a nutshell, MVC webform bindings needs form name requests to be send in the following format: PropertyName[Index].Property
Which is not the case at your example.
It is a good design practice, to create a wrapping ViewModel which will hold the properties you need for the given controller + pages.
ViewModel
public class RentalPropertiesViewModel
{
public List<CheckedRentalProperty> CheckedRentalProperties { get; set; }
}
Controller: Next we will want to use this ViewModel in our controller.
public ActionResult Index()
{
var checkHsList = new List<CheckedRentalProperty>();
checkHsList.Add(new CheckedRentalProperty { Id = 1, Address = "Address1", IsSelected = true });
checkHsList.Add(new CheckedRentalProperty { Id = 2, Address = "Address2", IsSelected = false });
checkHsList.Add(new CheckedRentalProperty { Id = 3, Address = "Address3", IsSelected = true });
var model = new RentalPropertiesViewModel
{
CheckedRentalProperties = checkHsList
};
return View(model);
}
[HttpPost]
public ActionResult Save(RentalPropertiesViewModel model)
{
// why checkHsList is coming as null ??
return null;
}
View: Now in our view we should set the Model as the new ViewModel type we created.
#model TestBindings.Models.RentalPropertiesViewModel
And our view form should be something like:
<table class="table">
<tr>
<th>
Is Selected
</th>
<th>
Address
</th>
</tr>
#for (int i = 0; i < Model.CheckedRentalProperties.Count(); i++)
{
<tr>
#Html.HiddenFor(model => model.CheckedRentalProperties[i].Id);
<td>#Html.CheckBoxFor(model => model.CheckedRentalProperties[i].IsSelected)</td>
<td>#Html.TextBoxFor(model => model.CheckedRentalProperties[i].Address)</td>
</tr>
}
</table>
I've use the following format model => model.CheckedRentalProperties[i].IsSelected and now MVC InputExtensions will bind it correctly. e.g: CheckedRentalProperties[0].IsSelected
Important Note: Notice i'm passing Id property as hidden, so MVC Binder will know to set the Id to the correct item.

How to post back a list of object to the controller in MVC [duplicate]

This question already has answers here:
MVC Form not able to post List of objects
(3 answers)
Post an HTML Table to ADO.NET DataTable
(2 answers)
Closed 6 years ago.
I have an object model and I am passing it to the view so that user can input their comments for some of the object's properties as a part of a survey.
I am able to receive what the user has entered for an object if I am only rendered one single object to the view. However, when I want to render multiple (a list) of objects to the view then I receive a null list of objects when the user click on the submit form.
Please see my code below:
This is my object model
public class SurveyViewModel
{
public string Name { get; set; }
public double PV { get; set; }
public double QtyUsePerMonth { get; set; }
public double TotalPVPerMonth { get; set; }
}
This is my view where I render the list of object
#model IEnumerable<WebApplication4.Models.SurveyViewModel>
#{
ViewBag.Title = "Survey";
}
<h2>Survey</h2>
#using (Html.BeginForm(null, null, FormMethod.Post, new { id = "form1" }))
{
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.PV)
</th>
<th>
#Html.DisplayNameFor(model => model.QtyUsePerMonth)
</th>
<th>
#Html.DisplayNameFor(model => model.TotalPVPerMonth)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
#Html.HiddenFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.PV)
#Html.HiddenFor(modelItem => item.PV)
</td>
<td>
#Html.TextBoxFor(modelItem => item.QtyUsePerMonth)
</td>
<td>
#Html.TextBoxFor(modelItem => item.TotalPVPerMonth)
</td>
</tr>
}
</table>
<input type="submit" value="Submit">
}
And this is my HttpPost method
[HttpPost]
public ActionResult Survey(List<Models.SurveyViewModel> model)
{
...
}
When the user click on the Submit button I got a null for model where I am expecting to see a list.
Please let me know what I am doing wrong.
Thank you for your help.
Normally, you can't post the list of objects to the controller in default model binder.
Best solution you can pass the object only based on Index to perform the CRUD operation in POST, and GET request you could get all list of objects. So in POST method it works if pass the object only.
If you want to post the list of object, you can achieve it by overriding the ModelBinder or using the FormCollection.
Here is an example, but to perform this way of operation we need to iterate and convert into the list. Because formcollection contains more number of items and not in the List type. The key of the property varies, because of html helper. Be aware when getting the value from formcollection.
[HttpPost]
public ActionResult Index(FormCollection model)
{
List<SurveyViewModel> obj = new List<SurveyViewModel>();
var name =Request.Form["item.Name"].Split(',').ToArray();
var pv =Request.Form["item.PV"].Split(',').ToArray();
//length must be same
for (var i = 0; i < name.Length; i++)
{
obj.Add(new SurveyViewModel()
{
Name = name[i],
PV = Convert.ToDouble(pv[i])
});
}
return View();
}

MVC 3 - The model item passed into the dictionary is of type 'System.Collections.Generic.List`1

Hi I am very new to mvc and need help
I created this
public ActionResult Index()
{
var joblist = (from s in _entities.TaleoJobs
group s by new { s.JobTitle}
into myGroup
where myGroup.Count() > 0
select new { myGroup.Key.JobTitle }
);
return View(joblist.ToList());
}
but when I create the view I get the following error
The model item passed into the dictionary is of type 'System.Collections.Generic.List1[<>f__AnonymousType01[System.String]]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[careers.TaleoJobs]'.
Here is the code for the view
*#model IEnumerable<careers.TaleoJobs>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
JobTitle
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.JobTitle)
</td>
</tr>
}
</table>*
I would be grateful if anyone can help - tried looking at other examples but i am at a loss.
When you are selecting the list, you are only selecting the JobTitle, which is a string. So your list is indeed a List<string>.
You can either update your select to select the entire object:
var joblist = (from s in _entities.TaleoJobs
group s by new { s.JobTitle}
into myGroup
where myGroup.Count() > 0
select s
);
Or, keep your current select and update the type of the view to:
IEnumerable<string>

View Models and Check Boxes in View

I have a newbie question, which I have tried to understand for the past few days. Hopefully someone can be kind enough to help me understand the programming flow.
Assuming I have a model, the information is stored in the database:
public class Student
{
public int studentID { get; set; }
public string studentName { get; set; }
public strin studentGrade {get; set; }
}
public class StudentDBContext : DbContext
{
public DbSet<Student> Students { get; set; }
}
and I want to display it into the view, with additional checkbox so I can select which students to be promoted into the next grade. I read that one way to do it is by putting into view model:
public class StudentViewModel
{
public bool promoted { get; set; }
public Student stu { get; set; }
}
But I am stuck on is this the way to do it? and if yes, how do you put into the view where it will display all the students with a checkbox next to it. Afterwards, I want to update all the grade for the students whose checkboxes are ticked. For example:
Student A, Student B, Student D promoted from Grade 1 to Grade 2. So I want to display the students, tick Student A, B and D and submit to update the Grade.
Step by step example will be much appreciated.
Update 1:
Controller:
[HttpGet]
public ViewResult CheckBox()
{
var studentViewModels = db.Students.Select(m => new StudentViewModel()
{
stu = m
}).ToList();
return View(studentViewModels);
}
[HttpPost]
public ActionResult CheckBox(IList<studentViewModel> list)
{
foreach (var stuUpdate in list.Where(m => m.promoted))
{
var stuRow = db.Students.Find(stuUpdate.stu.studentID);
stuRow.studentName = stuRow.studentName + "1";
db.Entry(stuRow).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("CheckBox");
}
return RedirectToAction("CheckBox");
}
View:
#model IList<School.ViewModels.StudentViewModel>
#using (Html.BeginForm())
{
<table>
<tr>
<th>
</th>
<th>
student ID
</th>
<th>
student name
</th>
<th>
student grade
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.CheckBoxFor(modelItem => item.promoted)
#Html.HiddenFor(modelItem => item.stu.studentID)
</td>
<td>
#Html.DisplayFor(modelItem => item.stu.studentID)
</td>
<td>
#Html.DisplayFor(modelItem => item.stu.studentName)
</td>
<td>
#Html.DisplayFor(modelItem => item.stu.studentGrade)
</td>
</tr>
}
</table>
<input type="submit" value="save" />
}
However currently hit by the following error:
Value cannot be null.
Parameter name: source
Source Error:
foreach (var stuUpdate in list.Where(m => m.promoted))
A very basic "step by step" (done in SO, so I probably did a few mistakes, but you've got the idea).
You have always a few ways to do these kind of things, so... just really take it as a sample, and find other examples to get other ideas.
well, first, in your controller, you will have a GET action (to see the list).
[HttpGet]
public ViewResult StudentList() {
//retrieve all students. With the Select, we create a new instance of StudentViewModel for each student.
//assuming StudentDbContext being a property of your controller, if it's not, you can instantiate a new one (in a using clause)
var studentViewModels = StudentDbContext.Students
.Select(m => new StudentViewModel() {
stu = m
//we don't say nothing about promoted :
//it will be there as "false" by default, which is probably what we want.
}).ToList();
//now we've got a list of StudentViewModel. This will be the model of our view
return View(studentViewModels);
}
Then we've got a view, StudentList.cshtml
in this view, we will display a table, with a line for each student : the studentId (hidden in this case), the name (display only), the grade (display only), and a checkbox.
We need a for loop (not a foreach) to get fine model binding.
#model IList<StudentViewModel>
#using (Html.BeginForm()) {
<table>
<tr>
<th>Student name</th>
<th>Student grade</th>
<th>Promote</th>
</tr>
#for (var i = 0; i < Model.Count(); i++) {
<tr>
<td>#Html.HiddenFor(m => Model[i].Student.studentID)
#Html.DisplayFor(m => Model[i].Student.studentName)
</td>
<td>#Html.DisplayFor(m => Model[i]Student.studentGrade)</td>
<td>#Html.CheckBoxFor(m => Model[i].promoted)</td>
</tr>
}
</table>
<input type="submit" value="save" />
}
This form will lead to another POST action (same name as the GET one, depending of what you have in your Html.BeginForm)
[HttpPost]
public ActionResult StudentList(IList<StudentViewModel> list) {
//we treat only the lines where checkbox has been checked
foreach (var studentViewModel in list.Where(m => m.promoted) {
var student = StudentDBContext.GetById(studentViewModel.Student.studentID);//get student entity instance from context
student.studentGrade ="<new value>";
StudentDBContext.SaveChanges();//save changes, you must have such a method somewhere.
}
return Action("StudentList");
}
Little detail :
Try to respect some really basic "usual" practices : for example in c#, Properties should begin by an uppercase letter (so StudentGrade, StudentName, Promoted, etc).

Resources