Checking if DropDownListFor item is selected in html - c#

I have cshtml page like this:
<div class="form-group">
#Html.LabelFor(m => m.QuestionnaireName, new { #class = "col-md-2 control-label" })
#Html.DropDownListFor(m => m.QuestionnaireName, Model.Questionnaires, new { #id = "ddlQuestionnaires", #class = "form-control" })
#Html.Label("Questions list:", new { #class = "col-md-2 control-label" })
// here: how to check if any dropdownlistfor value is selected?
</div>
Like i said in comment above. I want to check if value of DropDownListFor is selected and in case yes, build dynamicaly (table or list) for element of chosen Questionnaire.
Let say that Questionnaire.name is unique id and Questionnaire contain List Questions.
here is my model:
public class FillQuestionnaireModel
{
[Required]
[DataType(DataType.Text)]
[Display(Name = "Select questionnaire")]
public string QuestionnaireName { get; set; }
public SelectList Questionnaires { get; set; }
}
and my controller actions:
public ActionResult Fill()
{
QuestionnaireServiceReference.QuestionnaireServiceClient client = new QuestionnaireServiceReference.QuestionnaireServiceClient();
FillQuestionnaireModel model = new FillQuestionnaireModel();
List<QuestionnaireServiceReference.Questionnaire> Questionnaires = client.GetAllQuestionnaires().ToList();
Questionnaires.Insert(0, new QuestionnaireServiceReference.Questionnaire() { questionnaire_id = 0, name = "--Select--" });
model.Questionnaires = new SelectList(Questionnaires, "name", "name");
return View(model);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Fill(FillQuestionnaireModel model)
{
if (!ModelState.IsValid)
{
string SelectedValue = model.QuestionnaireName;
return View(model);
}
else
{
QuestionnaireServiceReference.QuestionnaireServiceClient client = new QuestionnaireServiceReference.QuestionnaireServiceClient();
List<QuestionnaireServiceReference.Questionnaire> Questionnaires = client.GetAllQuestionnaires().ToList();
Questionnaires.Insert(0, new QuestionnaireServiceReference.Questionnaire() { questionnaire_id = 0, name = "--Select--" });
model.Questionnaires = new SelectList(Questionnaires, "name", "name");
}
return View(model);
}

Related

After Implementing Validations in c#, I face problems in updating records

I'm working on a project in Asp.net c# MVC and I want to implement validations on a model using Data Annotations as follows:
public class MainRepository
{
public int Id { get; set; }
[Required]
public int Category_Id { get; set; }
[Required]
public int Department_Id { get; set; }
[Required]
public DateTime Start_Date { get; set; }
}
I have a controller as PM controller with the following Register Method.
public ActionResult Register()
{
var event_category = _context.Event_Categories.ToList();
var departments = _context.dept.ToList();
var vm = new InsertEdit_ViewModel
{
evt_catgrss = event_category,
depts = departmetns
};
return View(vm);
}
Here is the InsertEdit view Model:
public class InsertEdit_ViewModel
{
public MainRepository Main_RP { get; set; }
public List<Event_Categories> evt_catgrss { get; set; }
public List<Departments> depts { get; set; }
}
public InsertEdit_ViewModel()
{
Main_RP = new MainRepository();
evt_catgrss = new List<Event_Categories>();
depts = new List<Departments>();
}
}
And this is the view for the Register Method:
#model Project.ViewModel.InsertEdit_ViewModel
#using (Html.BeginForm("Store", "PM", FormMethod.Post, new { enctype = "multipart/form-data"}))
{
<div class="form-group">
<label>Event Category</label><br/>
#Html.DropDownListFor(a => a.Main_RP.Category_Id, new SelectList(Model.evt_catgrss, "Id", "type_of_event"), "Select a category", new { #class = "form-control btn-group dropdown-menu" })
#Html.ValidationMessageFor(a=> a.Main_RP.Category_Id)
</div>
<div class="form-group">
<label>Department</label>
#Html.DropDownListFor(a => a.Main_RP.Department_Id, new SelectList(Model.depts, "Id", "DepartmentName"), "Select Employee Department", new { #class = "form-control btn-group dropdown-menu" })
#Html.ValidationMessageFor(a=> a.Main_RP.Department_Id)
</div>
<div class="form-group">
<label>Start Date</label>
#Html.TextBoxFor(a => a.Main_RP.Start_Date, "Select Estimated Date of Start", new { #class = "form-control", #readonly = "readonly", #style = "cursor :default; background-color:#d4d4d4; font-size:11px;" })
#Html.ValidationMessageFor(a=> a.Main_RP.Start_Date)
</div>
#Html.AntiForgeryToken();
<button class="btn btn-primary">Register</button>
}
And finally this is the Store Method within the PM controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Store(InsertEdit_ViewModel pmI)
{
if (!ModelState.IsValid)
{
var event_category = _context.Event_Categories.ToList();
var departments = _context.dept.ToList();
var vm = new InsertEdit_ViewModel
{
evt_catgrss = event_category,
depts = departmetns
};
return View("Register",vm);
}
_context.main_repz.Add(pmI.Main_RP);
_context.SaveChanges();
return RedirectToAction("Index", "SystemAdmin");
}
Now till this portion everything is working fine including the validations. But I'm facing issues whenever i want to change the date of an event with another method as follows:
This is the Change Method within PM Controller:
public ActionResult Change(int? Id)
{
var EventDetails = _context.main_repz.Include(a => a.Event_Categories).SingleOrDefault(a => a.Id == Id);
var vm = new ChangeVM()
{
Main_RP = EventDetails
};
return View(vm);
}
This is the ChangeVM (ViewModel)
public class ChangeVM
{
public MainRepository Main_RP { get; set; }
public ChangeVM()
{
Main_RP = new MainRepository();
}
}
This is the view for Change Method
#model FEFA_MIS.ViewModel.ChangeVM
#using (Html.BeginForm("ChangeDate", "PM", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="form-group">
<label>Select New Date</label>
#Html.TextBoxFor(a => a.Main_RP.Start_Date, "{0:}", new { #class = "form-control"})
#Html.ValidationMessageFor(a=> a.Main_RP.Start_Date)
</div>
#Html.AntiForgeryToken();
#Html.HiddenFor(a => a.Main_RP.Id);
<button class="btn btn-primary">Request</button>
}
And Finally this is the ChangeDate Method within PM controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ChangeDate(ChangeVM ap)
{
if (!ModelState.IsValid)
{
return View("Change",ap);
}
var item = _context.main_repz.Single(a => a.Id == ap.Main_RP.Id);
item.Start_Date = ap.Main_RP.Start_Date;
_context.SaveChanges();
return RedirectToAction("Success", "PM");
}
Now this time it is not working properly,
Means, If I don’t select the new date It gives the validation message, which is perfectly fine.
But when I select the new date It does not proceed as I think it is expecting the Category_Id and Department_Id too, but they are no longer part of ChangeDate Method, they were part of Store Method used for Registration.
If i'm not mistaken, I think all of the three [Required] fields in the model, come under one ModelState, but anyhow I'm stuck here...
what can be the solution? Can the View Models access only specific attributes instead of calling the whole class (as in my case)?
I would not use the MainRepository in your ChangeVM. This includes all properties. Instead, limit your ViewModels to only those fields, that you are actually processing in that view. So, just add Id and Start_Date to the ChangeVM, and you should be good.
When you try to do update operation you must provide required properties value.This is mandatory.
Thanks

Setting the selectedvalue in dropdownlist from database MVC

I'm trying to get the original selectedvalue from the database in the Edit view. I need for the original value to be displayed, and from there the user can choose another value.
ViewModel
public Local Local { get; set; }
public SelectList Estados { get; set; }
public int IdEstadoSeleccionado { get; set; }
public SelectList Proveedores { get; set; }
public int IdProveedorSeleccionado { get; set; }
public LocalEditarViewModel(Local local, List<Estado> estados, List<Proveedor> proveedores,int estadoid)
{
this.Local = local;
this.Estados = new SelectList(estados, "Id", "State");
this.Proveedores = new SelectList(proveedores, "Id", "Nombre");
}
Controller
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Local local = db.Locales.Find(id);
List<Estado> estados;
List<Proveedor> proveedores;
using (AutoContex db = new AutoContex())
{
estados = db.Estados.ToList();
proveedores = db.Proveedores.ToList();
}
LocalEditarViewModel vm = new LocalEditarViewModel(local, estados, proveedores);
if (local == null)
{
return HttpNotFound();
}
Session["LocalId"] = local.Id;
return View(vm);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(LocalEditarViewModel vm)
{
using (AutoContex db = new AutoContex())
{
if (ModelState.IsValid)
{
string id = Session["LocalId"].ToString();
int localId = 0;
int.TryParse(id, out localId);
vm.Local.Id = localId;
vm.Local.Proveedor = db.Proveedores.Find(vm.IdProveedorSeleccionado);
vm.Local.Estado = db.Estados.Find(vm.IdEstadoSeleccionado);
Local original = db.Locales.Find(localId);
original.Estado = vm.Local.Estado;
original.Proveedor = vm.Local.Proveedor;
original.Id = localId;
original.Direccion = vm.Local.Direccion;
original.FechaIngreso = vm.Local.FechaIngreso;
//original.FechaInstalacion = vm.Local.FechaInstalacion;
original.Localidad = vm.Local.Localidad;
original.NombreComercio = vm.Local.NombreComercio;
original.NombreComercioUnificado = vm.Local.NombreComercioUnificado;
original.Provincia = vm.Local.Provincia;
original.Telefono = vm.Local.Telefono;
original.ViejoId = vm.Local.ViejoId;
original.NuevoId = vm.Local.NuevoId;
db.SaveChanges();
}
}
return View(vm);
}
VIEW
<div class="form-group">
#Html.LabelFor(model => model.Estados, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.IdEstadoSeleccionado, Model.Estados)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Proveedores, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.IdProveedorSeleccionado, Model.Proveedores,"--Select--")
</div>
In your Edit GET action method, set the value for IdProveedorSeleccionado and IdProveedorSeleccionado properties.
vm.IdProveedorSeleccionado = local.IdProveedorSeleccionado ;
vm.IdProveedorSeleccionado = local.IdProveedorSeleccionado ;
return View(vm);
The DropDownListFor helper method will select the option which has matching value attribute value as of these property values.

Render ViewModel errors on View if ModelState is not valid [duplicate]

This question already has an answer here:
MVC model validation
(1 answer)
Closed 6 years ago.
I have a form like following in my MVC application:
#using (Html.BeginForm("Register", "User", FormMethod.Post))
{
<div>
#Html.TextBoxFor(m => m.FirstName, new { placeholder = "First name", #class = "form-control", #type = "text" })
</div>
<div>
#Html.TextBoxFor(m => m.LastName, new { placeholder = "Last name", #class = "form-control", #type = "text" })
</div>
<div>
#Html.TextBoxFor(m => m.Email, new { placeholder = "Email", #class = "form-control", #type = "email" })
</div>
<div>
#Html.TextBoxFor(m => m.Password, new { placeholder = "Password", #class = "form-control", #type = "password" })
</div>
<div>
#Html.TextBoxFor(m => m.PasswordConfirm, new { placeholder = "Confirm password", #class = "form-control", #type = "password" })
</div>
<div>
#Html.DropDownListFor(model => model.SelectedCountryId, Model.Countries, new { #class="select2_single form-control select2-hidden-accessible", #tabindex = "-1" })
</div>
<div>
<input class="btn btn-default submit" type="submit" value="Register" />
</div>
}
My ViewModel looks like following:
public class UserRegistrationViewModel
{
[Required(ErrorMessage = "First name is required!")]
public string FirstName { get; set; }
[Required(ErrorMessage = "Last name is required!")]
public string LastName { get; set; }
[Required(ErrorMessage = "Email name is required!")]
public string Email { get; set; }
[Required(ErrorMessage = "Password name is required!")]
public string Password { get; set; }
[Required(ErrorMessage = "Password confirmation name is required!")]
public string PasswordConfirm { get; set; }
public int SelectedCountryId { get; set; }
[Required(ErrorMessage = "Country needs to be selected!")]
public SelectList Countries { get; set; }
}
And these are my two actions:
public ActionResult Index()
{
var model = new UserRegistrationViewModel();
var countries = Connection.ctx.Countries.OrderBy(x => x.CountryName).ToList();
model.Countries = new SelectList(countries, "CountryId", "CountryName");
return View(model);
}
[HttpPost]
public ActionResult Register(UserRegistrationViewModel model)
{
if (ModelState.IsValid)
{
var user = new Users();
user.FirstName = model.FirstName;
user.LastName =model.LastName;
user.Email = model.Email;
user.PasswordSalt = Helpers.PasswordHelper.CreateSalt(40);
user.PasswordHash = Helpers.PasswordHelper.CreatePasswordHash(model.Password, user.PasswordSalt);
user.CountryId = Convert.ToInt32(model.SelectedCountryId);
user.Active = true;
Connection.ctx.Users.Add(user);
Connection.ctx.SaveChanges();
var role = new UserRoles();
role.RoleId = 2;
role.UserId = user.UserId;
role.Active = true;
user.UserRoles.Add(role);
Connection.ctx.SaveChanges();
return RedirectToAction("Index");
}
return null;
}
Now my question here is what do I do if the model state is not valid (ie. display the error messages that I've set up in my ViewModel)???
Do I just do `return View(); or ??
I need to render those messages on my view now...
Whenever I get an invalid form being submitted, I return the View() back for them to correct the issue. Taking them to an error page where they would have to come back to the form and start again would frustrate the user. Give them back the invalid form and tell them what needs correcting.
Now, what needs correcting can be read from the ViewBag(). Or you can have inside you Model some properties that will hold your error message for the user and display them if they are not null.
In the case of an invalid model state, you can just return the current view with the model as a parameter:
if (!ModelState.IsValid)
{
return View(model);
}
EDIT: In your html, add the html elements to show the validation messages:
#Html.ValidationMessageFor(model => model.FirstName)

MVC Null exception on Model passed in ViewModel to View when I want to acces it via Model. not #Html

I am having problem in MVC with my Model which is passed in ViewModel to View. I have database with several tables on which I called entity framework to create models.
This is my ViewModel:
namespace BP_final.ViewModels
{
public class AllDBModels
{
public Models.Graph AllGraphs { get; set; }
public IEnumerable<NAMTAR_STUDYROOMS> Namtar_studyrooms { get; set; }
public IEnumerable<NAMTAR_STATS_STUDYROOMS> Namtar_stats_studyrooms { get; set; }
public List<bp_data> bp_data { get; set; }
public Models.Report reports { get; set; }
public AllDBModels()
{
Namtar_studyrooms = new List<NAMTAR_STUDYROOMS>();
reports = new Models.Report() { RoomNumber = "1"};
AllGraphs = new Models.Graph();
}
}
}
I create few properties for my tables and I initialize some of them.
Then in my controller i call my ViewModel class so it should create instance:
public ActionResult Index()
{
AllDBModels allModels = new AllDBModels();
allModels.AllGraphs = new Graph();
allModels.AllGraphs.Charts = new List<Highcharts>();
ChartsModel model = new ChartsModel();
model.Charts = new List<Highcharts>();
...
...
return View(allModels);
In my View I get the ViewModel, then I want to use it. I call DropDownListFor:
#model BP_final.ViewModels.AllDBModels
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
...
...
<div class="form-group">
#Html.LabelFor(model => model.reports.RoomNumber, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10 ">
#Html.DropDownListFor(model => model.reports.RoomNumber, new SelectList(
/*this fails*/ Model.Namtar_studyrooms.Select(x => new SelectListItem{ Value = x.ID.ToString(), Text = x.NAME }), "Value", "Text", 2
), new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.reports.Graph, "", new { #class = "text-danger" })
</div>
</div>
I want to populate the dropdown options with data from namtar_studyrooms table/model but can't. It is working for the first labmda expression which is taking from #Html (as model.reports while model is my viewmodel) but the next lamda I use with Model.Namtar_studyrooms.Select( does not work and I am getting null exception on Model. I looked on the internet and it seems I have everything as everyone else and I cant seem to find what is wrong
Add the dropdown collection to ViewBag.
In Controller;
public ActionResult Index()
{
AllDBModels allModels = new AllDBModels();
allModels.AllGraphs = new Graph();
allModels.AllGraphs.Charts = new List<Highcharts>();
ChartsModel model = new ChartsModel();
model.Charts = new List<Highcharts>();
ViewBag.Rooms = db.namtar_studyrooms.ToList() //the collection here (you should changeit, just an example)
}
In View;
#Html.DropDownListFor(model => model.reports.RoomNumber, new SelectList(ViewBag.Rooms, "RoomID", "RoomNameForDisplay"), "Select Room for default", new { #class = "form-control" })
Hope Helps.

FluentValidation Improperly Validating Model from DropDown

I have the following two models (stripped to relevant parts):
Models\Department.cs:
public class DepartmentValidator : AbstractValidator<Department> {
public DepartmentValidator() {
RuleFor(d => d.Name)
.NotEmpty().WithMessage("You must specify a name.")
.Length(0, 256).WithMessage("The name cannot exceed 256 characters in length.");
}
}
[Validator(typeof(DepartmentValidator))]
public class Department {
public int Id { get; set; }
[Column(TypeName = "nvarchar")]
[MaxLength(256)]
public string Name { get; set; }
}
Models\FacultyMember.cs:
public class FacultyValidator : AbstractValidator<FacultyMember> {
public FacultyValidator() {
RuleFor(f => f.Name)
.NotEmpty().WithMessage("You must specify a name.")
.Length(0, 64).WithMessage("The name cannot exceed 64 characters in length.");
}
}
[Validator(typeof(FacultyValidator))]
public class FacultyMember {
public int Id { get; set; }
[Column(TypeName = "nvarchar")]
[MaxLength(64)]
public string Name { get; set; }
public virtual ICollection<Department> Departments { get; set; }
public FacultyMember() {
Departments = new HashSet<Department>();
}
}
I have the following controller code:
Controllers\FacultyController.cs:
// GET: Faculty/Create
public ActionResult Create() {
// Get Departments.
var departmentList = db.Departments.ToList().Select(department => new SelectListItem {
Value = department.Id.ToString(),
Text = department.Name
}).ToList();
ViewBag.DepartmentList = departmentList;
var facultyMember = new FacultyMember();
facultyMember.Departments.Add(new Department()); // Create a single dropdown for a department to start out.
return View(facultyMember);
}
// POST: Faculty/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Id,Name,Departments")] FacultyMember facultyMember) {
// Get Departments.
var departmentList = db.Departments.ToList().Select(department => new SelectListItem {
Value = department.Id.ToString(),
Text = department.Name
}).ToList();
ViewBag.DepartmentList = departmentList;
if (!ModelState.IsValid) { // Problem here...
return View(facultyMember);
}
db.Faculty.Add(facultyMember);
db.SaveChanges();
return RedirectToAction("Index");
}
Views\Faculty\Create.cshtml:
...
<div class="form-group">
#Html.LabelFor(model => model.Departments, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Departments, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Departments, "", new { #class = "text-danger" })
</div>
</div>
...
Views\Shared\EditorTemplates\Department.cshtml:
#model MyProject.Models.Department
#Html.DropDownListFor(model => model.Id, ViewBag.DepartmentList as IEnumerable<SelectListItem>, "Select...", new { #class = "form-control" })
So, when I navigate to the create faculty page, everything displays properly; the 'Departments' field has a dropdown list with the departments in my database. However, upon submitting the form, my model state is invalid (see comment in code above). Upon further inspection, it seems that FluentValidation is spitting out an error because my "Name" field is null. That's exactly what it should do when I'm creating/editing departments, but for this dropdown in faculty members, it shouldn't be validating the entire department, should it? The only thing the dropdown is sending back is the Id, as I've specified.
The only thing that this dropdown sends is the Id of the department, which is properly received. So, what do I need to do to make this work? My goal is to have a dynamic set of dropdown lists, each populated with existing departments in the database. Similar to this example.
Please let me know if anything else needs explaining.
The solution, as explained by Stephen Muecke, was to create a view model to represent all data I wanted to pass to the form and back.
ViewModel\FacultyMemberViewModel.cs:
public class FacultyMemberViewModelValidator : AbstractValidator<FacultyMemberViewModel> {
public FacultyMemberViewModelValidator() {
RuleFor(f => f.Name)
.NotEmpty().WithMessage("You must specify a name.")
.Length(0, 64).WithMessage("The name cannot exceed 64 characters in length.");
RuleFor(s => s.SelectedDepartments)
.NotEmpty().WithMessage("You must specify at least one department.")
}
}
[Validator(typeof(FacultyMemberViewModelValidator))]
public class FacultyMemberViewModel {
public int Id { get; set; }
public string Name { get; set; }
public int[] SelectedDepartments { get; set; }
[DisplayName("Departments")]
public IEnumerable<SelectListItem> DepartmentList { get; set; }
}
Views\Faculty\Create.cshtml:
...
<div class="form-group">
#Html.LabelFor(model => model.DepartmentList, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.ListBoxFor(model => model.SelectedDepartments, Model.DepartmentList, new { #class = "form-control" }) #Html.ValidationMessageFor(model => model.SelectedDepartments, "", new { #class = "text-danger" })
</div>
</div>
...
Controllers\FacultyController.cs:
// GET: Faculty/Create
public ActionResult Create() {
var facultyMemberViewModel = new FacultyMemberViewModel {
DepartmentList = GetDepartmentList()
};
return View(facultyMemberViewModel);
}
// POST: Faculty/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Id,Name,SelectedDepartments,DepartmentList")] FacultyMemberViewModel facultyMemberViewModel) {
if (!ModelState.IsValid) {
// Re-set the Department list.
if (facultyMemberViewModel.DepartmentList == null) {
facultyMemberViewModel.DepartmentList = GetDepartmentList();
}
return View(facultyMemberViewModel);
}
var facultyMember = new FacultyMember {
Id = facultyMemberViewModel.Id,
Name = facultyMemberViewModel.Name,
};
foreach (var departmentId in facultyMemberViewModel.SelectedDepartments) {
// I'm assuming this is safe to do (aka the records exist in the database)...
facultyMember.Departments.Add(db.Departments.Find(departmentId));
}
db.Faculty.Add(facultyMember);
db.SaveChanges();
return RedirectToAction("Index");
}

Categories