i have a dropdownlist getting data from data base
it contains 4 data :
my controller :
public ActionResult Index()
{
ViewBag.Postes = _db.Postes.ToList();
return View();
}
[HttpPost]
public ActionResult Index( Poste poste,string num_cin="R346399")
{
if (ModelState.IsValid)
{
if (poste.Id == 3)
{
return RedirectToAction("Inscription", "Candidat");
}
return View(poste);
}
}
my view
#Html.DropDownListFor(model => model.Id,
new SelectList(ViewBag.Postes, "Id", "intitule_poste"),"choisir le poste")
the problem that if i choose a value from dropdownlist that !=3 it's give me an error "that items must be not null "
You view includes #Html.DropDownListFor() which is generated based on the value of ViewBag.Postes. When you return the view (i.e. when poste.Id is not equal to 3) you must reassign the value of ViewBag.Postes
if (ModelState.IsValid)
{
if (poste.Id == 3)
{
return RedirectToAction("Inscription", "Candidat");
}
ViewBag.Poste = _db.Postes.ToList(); // reassign collection for dropdown
return View(poste);
}
Related
I created a button that directs to another page with 3 tabs.
These 3 subtabs has different input text and only using 1 Action [HttpGet].
These are my cases.
I want to save only first tab data, the 2 tabs value will be null
I want to save only second data, the 1st tab and 3rd tab will be null
I want to save all the text input that I've typed under 1st tab, 2nd tab, and 3rd tab.
Here is my code:
[HttpGet]
public ActionResult Create_Data(int productId)
{
var model = BigViewModel();
///rest of code
return View(model)
}
[HttpPost]
public ActionResult Create_Data(BigViewModel model, int productId)
{
int experimentForOverloading = 0;
string experimentAgain = ""
// validates if first tab and doesn't have data inputted, will redirect to Create_SecondTab. Below is just for testing
if (model.FirstTabName == null && model.ThirdTabDirectory == null)
{
// this is where I want to go to route the new Action. But I don't know what to do..
return RedirectToAction("CreateData", new
{
model = BigViewModel,
Id = productId,
experimentForOverloading
}
}
else if (model.SecondTabSalary == null && model.ThirdTabDirectory == null)
{
return RedirectToAction("CreateData", new
{
model = BigViewModel,
Id = productid
experimentAgain
}
}
else
{
return RandomView(); //Testing purposes
}
}
// This is the second case, save only when first tab is empty
[HttpPost]
public ActionResult CreateData(BigViewModel, int bigId, int experimentForOverloading)
{
if(ModelState.IsValid)
{
//.. code here
_context.SaveChanges()
}
else
{
return RandomView(); //Testing purpose
}
}
// This is the first case, save only when second and third tab is empty
[HttpPost]
public ActionResult CreateData(BigViewModel, int bigId, string experimentAgain)
{
if(ModelState.IsValid)
{
//.. code here
_context.SaveChanges()
}
else
{
return RandomView(); //Testing purpose
}
}
I am making my MVC application. I open my view with predefined parameters like this:
return RedirectToAction("PickGroupForHomework", "Account", new {subject_id = id, qty=model.qty });
And this works fine, the data subject_id and qty are passed correctly. However, my view PickGroupForHomework contains a form to fill, which is then validated. If the input is not valid, the window simply should reload with the data subject_id and qty as defined in previous view. I do this in such way:
public ActionResult PickGroupForHomework(PickGroupForHomeworkViewModel model)
{
ClassDeclarationsDBEntities2 entities = new ClassDeclarationsDBEntities2();
model.groups = entities.Groups.ToList();
model.users = entities.Users.ToList();
int id = model.subject_id;
var subj = entities.Subjects
.Where(b => b.class_id == model.subject_id)
.FirstOrDefault();
if (subj != null)
{
model.subject_name = subj.name;
}
if (ModelState.IsValid)
{
}
else
{
return View(model);
}
return View(model);
}
But the resulting URL does not contain the data I need, but just a plain view. How do I do it right?
In order for you wep app to work, you will need two actions, one to set your model up for the View and another to actually do the work to post and save your data:
public ActionResult PickGroupForHomework(int subject_id, int qty)
{
//Initialize your model here. Below is just an example.
ClassDeclarationsDBEntities2 entities = new ClassDeclarationsDBEntities2();
PickGroupForHomeworkViewModel model = new PickGroupForHomeworkViewModel();
model.groups = entities.Groups.ToList();
model.users = entities.Users.ToList();
model.subject_id = subject_id;
model.qty = qty;
return View("PickGroupForHomework", model);
}
[HttpPost]
public ActionResult PickGroupForHomework(PickGroupForHomeworkViewModel model)
{
ClassDeclarationsDBEntities2 entities = new ClassDeclarationsDBEntities2();
int id = model.subject_id;
var subj = entities.Subjects
.Where(b => b.class_id == model.subject_id)
.FirstOrDefault();
if (subj != null)
{
model.subject_name = subj.name;
}
if (ModelState.IsValid)
{
//Save to database
[code goes here]
//return to a View to show your results
return View("[Your view to see the results]")
}
//Model Validation did not pass
//or exception occurred go back to View
return View(model);
}
I am stuck on a problem implementing LINQ properly on my model. Right now I have it so that when the user clicks on the "list tracks" view they will receive a listing of every song in the DB. What i want to do, is add another link at the top such as "pop tracks" and have it when the user clicks on it, it will sort all the songs by their GenreId (pop) which is 9. I am unsure how to accomplish this as i don't understand how you would return multiple views from 1 index() method (if that's even how i would do it?). Any help is appreciated.
I am now receiving this error:
xception Details: AutoMapper.AutoMapperMappingException: Missing type
map configuration or unsupported mapping.
Mapping types: Genre -> TrackBase Assignment_3.Models.Genre ->
Assignment_3.Controllers.TrackBase
Source Error:
Line 74: { Line 75: var AllPop = ds.Genres.Where(p
=> p.GenreId == 9); Line 76: return mapper.Map>(AllPop); Line 77: } Line
78:
Manager.cs:
public IEnumerable<TrackBase> TrackGetAll()
{
return mapper.Map<IEnumerable<Track>, IEnumerable<TrackBase>>(ds.Tracks);
}
public IEnumerable<TrackBase> TrackGetAllPop()
{
var AllPop = ds.Genres.Where(p => p.GenreId == 9);
return mapper.Map<IEnumerable<TrackBase>>(AllPop);
}
TrackController.cs:
public ActionResult Index(int? genreid)
{
if (genreid.HasValue && genreid.Value == 9)
{
return View(m.TrackGetAllPop());
}
return View(m.TrackGetAll());
}
AutoMapperConfig.cs:
cfg.CreateMap<Models.Track, Controllers.TrackBase>();
cfg.CreateMap<Controllers.TrackBase, Controllers.TracksController>();
You need to pass the genre id to Index action method and filter the songs accordingly. Change your controller to this
public ActionResult Index(int? genreid)
{
if (genreid.HasValue && genreid.Value == 9)
{
// return all pop songs to the view
return View(m.TrackGetAllPop());
}
// return all songs to the view
return View(m.TrackGetAll());
}
then in your index
#Html.ActionLink("All Tracks", "Index") |
#Html.ActionLink("Pop Tracks", "Index", new { genreid = 9})
You also have a problem with TrackGetAllPop method
public IEnumerable<TrackBase> TrackGetAllPop()
{
var AllPop = ds.Genres.Where(p => p.GenreId == 9);
return mapper.Map<IEnumerable<TrackBase>>(AllPop);
}
The above method returns IEnumerable<TrackBase> but you're querying from ds.Genres instead of ds.Tracks, so that's why you got the error. Assuming Track table has GenreId as the foreign key to the Genre table, TrackGetAllPop method should be like below
public IEnumerable<TrackBase> TrackGetAllPop()
{
var AllPop = ds.Tracks.Where(p => p.GenreId == 9);
return mapper.Map<IEnumerable<TrackBase>>(AllPop);
}
More General Solution
The above will work for this particular case, however you can make it more general for other genres too. Add this method in Manager.cs
public IEnumerable<TrackBase> TrackGetByGenre(int genreId)
{
var result = ds.Tracks.Where(p => p.GenreId == genreId);
return mapper.Map<IEnumerable<TrackBase>>(result);
}
and change your controller to below
public ActionResult Index(int? genreid)
{
if (genreid.HasValue)
{
// return songs based on the passed genreid to the view
return View(m.TrackGetByGenre(genreid.Value));
}
// return all songs to the view
return View(m.TrackGetAll());
}
I have a viewmodel, with two properties, one is a POCO class, the other is a double, when the controller builds and send the viewmodel out all the values are present and working on the page. When I POST the viewmodel the double value is set, and the object is present but the POCO class inside is null, which was not when the object is sent.
In the examples below, why is ticket.flight null on the POSTed viewmodel object?
ViewModel:
public class PayViewModel
{
public virtual Ticket ticket { get; set; }
public double amountToPay = 0.0;
[Display(Name = "Amount To Pay")]
[DataType(DataType.Currency)]
[DisplayFormat(DataFormatString = "{0:N2}", ApplyFormatInEditMode = true)]
public double AmountToPay
{
get
{
return amountToPay;
}
set
{
amountToPay = value;
}
}
}
Controller methods:
// GET: Tickets/Pay/5
public ActionResult Pay(int? id)
{
if (id == null)
{
return RedirectToAction("Index");
}
Ticket ticket = db.tickets.Find(id);
if (ticket == null)
{
return RedirectToAction("Index");
}
PayViewModel viewModel = new PayViewModel();
viewModel.ticket = ticket;
return View(viewModel);
}
// POST: Tickets/Pay/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Pay([Bind(Include = "AmountToPay,ticket,ticket.flight")]PayViewModel viewModel)
{
if (ModelState.IsValid)
{
viewModel.ticket.AmountPaid += viewModel.AmountToPay;
if (viewModel.ticket.AmountPaid >= viewModel.ticket.flight.ticketPrice)
{
viewModel.ticket.status = TicketStatusType.CONFIRMED;
}
db.Entry(viewModel.ticket).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel.ticket);
}
View code - https://gist.github.com/JonFriesen/f511a91b8e9a90c1b23c
During the form submit the browser only submits the fields of type input. This means that from your view only these statements create the fields of type input:
#Html.HiddenFor(model => model.ticket.id)
#Html.EditorFor(model => model.AmountToPay, new { htmlAttributes = new { #class = "form-control" } })
When the request arrives to an MVC application, the binding uses the arrived values ticket.id and AmountToPay to construct an object of type PayViewModel. Since it cannot find any property from ticket.flight amongst the submitted values, it assumes that it should not exist and therefore it is assigned a default value of null. This is the expected behavior of model binder.
If you want to have the initialized values, I suggest one of the following:
On POST initialize the object from the database code and use only the submitted value of AmountToPay to perform your processing.
In the view add the hidden variables for the missing fields, e.g. #Html.HiddenFor(model => model.ticket.flight.source.airportCode). In this case the variables would be submitted therefore the object would be fully populated.
I am trying to raise validation error in an ASP.Net MVC 3 application.
When the user enters a number that is greater than 1000 an error message should be displayed. with the following code on a view model it doesn't seem to be working.
What do i need to change?
[Range(0, 1000, ErrorMessage = "Total number of rows to display must be between 0 to 1000")]
public int DisplayTop { get; set; }
cshtml :
#model Calc.Models.CountingVM
#{
ViewBag.Title = "Reports";
Layout = "~/Views/Shared/_reportsLayout.cshtml";
}
#using (Html.BeginForm("Reports", "Calc", FormMethod.Post, new { #id = "frmReport" }))
{
.........
#Html.TextBoxFor(c => c.DisplayTop, "1000")
#Html.ValidationMessageFor(c => c.DisplayTop)
}
Action Method :
public ActionResult Reports(string ReportName, CalcCriteria criteria)
{
if ((criteria == null) || (criteria.nId == null))
{
criteria = TempData["criteria"] as CalcCriteria;
TempData["criteria"] = criteria; // For reload, without this reloading the page causes null criteria.
}
ReportType c = (ReportType)Enum.Parse(typeof(ReportType), ReportName, true);
JavaScriptSerializer serializer = new JavaScriptSerializer();
string vmJson = string.Empty;
switch (c)
{
.....
int displayTop;
..........
case ReportType.Inventory_Counts_Report:
..............
displayTop = Convert.ToInt32(Request["DisplayTop"]);
........
return View("Counting", CountingVM);
default:
return View();
}
return View(); }
Thanks
BB
You also need to display the validation message:
#Html.ValidationMessageFor(c => c.DisplayTop)
Try
#Html.EditorFor(c => c.DisplayTop, "1000")
I guess, that the problem occures, becase your property is of type int, and the range is for type int, byt you are showing it in a textbox.
Also you need to add ModelState.IsValid in your controller. For example:
[HttpPost]
public ActionResult Create(YourModel model)
{
if(ModelState.IsValid)
{
// Put your logic here
}
return View(create)
}