How can use MVC DropDownlist - asp.net-mvc

I have a problem with DropDownlist in MVC
I use ModelView in my application and this is my code
namespace MedicallexiconProject.ViewModel
{
public class WordViewModel
{
private readonly ICategoryService _categoryService;
public WordViewModel(ICategoryService categoryService)
{
_categoryService = categoryService;
var selectList = _categoryService.GetAllCategorysSelectList().
Select(x => new SelectListItem
{
Text = x.Name,
Value = x.ID.ToString()
}).ToList();
Categories = selectList;
}
public WordViewModel()
{
}
public string Name { get; set; }
private IList<SelectListItem> _categories;
public IList<SelectListItem> Categories
{
get
{
if (_categories == null)
{
_categories = new List<SelectListItem>();
}
return (_categories);
}
set { _categories = value; }
}
}
}
and this is my controller
[HttpGet]
public ActionResult Create()
{
var wordViewModel = new WordViewModel(_categoryService);
ViewBag.CategoryID = wordViewModel.Categories;
return View();
}
[HttpPost]
public ActionResult Create(WordViewModel wordViewModel)
{
Mapper.CreateMap<WordViewModel, Word>();
var word = new Word();
Mapper.Map(wordViewModel, word);
if (ModelState.IsValid)
{
_wordService.AddNewWord(word);
_uow.SaveChanges();
return RedirectToAction("Index");
}
return View(wordViewModel);
}
Now how can I insert dropdownlist in my View?

As AlfalfaStrange mentioned, you should not add logic in your ViewModel. That makes it ugly ! Keep your ViewModel simple POCO.
Add one more property in your ViewModel called "SelectedCategoryID" like this
public class WordViewModel
{
public int SelectedCategoryID { set;get;}
public IList<SelectListItem> Categories { set;get;}
public string Name { set;get;}
}
Initialize your Items (Categories) of your ViewModel in your GET method. Here i am calling a method called GetCategories which returns a list of categories.I can simply call the method wherever i want.
public ActionResult Create()
{
var model=new WordViewModel();
model.Categories=YourService.GetCategories();
return View(model);
}
In your strongly typed Create view , use this
#model WordViewModel
using(#Html.BeginForm())
{
#Html.DropDownFor(x=>x.SelectedCategoryID,
new SelectList(Model.Categories,"Value","Text"),"Select Category")
<input type="submit" value="Save" />
}
In your HttpPost action method , you can check for wordViewModel.SelectedCategoryID for the selected value.
[HttpPost]
public ActionResult Create(WordViewModel wordViewModel)
{
if(ModelState.IsValid)
{
//Checck for wordViewModel.SelectedCategoryID here now
}
//some validation failed. Let's reload the category data again.
wordViewModel.Categories=YourService.GetCategories();
return View(wordViewModel);
}

It's absolutely fine to include code that loads a dropdown list in your view model. A select list and a drop down are both "view" items.... they are not related to business logic and your controller and model need not know anything about SelectLists or SelectListItems or DropDownList, etc.

Related

I want to show selected value of dropdown list

Selected value is not coming when I am trying to check, drop down list is showing all the names, but when I am trying to show the selected value of the dropdownlist in the controller, option is not coming.
Controller:
public ActionResult Index1()
{
Class1 cs1 = new Class1();
return View(cs1);
}
[HttpPost]
public ActionResult Index1(Class1 cs)
{
var selecteditem = cs.psudetail.Find(p => p.Section_PSU == cs.psudetail.ToString());
if (selecteditem != null)
{
}
}
Model class:
namespace WebApplication1.Models
{
public class Class1
{
public List<PSUMaster> psudetail
{
get
{
PSUEntities pe = new PSUEntities();
return pe.PSUMasters.ToList();
}
}
}
}
And the View with Model:
#model WebApplication1.Models.Class1
#{
ViewBag.Title = "Index1";
}
<br />
#Html.DropDownListFor(m => m.psudetail, new SelectList(Model.psudetail, "S_no", "Section_PSU"), "--Select PSU--")
You need to have a property that can "store" the selection you make in the list. Extend the view model (Class1) to include a property SelectedPSU. I guess that S_no in the PSUMaster is the ID, and of type integer. Otherwise adjust the code accordingly!
I have also changed the list to be just a list, and then the controller can worry about populating it. This pattern fits MVC better (keep the model simple).
Updated class:
namespace WebApplication1.Models
{
public class PsuViewModel
{
public int SelectedPSU { get; set; }
public List<PSUMaster> PSU { get; set; }
}
}
Next, the controller has to be updated to pass the list to the view model in the GET Index method:
public ActionResult Index1()
{
var pe = new PSUEntities();
return View(new PsuViewModel {
PSU = pe.PSUMasters.ToList()
});
}
Now we can use the SelectedPSU property in our view:
#model WebApplication1.Models.Class1
#{
ViewBag.Title = "Index1";
}
<br />
#Html.DropDownListFor(m => m.SelectedPSU, new SelectList(Model.PSU, "S_no", "Section_PSU"), "--Select PSU--")
...and we can get the ID in the controller:
[HttpPost]
public ActionResult Index1(PsuViewModel model)
{
var pe = new PSUEntities();
var selectedPsu = pe.PSUMasters.FirstOrDefault(p => p.S_no == model.SelectedPSU);
if (selectedPsu != null) {
// ...
}
}

ASP.NET MVC Model Binding returns null when model type is inherited from CollectionBase

This is my model
public class MessageSetTypeCollection<T> : CollectionBase where T : MessageSetType, new()
{
public string Name { get; set; }
public string[] Tags { get; set; }
public MessageSetType this[int index]
{
get
{
return (MessageSetType)List[index];
}
}
public void Add(MessageSetType value)
{
List.Add(value);
}
}
This is my controller actions
public ActionResult TestAction()
{
MessageSetTypeCollection<MessageSetType> Model = new MessageSetTypeCollection<MessageSetType>();
Model.Add(new MessageSetType()
{
Alert = "test" // Alert is a public property of the MessageSetType class
});
Model.Add(new MessageSetType()
{
Alert = "test2"
});
return View(Model);
}
[HttpPost]
public void TestAction(MessageSetTypeCollection<MessageSetType> Model)
{
return;
}
In the view I've this code
#using (Html.BeginForm())
{
#Html.EditorFor(a => a[0].Alert)
#Html.EditorFor(a => a[1].Alert)
<input type="submit" value="OK" />
}
When I submit this form to the TestAction action, the inner list into the Model parameter has a Count of 0 elements. Why?
I've also tested this code with List<MessageSetType> model type instead of MessageSetTypeCollection<MessageSetType> and all works correctly. Where is the error?
Please see here source code for List:
http://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs
The implementation is pretty different. You don't have a collection of type MessageSetType on which your indexer should work.
I think you can use source code of to adjust your model: MessageSetTypeCollection.
I've resolved inheriting the MessageSetTypeCollection<T> from List<T> instead of CollectionBase
public class MessageSetTypeCollection<T> : List<T> where T : MessageSetType, new()
{
//Omissis
}

How to clear text from a search textbox after search is complete in MVC

I have two dropdown lists and two textboxes
Search By: ByHtml.DropDownList("Search1", "Please Select...")
Html.TextBox("searchString1")
Search By: Html.DropDownList("Search2", "Please Select...")
#Html.TextBox("searchString2")
<input type="submit" value="Filter" />
When I make my selection from whichever DDL and type text into the textbox and hit filter my search returns, however after the search the text remains in the textbox, is there a way of clearing it after the search so that the textbox is empty again? I tried
ModelState.Remove("");
but it didn't work.
A sample from My controller code is
public class MainController : Controller
{
private DBEntities db = new DBEntities();
// GET: /Main/
public ActionResult Index(string searchString1, string searchString2, string Search1, string Search2)
{
//Create a Dropdown list
var SearchOptionList = new List<string>();
SearchOptionList.Add("LandLord");
SearchOptionList.Add("Postcode");
SearchOptionList.Add("Street Address");
ViewBag.Search1 = new SelectList(SearchOptionList);
ViewBag.Search2 = new SelectList(SearchOptionList);
var mylist = from m in "mydatabase" select m;
//This statement runs if the user selects a parameter from Search2 and leaves Search1 empty
if (String.IsNullOrEmpty(Search1) && !String.IsNullOrEmpty(Search2))
{
if (Search2 == "Postcode")
{
mylist = mylist.Where(s => s.Postcode.Contains(searchString2));
}
if (Search2 == "LandLord")
{
mylist = mylist.Where(s => s.Name.Contains(searchString2));
}
if (Search2 == "Street Address")
{
mylist = mylist.Where(s => s.StreetAddress.Contains(searchString2));
}
}
return View(mylist.ToList());
}
Your should have a view model containing properties searchString1 and searchString2 and the select lists
public class SearchVM
{
public string searchString1 { get; set; }
public string searchString2 { get; set; }
public SelectList SearchList1 { get; set; }
public SelectList SearchList2 { get; set; }
}
Controller
public ActionResult Search()
{
SearchVM model = new SearchVM();
model.SearchList1 = new SelctList(...);
model.SearchList2 = new SelctList(...);
return View(model);
}
View
#model SearchVM
#using(Html.BeginForm())
{
....
#Html.DropDownListFor(m => m.searchString1, Model.SearchList1, "--Please select--")
#Html.DropDownListFor(m => m.searchString2, Model.SearchList2, "--Please select--")
....
}
Post
[HttpPost]
public ActionResult Search(SearchVM model)
{
// to clear all modelstate and reset values
ModelState.Clear();
model.searchString1 = null;
model.searchString2 = null;
// or to clear just one property and reset it
ModelState.Remove("searchString1");
model.searchString1 = null;
// repopulate select lists if your returning the view
return View(model);
}
At the end of my public ActionResult Index method but before return View() I placed the following code which worked perfectly
ModelState.Remove("searchString1");
ModelState.Remove("searchString2");
ModelState.Remove("Search1");
ModelState.Remove("Search2");
I know is an old question, but I fall in the same issue. So I put my solution.
View:
#Html.TextBox("Search", null, new { #autofocus = "autofocus" })
Controller:
ViewBag.Search= null;
ModelState.Remove("Search");
return View(list.ToList());
Hope to help someone

Model property is empty

I am trying to move from webForms to Asp.net-MVC and have some problems. I am trying to figure why this is not working, I am getting this error: "Object reference not set to an instance of an object"
I have the class 'Pages':
namespace _2send.Model
{
public class Pages
{
public string PageContent { get; set; }
public string PageName { get; set; }
public int LanguageId { get; set; }
}
}
I am inserting the value to 'Pages.PageContent' property with this class:
namespace _2send.Model.Services
{
public class PagesService : IPagesService
{
public void GetFooterlinksPage()
{
DB_utilities db_util = new DB_utilities();
SqlDataReader dr;
Pages pages = new Pages();
using (dr = db_util.procSelect("[Pages_GetPageData]"))
{
if (dr.HasRows)
{
dr.Read();
pages.PageContent = (string)dr["PageContent"];
dr.Close();
}
}
}
The Controller method looks like this:
private IPagesService _pagesService;
public FooterLinksPageController(IPagesService pagesService)
{
_pagesService = pagesService;
}
public ActionResult GetFooterLinksPage()
{
_pagesService.GetFooterlinksPage();
return View();
}
I am trying to write the property in the view like this:
#model _2send.Model.Pages
<div>
#Model.PageContent;
</div>
When debugging, the method is fired and the dataReader is inserting the value to the 'PageContent' property, but I am still getting this error from the view.
Thanks!
return View();
You didn't pass a model.
You need to pass the model as a parameter to the View() method.
You need to rewrite service method to return Pages:
public Pages GetFooterlinksPage()
{
DB_utilities db_util = new DB_utilities();
Pages pages = new Pages();
using (var dr = db_util.procSelect("[Pages_GetPageData]"))
{
if (dr.HasRows)
{
dr.Read();
pages.PageContent = (string)dr["PageContent"];
return pages;
// Because you use using, you don't need to close datareader
}
}
}
And then rewrite your action method:
public ActionResult GetFooterLinksPage()
{
var viewmodel = _pagesService.GetFooterlinksPage();
return View(viewmodel);
}
You can return a model:
var viewmodel = new _2send.Model.Pages().
//here you configure your properties
return View(viewmodel);

How to render a model property of string type as checkbox in ASP.NET MVC

I want to display a string type as checkbox on MVC view, but returns it as string type on HTTP post. The problem is that it returns false on HTTP Post. Below is my code:
View:
#model List<Car>
foreach(var car in Model){
bool isFourWheel = false;
if(bool.TryParse(car.IsFourWheel, out isFourWheel){
#Html.CheckBox("IsFourWheel", isFourWheel); //need to be rendered as checkbox, but returns string type on HTTP POST
}
}
Model:
public class Car
{
public string IsFourWheel { get; set; } //bad naming, but it can contain any type, include boolean
}
Controller:
public ActionResult Index()
{
var cars = new List<Car>(){ new Car(){IsFourWheel = "true"},new Car(){IsFourWheel = "false"} };
return View(cars);
}
[HttpPost]
public ActionResult Index(List<Car> cars) **Problem IsFourWheel is false when true is selected **
{
return View(cars);
}
Any ideal would be very much appreciated.
You can try specifying a template name in your helper:
#Html.EditorFor(car => car.IsFourWheel, "CheckBox")
And defining the template to render the data the way you want, in either ~/Views/{YourControllerName}/EditorTemplates/CheckBox.cshtml or ~/Views/Shared/EditorTemplates/CheckBox.cshtml.
You can find a whole series of post by Brad Wilson on MVC templates here:
Brad Wilson: ASP.NET MVC 2 Templates, Part 1: Introduction
It is for MVC 2, but most concepts still apply to MVC 3 as well (save for the Razor syntax).
Update:
Actually you probably don't need a custom template for this. Try using #Html.CheckBoxFor(car => car.IsFourWheel) instead.
Update 2:
Drop the following template in ~/Views/Shared/EditorTemplates:
IsFourWheel.cshtml
#functions {
private bool IsChecked() {
if (ViewData.Model == null) return false;
return Convert.ToBoolean(ViewData.Model, System.Globalization.CultureInfo.InvariantCulture);
}
}
#Html.CheckBox("", IsChecked(), new { #class = "check-box" })
Then from your view, call it like so:
#Html.EditorFor(model => model.IsFourWheel, "IsFourWheel")
I tested it and binding works in both GET and POST scenarios.
You could alter your viewmodel like this:
public class Car
{
public string IsFourWheel { get; set; }
public bool IsFourWheelBool { get { return bool.Parse(IsFourWheel); } }
}
Your view would look like this:
#Html.EditFor(x => x.IsFourWheelBool);
I think it will be easier, if you add an Id to your model. Just like this
Model:
public class Car
{
public int CarID { get; set; }
public string IsFourWheel { get; set; }
}
View:
#model IEnumerable<Car>
foreach (var car in Model)
{
if(car.IsFourWheel == "true"){
<input type="checkbox" name="carID" value="#car.CarID" checked="checked" />
}
else
{
<input type="checkbox" name="carID" value="#car.CarID" />
}
}
Controller:
[HttpPost]
public ActionResult Index(List<int> carID)
{
//handle selected cars here
return View();
}

Resources