I have flights timetable - Schedule view with list of flights
Where I just return View and have some filters and sorting.
Here is part of my view:
#model IEnumerable<AirPortIS.Models.Flight>
<div class="page-header">
<h3>Flights</h3>
</div>
<div id="modDialog" class="modal fade">
<div id="dialogContent" class="modal-dialog"></div>
</div>
<table class="table-bordered table-condensed">
<thead>
<tr>
<th>Flight №</th>
<th>Departure</th>
<th>Destination</th>
<th>#Html.ActionLink("Day", "Schedule", new { sort = ViewBag.SortDay, company = ViewBag.FiltrC, destination = ViewBag.FiltrD })</th>
<th>Departure Time</th>
<th>Arrival Time</th>
<th>Company</th>
<th>#Html.ActionLink("Seats", "Schedule", new { sort = ViewBag.SortSeats, company = ViewBag.FiltrC, destination = ViewBag.FiltrD })</th>
<th>#Html.ActionLink("Cost", "Schedule", new { sort = ViewBag.SortCost, company = ViewBag.FiltrC, destination = ViewBag.FiltrD })</th>
<th>Book ticket</th>
</tr>
</thead>
#foreach (var f in Model)
{
<tr>
<td>#Html.ActionLink(f.FlightId.ToString(), "FlightDetails", new { id = f.FlightId }, new {#class = "flItem" } )</td>
<td>#f.Departure</td>
<td>#f.Destination</td>
<td>#f.Day</td>
<td>#f.DepartureTime</td>
<td>#f.ArrivalTime</td>
<td>#f.Company.Name</td>
<td>#f.Seats</td>
<td>#f.Cost</td>
<td>#Html.ActionLink("Link for booking ticket")</td>
</tr>
}
</table>
I need to do that by clicking on a button "Book ticket" user is getting a page where dropdownlist have a preset value of FlightId.
For example we have a flight №1 and a link "Book ticket",so when user goes the booking ticket page he gets a droptdownlist with preselected value "1"
Here is my ticket Model
public class Tickets
{
public int Id { get; set; }
public int TicketId { get; set; }
public Flight Flight { get; set; }
public string Seat {get;set; }
public string Passenger { get; set; }
public int Flightid { get; set; }
public string Status { get; set; }
}
And part of TicketsController:
public class TicketsController : Controller
{
private readonly AirportContext _db = new AirportContext();
[Authorize]
public ActionResult Tickets()
{
var ticket = _db.Tickets.Include(t => t.Flight);
return View(ticket);
}
[HttpGet]
public ActionResult BookTicket()
{
IEnumerable<SelectListItem> statusList = new SelectList(new List<string> { "Book", "Buy" });
IEnumerable<SelectListItem> flights = new SelectList(_db.Flights.ToList(), "FlightId", "FlightId");
ViewData["flights"] = flights;
ViewData["statusList"] = statusList;
return View();
}
[HttpPost]
public ActionResult BookTicket(Tickets ticket)
{
IEnumerable<SelectListItem> statusList = new SelectList(new List<string> { "Book", "Buy" });
IEnumerable<SelectListItem> flights = new SelectList(_db.Flights.ToList(), "FlightId", "FlightId");
ViewData["flights"] = flights;
ViewData["statusList"] = statusList;
foreach (var c in _db.Tickets.ToList())
{
if ((_db.Tickets.ToList().Exists(x => c.TicketId == ticket.TicketId)) || (ticket.TicketId <= 0))
{
ModelState.AddModelError("TicketId", "Wrong ticket id");
}
if ((_db.Tickets.ToList().Exists(x => c.Seat == ticket.Seat)) && (_db.Tickets.ToList().Exists(x => c.Flightid == ticket.Flightid))
&& (_db.Tickets.ToList().Exists(x => c.TicketId == ticket.TicketId)))
{
ModelState.AddModelError("Seat", "The seat is unavailable");
}
if (_db.Tickets.ToList().Exists(x => c.Passenger == ticket.Passenger))
{
ModelState.AddModelError("Passenger", "The ticket has already bought");
}
}
if (ModelState.IsValid)
{
_db.Tickets.Add(ticket);
_db.SaveChanges();
return RedirectToAction("Tickets");
}
else return View(ticket);
}
And my BookTikcet View:
#model AirPortIS.Models.Tickets
#{
ViewBag.Title = "Book ticket";
}
<h2>Book ticket:</h2>
<form class="form-inline" method="post">
<div>
#Html.ValidationSummary()
</div>
<div class="form-group col-md-2">
Ticket №<br/>
#Html.EditorFor(model => Model.TicketId)
</div>
<div class="form-group col-md-1">
Flight №<br />
#Html.DropDownListFor(model => Model.Flightid, ViewData["flights"] as IEnumerable<SelectListItem>)
</div>
<div class="form-group col-md-2">
Место<br />
#Html.EditorFor(model => Model.Seat)
</div>
<div class="form-group col-md-2">
Passenger Name<br />
#Html.EditorFor(model => Model.Passenger)
</div>
<div class="form-group col-md-2">
Status<br />
#Html.DropDownListFor(model => Model.Status, ViewData["statusList"] as IEnumerable<SelectListItem>)
</div>
<div>
<input class="btn-success" type="submit" value="Book Ticket"/>
</div>
</form>
<div>
<form method="get" action="Tickets">
<button class="btn-danger" type="submit">Cancel</button>
</form>
</div>
I have no idea how to do it,so this whole code above just a standart code for creating a new ticket.
How I should modify code or add something to have this (For example we have a flight №1 and a link "Book ticket",so when user goes the booking ticket page he gets a droptdownlist with preselected value "1",for flight №2 on a page dropdownlist has a preselected value "2" for FlightId.
Hope that my question is clear,sorry if something is wrong written or not quite clear.
You need to pass the value of FlightId as a route (or query string) value to the BookTicket method. You link should be
#Html.ActionLink("Book ticket", "BookTicket", new { id = f.FlightId })
and modify the method to
[HttpGet]
public ActionResult BookTicket(int ID)
{
... // set you SelectLists as above
// Initialize your model and set the Flightid property
var model = new Tickets()
{
Flightid = ID
};
return View(model); // return the model to the view
}
Your dropdownlist will now have the option identified by Flightid selected when you first generate the view.
Note. I recommend you use a view model rather than your Tickets data model which will contain properties IEnumerable<SelectListItem> Flights and IEnumerable<SelectListItem> StatusList rather than using ViewData so that your view are strongly typed using
#Html.DropDownListFor(m => m.Flightid, Model.Flights)
You should also consider refactoring the code to populate the SelectLists into a private method so that you do not repeat code, for example
private void ConfigureViewModel(TicketVM model)
{
model.Flights = new SelectList(...);
model.StatusList = new SelectList(...);
}
Note also that it is a waste of resources to be calling your database to get the SelectList's in the POST method if ModelState is valid. Your code should be
if (!ModelState.IsValid)
{
ConfigureViewModel(model); // only necessary if you need to return the view
return View(model);
}
// save and redirect
Side note: It's unclear why you actually need a dropdownlist for Flightid in the BookTicket view. The user has already selected the flight so why are you giving the option to change it? It might be more appropriate to just render the Flightid as a hidden or readonly input so its submitted back to the POST method.
Related
I am a new to MVC and still learning! I am trying to create a very basic App in my web which allows users to convert money value according to their preference. I made the web APi and was successful to call the service to my forms. However, in my controller I managed to get the currencies (names) to the index view, but cannot post the form back once entering a value in the text box to generate the partial view! What am I doing wrong in my codes?!
Currency Controller
namespace MVC_ATM.Controllers
{
public class CurrencyController : Controller
{
[HttpGet]
// GET: Currency
public ActionResult Index()
{
CurrenciesClient Cur = new CurrenciesClient();
var listCurrency = Cur.findAll();
SelectList list = new SelectList(listCurrency,"Id", "CurrencyName");
ViewBag.listCurrencies = list;
return View();
}
[HttpPost]
public ActionResult Index(Currencies cur)
{
if (!ModelState.IsValid)
{
string errors = string.Join("<br />", ModelState.Values
.SelectMany(x => x.Errors)
.Select(x => x.ErrorMessage));
return new ContentResult { Content = errors };
var rate = Convert.ToDecimal(cur.ConversionRate);
if (cur.CurrencyName == cur.CurrencyName)
{
ModelState.AddModelError("CurrencyCountry", "Can't make the conversion for the same value");
}
else if (cur.CurrencyName != cur.CurrencyName)
{
foreach (var currency in cur.CurrencyName)
{
ViewBag.Theresult = rate * cur.Value;
}
return PartialView("_CurrencyValue");
}
}
return View();
}
}
}
Currencies Model
namespace Project.Model
{
public class Currencies
{
public int Id { get; set; }
public string CurrencyName { get; set; }
public string CurrencyCountry {get; set;}
public decimal Value { get; set; }
public string ConversionRate { get; set; }
}
}
Index View
#model Project.Model.Currencies
#{
ViewBag.Title = "Index";
}
<h2>Currency</h2>
<body>
<div class="converter">
Convert: #Html.TextBoxFor(m => m.ConversionRate, new { #size = "5" })
<div class="form-group">
#Html.Label("Convert from", new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.DropDownList("Currency List", ViewBag.listCurrencies as SelectList, "Please Select a currency")
</div>
</div>
<div class="form-group">
#Html.Label("Convert to", new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.DropDownList("Currency List", ViewBag.listCurrencies as SelectList, "Please Select a currency")
</div>
</div>
<div>
<button type="submit" class="btn btn-primary">Convert</button>
</div>
</div>
</body>
Couple of things to notice, is the POST action and missing form tag in the view . You created a POST action that accepts Currencies model but the form doesn't post that. Only ConversionRate will bind to the model. To get the "Currency From" and "Currency To" and the "Conversion Rate" you will require a different approach/small changes.
ConversionModel.cs a new Model for index page that will capture your required fields.
public class ConversionModel
{
[Required]//decimal would be better but up to you requirement
public decimal ConversionRate { get; set; }
[Required]
public int FromCurrencyId {get;set;}
public SelectList FromCurrencies {get;set;}
[Required]
public int ToCurrencyId {get;set;}
public SelectList ToCurrencies {get;set;}
}
Get: while there is nothing wrong with what you've done, lets use a model approach and tightly bind it.
public ActionResult Index()
{
CurrenciesClient Cur = new CurrenciesClient();
var listCurrency = Cur.findAll();
ConversionModel model = new ConversionModel();
model.FromCurrencies = new SelectList(listCurrency,"Id", "CurrencyName");
model.ToCurrencies = new SelectList(listCurrency,"Id", "CurrencyName");
return View(model);
}
Post: Important thing here to notice is the SelectList will not be posted back. Only the ConversionRate, FromCurrencyId and ToCurrencyId are sent back not the Lists. If error occurs you will need to rebuild the lists and send it back in the model.
[HttpPost]
public ActionResult Index(ConversionModel curModel)
{
if(ModelState.IsValid)
{
if(curModel.FromCurrencyId ==curModel.ToCurrencyId)
{
//do something if same currecnies and return.
}
else
{
//Get the currencyList with rates from db
//use currency ToCurrencyId and FromCurrencyId to fetch the 2 currencies
// perform conversion with curModel.ConversionRate with existing logic
}
}
//Don'f forget to rebuild the Select Lists...
return View(curModel);
}
View:
#model Project.Model.ConversionModel
#{
ViewBag.Title = "Index";
}
#using (Html.BeginForm("Index", "Currency", FormMethod.Post)
{
#Html.TextBoxFor(m => m.ConversionRate, new { #size = "5" })
#* Please check the syntax *#
#Html.DropDownListFor(m => m.FromCurrencyId , Model.FromCurrencies as SelectList)
#Html.DropDownListFor(m => m.ToCurrencyId , Model.ToCurrencies as SelectList)
<button type="submit" class="btn btn-primary">Convert</button>
}
Not a CUT_COPY_PASTE. please do check for errors if any. It is only an approach.
ajax POST probably the next thing to learn... Let us know.
You need to put your items inside a form like this:
#using (Html.BeginForm("Index", "Currency", FormMethod.Post)
{
// Your form items
}
What I have done is search Activedirectory users with a given value being a name. I then create a viewmodel that contains the values Name,Email and description. I then display it as .cshtml on the index.
The thing is with the way I have made it, it only sends through the first user it finds- (If I search for Andrew out of multiple Andrews, it finds them all but returns the first one.)
I want to add them to a list then pretty much do the same thing, but of course on the .cshtml iterate over the list and display the results.
Here is the HomeController.cs code --
public ActionResult Index(IndexViewModel profile)
{
if (ModelState.IsValid)
{
//List<Principal> users = new List<Principal>();
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
UserPrincipal qbeUser = new UserPrincipal(ctx);
qbeUser.DisplayName = profile.Name + "*";
using (PrincipalSearcher srch = new PrincipalSearcher(qbeUser))
{
if(!(srch.FindAll().Count() < 0))
{
foreach(var found in srch.FindAll())
{
//users.Add(found);
IndexViewModel returnmodel = new IndexViewModel(found);
return View(returnmodel);
}
}
}
}
}
return View(profile);
}
The bit to look at in that is the
foreach(var found in srch.FindAll())
{
//users.Add(found);
IndexViewModel returnmodel = new IndexViewModel(found);
return View(returnmodel);
}
Here is the code for the IndexViewModel.cs#
public class IndexViewModel
{
public IndexViewModel(Principal found)
{
Name = found.DisplayName;
Email = found.UserPrincipalName;
Description = found.Description;
}
[Required(ErrorMessage = "Please enter a name")]
[Display(Name = "Persons Name")]
public string Name { get; set; }
public string Email { get; set; }
public string Description { get; set; }
}
And here is the Index.cshtml
/ this just create the input box, validation text and submit button.
<div id="content">
#Html.ValidationSummary(true)
#using (Html.BeginForm("Index", "Home"))
{
<fieldset>
<div class="form-group col-md-12">
#Html.LabelFor(model => model.Name, new { #class = "control-label col-md-2" })
<div class="col-md-4">
#Html.EditorFor(modelItem => Model.Name, new { htmlAttributes = new { #class = "form-control", #style = "width:280px" }, })
#Html.ValidationMessageFor(x => x.Name)
</div>
<div class="col-md-2">
<input type="submit" class="btn btn-default" value="Search">
</div>
<div class="col-md-3">
</div>
</div>
</fieldset>
}
<br>
</div>
This here displays the single result found /
<table id="historyTable" class="table">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>#Model.Name</td>
<td>#Model.Email</td>
<td>#Model.Description</td>
</tr>
</tbody>
</table>
Andy's answer is correct but here is the code you might like to try if you're still having trouble.
First create the new user class to hold the information about the user you want to display :
public class User
{
public string Name { get; set; }
public string Email { get; set; }
public string Description { get; set; }
}
Then amend your IndexViewModel to utilize this new class :
public class IndexViewModel
{
public List<User> FoundUsers {get; set;}
public string Name {get; set;}
public IndexViewModel(List<User> found)
{
this.FoundUsers = found;
}
}
In your controller, you're correct in identifying the problem area, and this would be one way round it :
public ActionResult Index(IndexViewModel profile)
{
if (ModelState.IsValid)
{
List<User> users = new List<User>();
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
UserPrincipal qbeUser = new UserPrincipal(ctx);
qbeUser.DisplayName = profile.Name + "*";
using (PrincipalSearcher srch = new PrincipalSearcher(qbeUser))
{
if(!(srch.FindAll().Count() < 0))
{
foreach(var found in srch.FindAll())
{
users.Add(new User() {
Name = found.Name,
Email = found.Email,
Description = found.Description
});
}
}
IndexViewModel returnmodel = new IndexViewModel(users);
return View(returnmodel);
}
}
}
return View(profile);
}
So in the controller you are now populating your view model with a List<User> that you can iterate over in your view :
<table id="historyTable" class="table">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Description</th>
</tr>
</thead>
<tbody>
#foreach(var user in Model.FoundUsers)
{
<tr>
<td>#user.Name</td>
<td>#user.Email</td>
<td>#user.Description</td>
</tr>
}
</tbody>
</table>
I think you want a User Model first. Then have your IndexViewModel has a List<User>. In your foreach, create a new User class and add that to your list. Create the IndexViewModel outside the foreach and return it after the foreach. Then loop through the list in your view. This is pretty common, if you google you'll find examples.
It's time to ask the internet. I'm a student and really new to MVC + coding in general, but I can't for the life of me figure out why this isn't working. Probably something really obvious. :/
I have a View (AddMemberToGroup) that is strongly-typed to a viewmodel (PersonGroupingViewModel). What am I trying to do is add a Person to a Group, with the user selecting a group from a dropdown list in the View.
Viewmodel:
public class PersonGroupingViewModel
{
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set;}
public List<Group> Memberships { get; set; }
public SelectList AllGroups { get; set; }
public int SelectedGroupId { get; set; }
}
Controller:
//GET People/AddToGroup
public ActionResult AddMemberToGroup(int? PersonId)
{
if (PersonId == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Person person = db.People.Find(PersonId);
if (person == null)
{
return HttpNotFound();
}
SelectList allthegroups = new SelectList(db.Groups, "GroupId", "Name");
PersonGroupingViewModel viewmodel = new PersonGroupingViewModel();
viewmodel.PersonId = person.PersonId;
viewmodel.FirstName = person.FirstName;
viewmodel.LastName = person.LastName;
viewmodel.AllGroups = allthegroups;
//viewmodel.Memberships cannot be empty
if (person.Memberships == null)
{
viewmodel.Memberships = new List<Group>();
}
else
{
viewmodel.Memberships = person.Memberships.ToList();
}
return View(viewmodel);
}
//POST: People/AddToGroup
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult AddMemberToGroup(PersonGroupingViewModel vm)
{
SelectList allthegroups = new SelectList(db.Groups, "GroupId", "Name");
vm.AllGroups = allthegroups;
int PersonId = vm.PersonId;
int GroupId = vm.SelectedGroupId;
Person person = db.People.Find(PersonId);
Group group = db.Groups.Find(GroupId);
group.Members.Add(person);
db.SaveChanges();
return View(vm);
}
View form (strongly-typed to PersonGroupingViewModel):
Add Member To Group
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div>
<h4>Groups #Html.DisplayFor(model => model.FirstName) is already in:</h4>
<ul>
#foreach (var group in Model.Memberships)
{
<li>#Html.DisplayFor(modelItem => group.Name)</li>
}
</ul>
</div>
<div class="form-horizontal">
<h4>Add #Html.DisplayFor(model => model.FirstName) #Html.DisplayFor(model => model.LastName) To Group:</h4>
#Html.HiddenFor(model => model.PersonId)
<div class="form-group">
<label>Group: </label>
#Html.DropDownListFor(m => m.SelectedGroupId, Model.AllGroups, String.Empty)
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Add To Group" class="btn btn-default" />
</div>
</div>
</div>
}
When I click 'submit' in the browser I get back a URL:
localhost:54696/People/AddMemberToGroup?PersonId=1
Along with exception "Object reference not set to an instance of an object" on the line Group group = db.Groups.Find(GroupId); in the controller.
Is the viewmodel coming back empty or not at all? I am not sure what is going on and would appreciate someone attempting explaining it in small words. I've done a lot of Googling and tried several suggestions from that but in the end I feel as though I'm going in circles.
Solved it...
group.Members was null so group.Members.Add(person) didn't work. Wrote in an if/else statement to instantiate a new member list if the list is null, and it works fine:
if (group.Members == null)
{
group.Members = new List<Person>();
group.Members.Add(person);
}
else {
group.Members.Add(person);
}
I have the following DropDownList in an ASP.NET MVC cshtml page:
#Html.DropDownListFor(model => model.GroupId, (IEnumerable<SelectListItem>)ViewBag.PossibleGroups, "")
The property is defined as public virtual Nullable<int> GroupId
Although GroupId is Nullable the select menu won't accept an empty option. If I try to save the model without selecting a group, I get the following error message:
The field GroupId must be a number.
The select menu is being rendered like this:
<select data-val="true" data-val-number="The field GroupId must be a number." id="GroupId" name="GroupId" class="input-validation-error" data-hasqtip="0" aria-describedby="qtip-0">
<option value=""></option>
<option value="1">Test Group</option>
</select>
And no, GroupId is not decorated with the [Required] attribute.
How can I make it so the page will accept an empty value for the GroupId?
P.S. The GroupId type (Nullable<int>) is code-generated. I use the database-first scheme. I don't know though what is the difference between <Nullable>int and int?
UPDATE:
Even having zero as value for the empty select item does not pass the non-obstrusive (JavaScript) validation. However, putting a value of -1 passes both the client side and the server side validation. So for now, I am using this value and in the controller, I set GroupId to null if it equal to -1.
I cannot believe there no simpler solution to such a simple problem. Is this is a bug in ASP.NET MVC 3?
Create Class for Model Bind
public class BindDropDown
{
public Nullable<int> ID{ get; set; }
[Required(ErrorMessage = "Enter name")]
public string Name{ get; set; }
}
Create Controller
namespace DropDown.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
ViewBag.InterviewList = NumberList;
return View(new BindDropDown());
}
[HttpPost]
public ActionResult Index(BindDropDown d)
{
if (ModelState.IsValid)
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
}
else
{
ViewBag.Message = "error";
}
ViewBag.NumberList = NumberList;
return View(new BindDropDown());
}
public ActionResult About()
{
return View();
}
public static IEnumerable<SelectListItem> NumberList
{
get
{
IEnumerable<NumberClass> interviewAppeals = Enum.GetValues(typeof(NumberClass))
.Cast<NumberClass>();
return from item in interviewAppeals
select new SelectListItem
{
Text = item.ToString(),
Value = ((int)item).ToString()
};
}
}
}
public enum NumberClass
{
One = 1,
Two = 2,
Three = 3
}
}
Index.cshtml
#using DropDown.Models
#model BindDropDown
#{
ViewBag.Title = "Home Page";
}
<h2>#ViewBag.Message</h2>
<p>
</p>
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { id = "frmOnline" }))
{
#Html.ValidationSummary(false)
<div class="w100">
<div class="fleft">
<label>ID :</label>
</div>
<div class="fleft">
#Html.DropDownListFor(model => model.ID, (IEnumerable<SelectListItem>)ViewBag.NumberList, "")
</div>
</div>
<div class="w100">
<div class="fleft">
<label>Name :</label>
</div>
<div class="fleft">
#Html.TextBoxFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
</div>
<div class="w100 clear">
<label> </label>
<div class="fleft">
<input type="submit" value="Save" class="button green" />
#Html.ActionLink("Back", "GetAllAction", null, new { #class = "button gray" })
</div>
</div>
}
Try this to display blank values in drop down list
Model
public class Products {
public int pid {get;set;}
public String sValue {get; set;}
}
Controller
List<Products> lstProducts = new List<Products>()
{
new Products() {pid=0, sValue=""},
new Products() {pid=1, sValue="One"},
new Products() {pid=2, sValue="Two"}
};
ViewBag.products = new SelectList(lstProducts, "pid", "sValue");
View
#Html.DropDownList("products",#ViewBag.products as List<SelectListItems>)
I have a page to create objects, and in this I have a DropDownList. If I select an item from the list my page will save correctly, however if I don't select an item it looks like it fails on a postback as the objects will be null.
What I want is to try and validate whether the user has selected an item (default is "Please Select...").
I have code that will check and see in the controller if the item is null, but it's how do I then display a message? Keeping all other details if they exist.
public ActionResult Create(int objectId = 0)
{
var resultModel = new MyObjectModel();
resultModel.AllObjects = new SelectList(_system.GetAllObjects(objectId));
// GetAllObjects juts returns a list of items for the drop down.
return View(resultModel);
}
[HttpPost]
public ActionResult Create(int? objectId, FormCollection collection)
{
try
{
int objectIdNotNull = 0;
if (objectId > 1)
{
objectIdNotNull = (int) objectId;
}
string objectName = collection["Name"];
int objectTypeSelectedResult = 1;
int.TryParse(collection["dllList"], out objectTypeSelectedResult);
if (!Convert.ToBoolean(objectTypeSelectedResult))
{
// So here I have discovered nothing has been selected, and I want to alert the user
return RedirectToAction("Create",
new {ObjectId = objectIdNotNull, error = "Please select an Object Type"});
}
....
return RedirectToAction(...)
}
catch
{
return View();
}
}
The above code just goes to the Create page but doesn't display an error. In my View for Create I have the following line which I assumed would display any errors:
#ViewData["error"]
Additional code
Model:
using System.Collections.Generic;
using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;
namespace MyNameSpace
{
public class MyObjectModel
{
[Required(ErrorMessage = "Please select an Object Type")]
public SelectList AllObjects { get; set; } // I populate the drop down with this list
}
}
View:
#model MyNameSpace.MyObjectModel
#{
ViewBag.Title = "Create";
}
<h2>Create </h2>
<p class="text-error">#ViewData["Message"]</p>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"> </script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"> </script>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<div class="editor-label">
#Html.LabelFor(model => model.MyObject.Name)
</div>
<div class="editor-field">
#Html.TextBoxFor(model=>model.MyObjectType.Name, new {style="width: 750px"})
#Html.ValidationMessageFor(model => model.MyObjectType.Name)
</div>
<div>
<label for="ddlList">Choose Type</label>
#if (#Model != null)
{
#Html.DropDownList("ddlList", Model.AllObjects, "Please Select...")
#Html.ValidationMessageFor(model => model.AllObjects, "An object must be selected", new { #class = "redText"})
}
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
You are validating the SelectList which is wrong
[Required(ErrorMessage = "An object must be selected")]
public SelectList AllObjects { get; set; }
Your Model should be
[Required(ErrorMessage = "Please select an Object Type")]
public int ObjectId { get; set; }
public string ObjectName { get; set; }
Your Controller(no need for form collection thats the whole point of MVC)
public ActionResult Create(int Id = 0)
{
MyObjectModel resultModel = new MyObjectModel();
var ObjectResultList = _system.GetAllObjects(Id);
var ObjectSelectList = new SelectList(ObjectResultList, "id", "Name");
ViewBag.ObjectList = ObjectSelectList;
return View(resultModel);
}
Your Post controller:
[HttpPost]
public ActionResult Create(MyObjectModel o)
{
try
{
if (ModelState.IsValid)
{
//It's valid , your code here!
return RedirectToAction("ObjectCreated", new { id = o.objectId });
}
else
{
var errors = ModelState
.Where(x => x.Value.Errors.Count > 0)
.Select(x => new { x.Key, x.Value.Errors })
.ToArray();
}
}
}
catch (Exception ex)
{
Response.Write(ex.InnerException.Message);
}
//If we get here it means the model is not valid, We're in trouble
//then redisplay the view repopulate the dropdown
var ObjectResultList = _system.GetAllObjects(objectId);
var ObjectSelectList = new SelectList(ObjectResultList, "id", "value");
ViewBag.ObjectList = ObjectSelectList;
return View(o);
}
Your View should be strongly Typed
<div class="editor-label">
#Html.LabelFor(model => model.ObjectId)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.ObjectId,
(IEnumerable<SelectListItem>)ViewBag.ObjectList, "-- Select One Object --")
#Html.ValidationMessageFor(model => model.ObjectId)
</div>