dropdownlist in mvc _layout file in asp.net mvc - asp.net

In my application i have a form with dropdownlist in _layout file.
After submitting form in View (I have many Views with same _Layout file) goto some Other controller view.
But i am getting always a error
Object reference not set to an instance of an object at dropdownlist.
My _HomeLayout.cshtml
#using (Ajax.BeginForm("Allpost", "User", new AjaxOptions() { HttpMethod = "GET", UpdateTargetId = "frmEmp" }))
{
#Html.Partial("_AllCategories", Model)
}
Partial View
#model Models.HomePageSearchVM
#Html.DropDownListFor(m => m.catlist, Model.CategoriesList, "Select Categorie")
HomeController
public ActionResult _AllCategories()
{
HomePageSearchVM pasvm = new HomePageSearchVM();
pasvm.CategoriesList = new MultiSelectList(db.CategoriesList, "CatId", "CategorieName");
return PartialView("_AllCategories", pasvm);
}
HomePageSearchVM.cs
namespace Entities
{
public partial class HomePageSearchVM
{
public virtual IEnumerable<SelectListItem> CategoriesList { get; set; }
[NotMapped]
public string[] catlist { get; set; }
public string search { get; set; }
}
}
View Home
#model Models.PostallVM
#{
Layout = "~/Views/Shared/_HomeLayout.cshtml";
}
----- some code ----
Error
Object reference not set to an instance of an object.
How use Form in _Layout file with some text and dropdown fields and call a model in Layout. I am using the same layout file for many Views with different Models.
I hope you understand my problem.

Related

Populate a select list ASP.NET Core MVC

I'm busy with an ASP.NET Core MVC application, and I'm trying to populate a drop down list. I've created a view model and I have added a method to my StoresController that returns a list of stores that I want to display in a dropdown. I've been working off some online tutorials as I'm very new to asp.
View model:
public class StoreListViewModel
{
public List<StoreList> StoreList { get; set; } = new List<StoreList>();
}
public class StoreList
{
public string StoreId { get; set; } = null!;
public string StoreName { get; set; } = null!;
}
StoresController:
public IActionResult LoadStoreList()
{
if (ModelState.IsValid)
{
var storeList = new StoreListViewModel().StoreList.Select
(x => new SelectListItem { Value = x.StoreId, Text = x.StoreName }).ToList();
ViewBag.Stores = storeList;
}
return NotFound();
}
I'm trying to use ViewBag to call my LoadStoreList() method.
<select name="storeList" class="form-control" asp-items="#(new SelectList(ViewBag.Stores, "Value", "Text"))"></select>
When I load my page I get the following error
Value cannot be null. (Parameter 'items')
The page I need the dropdown list on is my CreateUser.cshtml which is bound to my UserModel and has a UsersController. The method I have created for listing the stores is in my StoresController which is bound to my StoresModel. So I'm not sure if that's causing the issue.
I've been battling with this for days, if someone could help me get this working or show me a better method, that would be great.
*Edit
The UserIndex() method is the first method that fires when my users page opens, do I call the LoadStoreList() method from there ?
UserController
public async Task<IActionResult> UsersIndex()
{
return _context.UsersView != null ?
View(await _context.UsersView.ToListAsync()) :
Problem("Entity set 'ApplicationDbContext.Users' is null.");
}
I'm trying to use ViewBag to call my LoadStoreList() method.
ViewBag cannot be used to call any method. You just need set value for ViewBag in the method which renders your show dropdownlist's page.
From your description, you said the page you need the dropdown list on is CreateUser.cshtml. Assume that you render the CreateUser.cshtml page by using CreateUser action.
CreateUser.cshtml:
<select name="storeList" class="form-control" asp-items="#(new SelectList(ViewBag.Stores, "Value", "Text"))"></select>
Controller:
public class YourController : Controller
{
private readonly YourDbcontext _context;
public YourController(YourDbcontext context)
{
_context = context;
}
[HttpGet]
public IActionResult CreateUser()
{
var storeList = _context.StoreLists.Select
(x => new SelectListItem { Value = x.StoreId , Text = x.StoreName }).ToList();
ViewBag.Stores = storeList;
return View();
}
}
YourDbcontext should be something like:
public class YourDbcontext: DbContext
{
public YourDbcontext(DbContextOptions<MvcProjContext> options)
: base(options)
{
}
public DbSet<StoreList> StoreLists{ get; set; }
}
Dont use viewbag for storing list data. Make your view page model including List, for example:
public class UserCreationViewModel{
public int Id{ get; set; }
public string Name { get; set; }
// Any other properties....
public List<StoreList> StoreList { get; set; }
}
in your controller YourController:
[HttpGet]
public IActionResult CreateUser()
{
var storeList = new StoreListViewModel().StoreList.Select
(x => new SelectListItem { Value = x.StoreId, Text = x.StoreName }).ToList();
UserCreationViewModel model=new UserCreationViewModel{
StoreList = storeList
};
return View("createUserViewName", model);
}
in createUserViewName:
#Html.DropDownList("StoreId", new SelectList(Model.StoreList, "StoreId", "StoreName"), "Select", new { #class = "form-control" })
or
<select class="form-control" asp-for="#Model.StoreId" asp-items="#(new SelectList(Model.StoreList, "StoreId", "StoreName"))">
<option value="-1">Select</option>
</select>

Unusual behavior DropDownList MVC 5

I managed to populate DropDownList with value from a Database in ASP.NET MVC 5. My goal is to assing one of the dropDownList's value to a specific model, and send it back to the Database. So, if i leave the default value in the dropdownlist, the data in SQL server is null, which is Okay, but if I choose an option, I get an error :
Exception thrown: 'System.InvalidOperationException' in System.Web.Mvc.dll ("There is no ViewData item of type 'IEnumerable' that has the key 'Status'."). I tried everything so far and i am opened for suggestions. Thank you !!!
In Controller :
ViewBag.Status = new SelectList(db.Status, "Id", "Name");
in View
#Html.DropDownList("Status","Select status...")
In Controller so far..
public ActionResult Index()
{
return View();
}
[HttpGet]
public ActionResult Apply(ViewModelVM vm,int x=0)
{
myDb db = new myDb();
ViewBag.SocialStatus = new SelectList(db.SocialStatuses, "Id", "StatusDescription");
return View();
}
[HttpPost]
public ActionResult Apply(ViewModelVM vm)
{
if (ModelState.IsValid)
{
using (myDb db = new myDb())
{
var personalinfo = new PersonalInformation()
{
FirstName = vm.PersonalInformation.FirstName,
LastName = vm.PersonalInformation.LastName,
Birthdate = vm.PersonalInformation.Birthdate,
SocialStatus = vm.SocialStatus
};
ViewBag.SocialStatus = new SelectList(db.SocialStatuses, "Id", "StatusDescription");
db.PersonalInformations.Add(personalinfo);
db.SaveChanges();
}
return View("Success");
}
return View();
}
The model:
public partial class Status
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public SocialStatus()
{
PersonalInformations = new HashSet<PersonalInformation>();
}
public int Id { get; set; }
[StringLength(20)]
public string StatusDescription { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<PersonalInformation> PersonalInformations { get; set; }
}
}
The ViewModel:
public class ViewModelVM
{
...
public Status SocialStatus { set; get; }
...
}
Firstly your using a view model so include a property in your view model for the SelectList
public IEnumerable<SelectListItem> StatusList { get; set; }
Next remove the parameter for the model from the GET method (and since you don't appear to be using the value of x, that should be removed also)
[HttpGet]
public ActionResult Apply(ViewModelVM vm,int x=0)
{
myDb db = new myDb();
ViewModelVM model = new ViewModelVM()
{
StatusList = new SelectList(db.SocialStatuses, "Id", "StatusDescription");
};
return View(model); // return the model to the view
}
Next, your dropdown is binding to a property named Status but your view model does not contain a property named status (its SocialStatus) and SocialStatus is a complex object and you cannot bind a <select> to a complex object (a <select> only posts back a single value (or array or values in the case of <select multiple>).
In addition, because your view model contains a property which is a complex object with validation attributes on its properties, ModelState will always be invalid because you do not post back a value for StatusDescription. As a result you always return the view in the POST method, and because you have not reassigned ViewBag.Status = ...., it is null, hence the error.
Remove property public Status SocialStatus { set; get; } and include
[Display(Name = "Social Status")]
[Required(ErrorMessage = "Please select a status")]
public int SocialStatus { get; set; }
an then in the view, strongly bind to your model using
#Html.LabelFor(m => m.SocialStatus)
#Html.DropDownListFor(m => m.SocialStatus, Model.StatusList, "-Please select-")
#Html.ValidationMessageFor(m => m.SocialStatus)
Then, in the POST method, if ModelState is invalid, populate the select list again before returning the view
if(!ModelState.IsValid)
{
model.StatusList = new SelectList(db.SocialStatuses, "Id", "StatusDescription");
return View(model);
}
// save and redirect
Finally, review What is ViewModel in MVC?.

Binding Drop Down list in asp.net mvc

I am binding my drop down list with database using EF code first approach.My model class is department
public class Department
{
[Key]
public int DepartmentID { get; set; }
[Required]
[Display(Name = "Department")]
public string DepartmentName { get; set; }
}
I am getting all department name in ViewData
ViewData["Departments"] = new SelectList(db.Departments,"DepartmentName");
In my view my code is this
#Html.DropDownList("Departments", "Select Department")
Thid code binding my data but not with name but their are 10 objects like
MyProjectName.Models.Department
MyProjectName.Models.Department
MyProjectName.Models.Department
MyProjectName.Models.Department
MyProjectName.Models.Department
....
Need help what is going wrong in my code.
Try using the correct constructor of the SelectList class taking the collection, the value and text property:
ViewData["Departments"] = new SelectList(db.Departments, "DepartmentID", "DepartmentName");
You might also consider using view models and get rid of the weakly typed ViewData. So, start by defining your view model:
public class MyViewModel
{
public int SelectedDepartmentID { get; set; }
public IEnumerable<SelectListItem> Departments { get; set; }
}
that your controller action will populate and pass to the view:
public ActionResult Index()
{
var model = new MyViewModel();
model.Departments = db.Departments.ToList().Select(d => new SelectListItem
{
Value = d.DepartmentID.ToString(),
Text = d.DepartmentName,
});
return View(model);
}
and in your strongly typed view you could use the strongly typed DropDownListFor version of the helper to generate the dropdown:
#model MyViewModel
...
#Html.DropDownListFor(x => x.SelectedDepartmentID, Model.Departments, "Select Department")

ASP.NET MVC Razor post form containing partial view

I have a ASP.NET view containing a partial view. I reuse the partial view in several other views with different models. The important part of the view looks like this:
#Html.EditorFor(model => model.Title)
//TextArea inserted by partial view
#Html.TextArea("content", new { id = "mycontent" })
//Submit button here
The corresponding model:
public class Entry {
public int ID { get; set; }
public string Title { get; set; }
public string Content { get; set; }
}
And controller method:
public ActionResult Create([Bind(Include = "ID,Title,Content")] Entry entry) {
if (ModelState.IsValid) {
db.Entries.Add(entry);
db.SaveChanges();
...
}
}
How can I submit this form posting the content of the TextArea to the "Content" of the model without using code like #Html.TextArea(model => model.Content)? Do I have to use AJAX?
In your partial view instead of using
#Html.TextArea("content", new { id = "mycontent" })
use this :
#Html.TextArea("Content", new { id = "mycontent" })
and without using #Html.TextAreaFor() data will be bind to model property Content and you can get its value in Controller.

MVC Model State Validation fails on Listbox

I have a simple model which uses a multi select listbox for a many-many EF relationship.
On my Create action, I'm getting the error
The parameter conversion from type 'System.String' to type 'MyProject.Models.Location' failed because no type converter can convert between these types.
I have 2 models, an Article and a Location:
Article.cs
namespace MyProject.Models
{
public class Article
{
public Article()
{
Locations = new List<Location>();
}
[Key]
public int ArticleID { get; set; }
[Required(ErrorMessage = "Article Title is required.")]
[MaxLength(200, ErrorMessage = "Article Title cannot be longer than 200 characters.")]
public string Title { get; set; }
public virtual ICollection<Location> Locations { get; set; }
}
Location.cs:
namespace MyProject.Models
{
public class Location
{
[Key]
public int LocationID { get; set; }
[Required(ErrorMessage = "Location Name is required.")]
[MaxLength(100, ErrorMessage = "Location Name cannot be longer than 100 characters.")]
public string Name { get; set; }
public virtual ICollection<Article> Articles { get; set; }
}
}
I have a ViewModel:
namespace MyProject.ViewModels
{
public class ArticleFormViewModel
{
public Article article { get; set; }
public virtual List<Location> Locations { get; set; }
public ArticleFormViewModel(Article _article, List<Location> _locations)
{
article = _article;
Locations = _locations;
}
}
}
create.cshtml:
#model MyProject.ViewModels.ArticleFormViewModel
<h2>Create</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Article</legend>
<div class="editor-label">
#Html.LabelFor(model => model.article.Title)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.article.Title)
#Html.ValidationMessageFor(model => model.article.Title)
</div>
<h3>Locations</h3>
#Html.ListBoxFor(m=>m.article.Locations,new MultiSelectList(Model.Locations,"LocationID","Name"))
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
Finally my controller actions:
// GET: /Article/Create
public ActionResult Create()
{
var article = new Article();
var AllLocations = from l in db.Locations
select l;
ArticleFormViewModel viewModel = new ArticleFormViewModel(article, AllLocations.ToList());
return View(viewModel);
}
//
// POST: /Article/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Article article)
{
var errors = ModelState.Values.SelectMany(v => v.Errors);
if (ModelState.IsValid)
{
var locations = Request.Form["article.Locations"];
if (locations != null)
{
var locationIDs = locations.Split(',');
foreach (var locationID in locationIDs)
{
int id = int.Parse(locationID);
Location location = db.Locations.Where(l => l.LocationID == id).First();
article.Locations.Add(location);
}
}
db.Articles.Add(article);
db.SaveChanges();
return RedirectToAction("Index");
}
var AllLocations = from l in db.Locations
select l;
ArticleFormViewModel viewModel = new ArticleFormViewModel(article, AllLocations.ToList());
return View(viewModel);
}
This all works relatively well, my Locations listbox is populated properly:
If I do not select a Location then my model is saved properly. If I select one or more locations then my Model.IsValid check fails with the exception
The parameter conversion from type 'System.String' to type 'MyProject.Models.Location' failed because no type converter can convert between these types.
However if I remove the ModelState.IsValid check then despite the error my values are all correctly saved into the database - just that I lose validation for things such as the model title.
Hope someone can help!
Unless you create a type converter, you cannot directly bind the results of your list box directly to a complex object like that. The reason lies in the fact that MVC can only deal with posted HTTP values, which in this case are an array of strings that contain the selected ID's. Those strings do not directly map to your Locations object (ie the number 1 cannot be directly converted to a Locations object with an ID of 1).
Your best bet is to have a list of location ID's in your View Model of type string or int to accept the posted values, then in your post method create the Location objects and fill them with the correct ID's.
FYI, the reason your code works is because you are bypassing the model binding and going directly to the Request.Form collection. You will notice that the bound Article object will not have any Location objects.
EDIT:
I don't even see how your code would work even without this problem. Your ArticleFormViewModel does not have a parameterless constructor, so that will fail in model binding (unless you have a custom model binder).
In any event, what you want to do is this (note, you will have to populate SelectedLocationIDs if you want them to be selected when the view is rendered):
public class ArticleFormViewModel
{
...
List<int> SelectedLocationIDs { get; set; }
...
}
Then, in your view you have:
#Html.ListBoxFor(m=>m.SelectedLocationIDs,
new MultiSelectList(Model.Locations,"LocationID","Name"))
In your Post method, instead of the code that calls Request.Form, you have something like this:
foreach(var locationID in article.SelectedLocationIDs) {
... // look up your locations and add them to the model
}

Resources