MVC DropDownList lagging - asp.net-mvc

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)

Related

ASP.NET Core - MVC. Drop down populate issue

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.

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.

Searching always returns empty list in MVC?

I'm trying to implement filtering in a page that contains some data, the page shows three different entities: Branches, Items and Categories, so I used a view model:
public class WarehouseData
{
public IEnumerable<Item> Items { get; set; }
public IEnumerable<Category> Categories { get; set; }
public IEnumerable<Branch> Branches { get; set; }
}
in the controller:
public ActionResult Index(string sort, string search)
{
var warhouse = new WarehouseData();
warhouse.Items = db.Items.Include(c => c.Categories).ToList();
warhouse.Branches = db.Branches;
ViewBag.Search = search;
warhouse.Branches = db.Branches.ToList();
switch (sort)
{
case "q_asc":
warhouse.Items = warhouse.Items.OrderBy(c => c.Quantity).ToList();
ViewBag.Sort = "q_desc";
break;
case "q_desc":
warhouse.Items = warhouse.Items.OrderByDescending(c => c.Quantity).ToList();
ViewBag.Sort = "q_asc";
break;
default:
warhouse.Items = warhouse.Items.OrderBy(c => c.Name).ToList();
ViewBag.Sort = "q_asc";
break;
}
if (!string.IsNullOrEmpty(search))
{
warhouse.Items = warhouse.Items.Where(i => i.Name.Contains(search)).ToList();
ViewBag.Search = search;
}
return View(warhouse);
}
this is the Index view:
#model WarehouseManagementMVC.ViewModels.WarehouseData
#{
ViewBag.Title = "Index";
}
<h2 style="display:inline-block">Registered Branches | </h2> #Html.ActionLink("Add New Branch", "Create", controllerName: "Branch")
#foreach (var branch in Model.Branches)
{
<ul>
<li>#Html.ActionLink(branch.Location, "Details", "Branch", routeValues: new { id = branch.Id }, htmlAttributes: null)</li>
</ul>
}
<hr />
<h2>All Items Available</h2>
<div>
#using (#Html.BeginForm("Index", "Warehouse", FormMethod.Get))
{
<input type="text" name="search" value="#ViewBag.Search"/>
<input type="submit" value="Filter" />
}
</div>
<table class="table table-bordered">
<tr>
<th>Product</th>
<th>#Html.ActionLink("Quantity", "Index", new { sort = ViewBag.Sort, search = ViewBag.Search })</th>
<th>Categories</th>
</tr>
#foreach (var item in Model.Items)
{
<tr>
<td>
#Html.ActionLink(item.Name, "Details", "Item", routeValues: new { id = item.Id }, htmlAttributes: null)
</td>
<td>
<span>#item.Quantity</span>
</td>
<td>
#{foreach (var cat in item.Categories)
{
#cat.Name <br />
}
}
</td>
</tr>
}
</table>
But when I search, the result is always empty list, why?
There's only two things that would cause Items to be empty here:
There's no items in the DB.
None of those items have Name values that contain the search term. Be advised in particular here that Contains is case-sensitive. So if the name is Foo and you searched for foo it will not match. If you want to do case-insensitive search, then you should cast both Name and search to either lowercase or uppercase before comparing:
Where(m => m.Name.ToLower().Contains(search.ToLower()))
While we're here. A search should ideally filter at the database level. Currently, you're selecting all items in the database and then filtering them in-memory, which is highly-inefficient. As soon as you you call ToList() in the second line of the action, the query has been sent, but you have to do so in order to set warhouse.Items. Instead, you should store your items in a temporary variable, i.e. IQueryable items = db.Items.Include(c => c.Categories); and do all your conditional ordering and filtering on that. Then, finally, set warhouse.Items = items.ToList();.
I found that the search is case sensitive, this solved it:
if (!string.IsNullOrEmpty(search))
{
warhouse.Items = warhouse.Items.Where(i => i.Name.ToLower().Contains(search.ToLower())).ToList();
ViewBag.Search = search;
}
If you have another suggestion for the code , I appreciate sharing it.

lambda expression Problems

My question is when I click actionlink,the view send specific ID to controller(ex. ProductID = 6), but my controller grab all data to me not specific ID data.
I think the problem is the lambda expression at controller, it will grab all data to me.
These are my Models:
public class ShoppingCart
{
public List<ShoppingCartItemModel> items = new List<ShoppingCartItemModel>();
public IEnumerable<ShoppingCartItemModel> Items
{
get { return items; }
}
}
public class ShoppingCartItemModel
{
public Product Product
{
get;
set;
}
public int Quantity { get; set; }
}
Controller :
[HttpGet]
public ActionResult EditFromCart(int ProductID)
{
ShoppingCart cart = GetCart();
cart.items.Where(r => r.Product.ProductID == ProductID)
.Select(r => new ShoppingCartItemModel
{
Product = r.Product,
Quantity = r.Quantity
});
return View(cart);
//return RedirectToAction("Index", "ShoppingCart");
}
private ShoppingCart GetCart()
{
ShoppingCart cart = (ShoppingCart)Session["Cart"];
//如果現有購物車中已經沒有任何內容
if (cart == null)
{
//產生新購物車物件
cart = new ShoppingCart();
//用session保存此購物車物件
Session["Cart"] = cart;
}
//如果現有購物車中已經有內容,就傳回 view 顯示
return cart;
}
View
#model ShoppingCart
#{
ViewBag.Title = "購物車內容";
}
<h2>Index</h2>
<table class="table">
<thead>
<tr>
<th>
Quantity
</th>
<th>
Item
</th>
<th class="text-right">
Price
</th>
<th class="text-right">
Subtotal
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.items)
{
<tr>
<td class="text-center">
#item.Quantity
</td>
<td class="text-center">
#item.Product.ProductName
</td>
<td class="text-center">
#item.Product.Price.ToString("c")
</td>
<td class="text-center">
#( (item.Quantity * item.Product.Price).ToString("c"))
</td>
<td>
#using (Html.BeginForm("RemoveFromCart", "ShoppingCart"))
{
#Html.Hidden("ProductId", item.Product.ProductID)
#*#Html.HiddenFor(x => x.ReturnUrl)*#
<input class="btn btn-warning" type="submit" value="Remove">
}
</td>
<td>
#using (Html.BeginForm("EditFromCart", "ShoppingCart", FormMethod.Get))
{
#Html.Hidden("ProductId", item.Product.ProductID)
<input class="btn btn-warning" type="submit" value="Edit">
}
</td>
</tr>
}
</tbody>
</table>
The key issue is that this code doesn't return the result of the LINQ queries, because you have not assigned a variable to the result:
cart.items.Where(r => r.Product.ProductID == ProductID)
.Select(r => new ShoppingCartItemModel
{
Product = r.Product,
Quantity = r.Quantity
});
I strongly suggest you create a viewmodel specifically to display the cart items.
public class CartItemsViewModel
{
public List<ShoppingCartItemModel> Items { get; set; }
}
[HttpGet]
public ActionResult EditFromCart(int ProductID)
{
ShoppingCart cart = GetCart();
var viewModel = new CartItemsViewModel();
viewModel.Items.AddRange(cart.items.Where(r => r.Product.ProductID == ProductID)
.Select(r => new ShoppingCartItemModel
{
Product = r.Product,
Quantity = r.Quantity
}));
return View(viewModel);
}
In my example I use the .AddRange() method to take the results of the LINQ calls against the cart items and store them in the viewmodel's Items property.
You must have to assign filtered value to cart like this.
cart.item = cart.items.Where(r => r.Product.ProductID == ProductID)
.Select(r => new ShoppingCartItemModel
{
Product = r.Product,
Quantity = r.Quantity
}).ToList();
use ToList(); or FirstOrDefault() as per your condition
You need to hold the return value from the linq query on cart.Items in a variable and pass that to the View method.
At the moment, the result of your query is being lost and the whole cart passed to the View method.

Model is not populated during form post ASP.NET MVC

I am learning ASP.NET MVC. I am trying to catch model data on form post, but model is showing as null.
Here is my Model
public class SampleModel
{
public int ID { get; set; }
public string Name { get; set; }
public string CRUDOperation { get; set; }
}
Here is my view
#model IEnumerable<SampleModel>
#using (Html.BeginForm("SubmitUpdateGridRow", "GridView", FormMethod.Post, new {value = "form" }))
{
#Html.AntiForgeryToken()
<table class="table table-bordered">
<tr>
<th>
#Html.Label("CRUD Actions")
</th>
<th>
#Html.DisplayNameFor(model => model.ID)
</th>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
</tr>
#foreach (SampleModel Row in Model)
{
<tr>
#if (Row.CRUDOperation == "Select")
{
<td>
#Html.ActionLink("Update", "UpdateGridRow", "GridView", Row, new { #title = "U: Update Operation of CRUD" }) |
#Html.ActionLink("Edit", "EditGridRow", "GridView", new { id = Row.BGID }, new { #title = "U: Update Operation of CRUD" }) |
#Html.ActionLink("Delete", "DeleteGridRow", "GridView", new { id = Row.BGID }, new { #title = "D: Delete Operation of CRUD" }) |
#Html.ActionLink("Details", "DetailsGridRow", "GridView", new { id = Row.BGID }, new { #title = "Form level view for details" })
</td>
<td>
#Row.ID
</td>
<td>
#Row.Name
</td>
}
else if (Row.CRUDOperation == "Edit")
{
<td>
#Html.HiddenFor(ID => Row.ID)
#Html.HiddenFor(CRUDOperation => Row.CRUDOperation)
#Row.BGID
</td>
<td>
#Html.EditorFor(Name => Row.Name)
</td>
<td>
<input type="submit" value="Update" id="UpdateSubmit" />
#Html.ActionLink("Edit", "EditGridRow", "GridView", new { id = Row.ID }, new { #title = "U: Update Operation of CRUD" }) |
#Html.ActionLink("Reset", "ResetGridRow", "GridView", new { id = Row.ID }, new { #title = "R: Reset Operation of CRUD" })
</td>
}
</tr>
#*<tr>
#if (Row.CRUDOperation == "Edit")
{
EditRow(Row);
}
else
{
DisplayRow(Row);
}
</tr>*#
//Row.CRUDOperation.Equals("Edit") ? EditRow(Row) : DisplayRow(Row);
}
</table>
}
Here is my controller
public class GridViewController : Controller
{
[HttpPost]
public ActionResult SubmitUpdateGridRow(FormCollection FC, SampleModel VM)
{
string str = (string)FC.GetValue("Row.Name").AttemptedValue;
......
}
}
I was able to get the values from form collection, but my model is coming as null.
Thanks in advance.
PS: i would like to find the solution only with server side scripting, dont want to use javascript, JQuery
In your view you are posting a collection of SampleModel however your controller only takes in a single SampleModel parameter.
First you need to change your controller to take in IEnumerable<SampleModel>.
Then in your view, you need to pass the index to the html helpers to generate the correct html for list model binding to work out of the box.
For example:
#model IList<SampleModel>
#for(var i = 0; i < Model.Count; i++)
{
#Html.HiddenFor(m => Model[i].Id)
}
Check this useful article for more on model binding lists
Put Antiforgery attribute on top of the controller action as your HTML form has Antiforgery tag.

Resources