This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 7 years ago.
I'm still learning MVC and am confused. I am converting a windows application for CRUD with a database to an MVC website. I got an entire ViewModel's CRUD working that uses dropdownlist's already and the code is identical but throwing object reference not set errors with it in another page.
Controller
public ActionResult Create()
{
var shiftsEmployees = new ShiftsEmployeesViewModel();
var oEmployees = new CEmployees();
oEmployees.GetActiveEmployees();
shiftsEmployees.Employees = oEmployees;
return View(shiftsEmployees);
}
// POST: Shifts/Create
[HttpPost]
public ActionResult Create(ShiftsEmployeesViewModel shiftsEmployees)
{
try
{
shiftsEmployees.InsertShift();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
View
#model StatTracker.ASPMVC.ViewModels.ShiftsEmployeesViewModel
#{
ViewBag.Title = "Add Shift";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal text-center">
#Html.ValidationSummary(true, "", new {#class = "text-danger"})
<div class="form-group">
<div class="input-group date col-md-12">
#Html.LabelFor(model => model.Shift.Date, new {#class = "control-label"})
#Html.EditorFor(model => model.Shift.Date, new {#class = "form-control datepicker", placeholder = "Pick a date"})
#Html.ValidationMessageFor(model => model.Shift.Date, "", new {#class = "text-danger"})
#Html.LabelFor(model => model.Employee.FullName, new {#class = "control-label"})
#Html.DropDownListFor(model => model.Employee.Id, new SelectList(Model.Employees.Employees, "Id", "FullName", Model.Employee), null, null)
#Html.ValidationMessageFor(model => model.Employee.Id, "", new {#class = "text-danger"})
#Html.LabelFor(model => model.Shift.Hours, new {#class = "control-label"})
#Html.EditorFor(model => model.Shift.Hours, new {#class = "form-control", placeholder = "Hours worked"})
#Html.ValidationMessageFor(model => model.Shift.Hours, "", new {#class = "text-danger"})
</div>
</div>
<div class="form-group">
<div class="col-md-12">
<input type="submit" value="Add Shift" class="btn btn-default"/>
</div>
</div>
</div>
}
<div class="text-center col-md-12">
#Html.ActionLink("Back to List", "Index")
</div>
ViewModel:
namespace StatTracker.ASPMVC.ViewModels
{
public class ShiftsEmployeesViewModel
{
public CShift Shift { get; set; }
public CEmployee Employee { get; set; }
public CEmployees Employees { get; set; }
public void InsertShift()
{
CShift.InsertShift(hours: Shift.Hours, employeeid: Employee.Id, date: Shift.Date);
}
public void UpdateShift()
{
CShift.UpdateShift(hours: Shift.Hours, employeeid: Employee.Id, date: Shift.Date, shiftid: Shift.Id);
}
}
}
working code with same idea
controller
public ActionResult Create()
{
var oSalesEmployeeService = new SalesEmployeeServiceViewModel();
var oServices = new CServices();
oServices.GetServices();
var oEmployees = new CEmployees();
oEmployees.GetActiveEmployees();
oSalesEmployeeService.Employees = oEmployees;
oSalesEmployeeService.Services = oServices;
return View(oSalesEmployeeService);
}
// POST: Sales/Create
[HttpPost]
public ActionResult Create(SalesEmployeeServiceViewModel oSalesEmployeeService)
{
try
{
oSalesEmployeeService.InsertSale();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
viewmodel
using StatTracker.BL;
namespace StatTracker.ASPMVC.ViewModels
{
public class SalesEmployeeServiceViewModel
{
public CSale Sale { get; set; }
public CEmployees Employees { get; set; }
public CServices Services { get; set; }
public CEmployee Employee { get; set; }
public CService Service { get; set; }
public void InsertSale()
{
CSale.InsertSale(service: Service.Id, date: Sale.Date, employee: Employee.Id);
}
public void UpdateSale()
{
CSale.UpdateSale(service: Service.Id, date: Sale.Date, employee: Employee.Id, salesid: Sale.Id);
}
}
}
view
#model StatTracker.ASPMVC.ViewModels.SalesEmployeeServiceViewModel
#{
ViewBag.Title = "Add Sale";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal text-center">
#Html.ValidationSummary(true, "", new {#class = "text-danger"})
<div class="form-group">
<div class="input-group date col-md-12">
#Html.LabelFor(model => model.Sale.Date, new {#class = "control-label"})
#Html.EditorFor(model => model.Sale.Date, new {#class = "form-control datepicker", placeholder = "Pick a date"})
#Html.ValidationMessageFor(model => model.Sale.Date, "", new {#class = "text-danger"})
#Html.LabelFor(model => model.Employee.FullName, new {#class = "control-label"})
#Html.DropDownListFor(model => model.Employee.Id, new SelectList(Model.Employees.Employees, "Id", "FullName", Model.Employee), null, null)
#Html.ValidationMessageFor(model => model.Employee.Id, "", new {#class = "text-danger"})
#Html.LabelFor(model => model.Service.Description, new {#class = "control-label"})
#Html.DropDownListFor(model => model.Service.Id, new SelectList(Model.Services.Services, "Id", "Description", Model.Service), null, null)
#Html.ValidationMessageFor(model => model.Service.Id, "", new {#class = "text-danger"})
</div>
</div>
<div class="form-group">
<div class="col-md-12">
<input type="submit" value="Add Sale" class="btn btn-default"/>
</div>
</div>
</div>
}
<div class="text-center col-md-12">
#Html.ActionLink("Back to List", "Index")
</div>
You have not indicated exactly where the error is being thrown but there will be numerous reasons
Firstly, a view model is not just a holder for a series of data models. It should contain only those properties which you need to display/edit in the view. Currently if any properties of CShift or CEmployee have validation attributes (other that the Date and Hours properties), your model will be invalid.
Secondly, when you return the view, you need to return the model to the view and also assign the value of Employees which currently will be null (hence the exception when you access Model.Employees.Employees in the DropDownList() method).
Based on the view you have shown, your view model should be just (add validation attributes as required)
public class ShiftsEmployeesViewModel
{
public DateTime Date { get; set; }
public int Employee { get; set; }
public float Hours { get; set; }
public SelectList EmployeeList { get; set; }
}
Controller
public ActionResult Create()
{
ShiftsEmployeesViewModel model = new ShiftsEmployeesViewModel();
model.Employee = ? // set default selection
ConfigureCreateModel(model);
return View(model);
}
[HttpPost]
public ActionResult Create(ShiftsEmployeesViewModel model)
{
if (!ModelState.IsValid)
{
ConfigureCreateModel(model);
return View(model);
}
.... // map the view model properties to a new instance of the data model, save and redirect
}
private void ConfigureCreateModel(ShiftsEmployeesViewModel model)
{
var oEmployees = (new CEmployees()).GetActiveEmployees();
model.EmployeeList = new SelectList(oEmployees, "Id", "FullName");
}
View
#Html.LabelFor(m => m.Date)
#Html.TextBoxFor(m => m.Date)
#Html.ValidationMessageFor(m => m.Date)
#Html.LabelFor(m => m.Employee)
#Html.DropDownListFor(m => m.Employee, Model.EmployeeList, "-please select-")
#Html.ValidationMessageFor(m => m.Employee)
#Html.LabelFor(m => m.Hours)
#Html.EditorFor(m => m.Hours)
#Html.ValidationMessageFor(m => m.Shift.Hours)
Side note: Your current usage of SelectList(Model.Employees.Employees, "Id", "FullName", Model.Employee) where you use the 4th parameter is pointless. Your binding to a property, so attempting to set the value of the Selected is ignored (the selected option is based on the value of the property your binding to)
Yes, because model.Employee has not been initialized and therefore, model.Employee.Id will throw a null reference exception. After that You still need to initialize the shift object as it will also throw a null reference exception when model.Shift.Hours is accessed. Please see my suggestions below
You will have to initialize the remaining properties
public ActionResult Create()
{
var oEmployees = new CEmployees();
oEmployees.GetActiveEmployees();
var shiftsEmployees = new ShiftsEmployeesViewModel
{
Employee = new CEmployee(),
Shift = new CShift(),
Employees = oEmployees;
};
return View(shiftsEmployees);
}
Another option is to just always initialize them in the constructor of the view model (you just have to make sure that somewhere GetActiveEmployees is getting called)
public class ShiftsEmployeesViewModel
{
public ShiftsEmployeesViewModel()
{
this.oEmployees = new CEmployees();
this.Employee = new CEmployee();
this.Shift = new CShift();
}
}
Also change the implementation in your view for the dropdownlist
#Html.DropDownListFor(model => model.Employee.Id,
new SelectList(Model.Employees.Employees ?? new List<CEmployee>(),
"Id",
"FullName"))
Related
I have two objects that I pass to View, and than back to controller.
public class Category1Dictionary
{
public int Id { get; set; }
public IList<Category2Dictionary> SubCategories {get; set;}
public string UserName { get; set; }
}
public class Category2Dictionary
{
public int Id { get; set; }
public string Category2Item { get; set; }
}
My view looks like this:
#model Budget.Models.Category1Dictionary
#{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm())
{
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(m => m.Id)
#Html.HiddenFor(m => m.UserName)
#Html.HiddenFor(m => m.SubCategories)
#Html.LabelFor(m => m.Category1Item, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="form-group">
<div class="col-md-10">
#Html.EditorFor(m => m.Category1Item, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(m => m.Category1Item, "", new { #class = "text-danger" })
</div>
#for (int i = 0; i < Model.SubCategories.Count; i++)
{
<div class="col-md-10" style="padding-left:40px">
#Html.EditorFor(m => m.SubCategories[i].Category2Item, new { htmlAttributes = new { #class = "form-control" } })
#Html.HiddenFor(m => m.SubCategories[i].Id, new { htmlAttributes = new { #class = "form-control" } })
</div>
}
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
And action in the controller:
[HttpPost]
public ActionResult Edit(Category1Dictionary category1Dictionary)
{
return View(category1Dictionary);
}
With this layout in action I get object Category1Dictionary with all items but SubCategories is NULL. I saw some similar posts but I have spent 6 hours in total on this and still can make it work...
Get Method:
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Category1Dictionary category1Dictionary = db.Category1Dictionaries.Include(p=>p.SubCategories).First(c=>c.Id == id);
if (category1Dictionary == null)
{
return HttpNotFound();
}
return View(category1Dictionary);
}
EDIT:
input field generated by EditorFor
Post message from fiddler:
I have table named Korisnik (on my language, on english its User) and i added an Edit ActionResult in my Controller , but it wont work because of the [Compare("Lozinka")] that is comparing the password from the database and the added property PotvrdiLozinku, in other words i must enter the Confirm password in order to Submit the changes
namespace ProjekatFinalni.Models
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
public partial class Korisnik
{
public int KorisnikID { get; set; }
[DisplayName("Korisnicko ime:")]
[Required(ErrorMessage ="Molimo vas unesite korisnicko ime.")]
public string Korisnickoime { get; set; }
[DisplayName("Lozinka:")]
[DataType(DataType.Password)]
[Required(ErrorMessage = "Molimo vas unesite lozinku.")]
public string Lozinka { get; set; }
[DisplayName("Admin:")]
public bool DaLiJeAdmin { get; set; }
[DisplayName("Gost:")]
public bool Gost { get; set; }
[DisplayName("Pravo za unos:")]
public bool PravoUnosa { get; set; }
[DisplayName("Potvrdi lozinku:")]
[DataType(DataType.Password)]
[Compare("Lozinka",ErrorMessage ="Lozinke se ne poklapaju.")]
public string PotvrdiLozinku { get; set; }
public string LoginErrorPoruka { get; set; }
}
This is the Edit ActionResult in my controller
public ActionResult Edit(int id)
{
using (BazaProjekatEntities4 dbModel = new BazaProjekatEntities4())
{
return View(dbModel.Korisniks.Where(x => x.KorisnikID == id).FirstOrDefault());
}
}
[HttpPost]
public ActionResult Edit(int id,Korisnik k)
{
try
{
using (BazaProjekatEntities4 dbModel = new BazaProjekatEntities4())
{
dbModel.Entry(k).State = EntityState.Modified;
dbModel.SaveChanges();
}
return RedirectToAction("Izlistaj");
}
catch
{
return View();
}
}
And this is the Edit.cshtml
#model ProjekatFinalni.Models.Korisnik
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Korisnik</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.KorisnikID)
<div class="form-group">
#Html.LabelFor(model => model.Korisnickoime, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Korisnickoime, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Korisnickoime, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Lozinka, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Lozinka, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Lozinka, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.PotvrdiLozinku, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.PotvrdiLozinku, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.PotvrdiLozinku, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.DaLiJeAdmin, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<div class="checkbox">
#Html.EditorFor(model => model.DaLiJeAdmin)
#Html.ValidationMessageFor(model => model.DaLiJeAdmin, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Gost, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<div class="checkbox">
#Html.EditorFor(model => model.Gost)
#Html.ValidationMessageFor(model => model.Gost, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.PravoUnosa, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<div class="checkbox">
#Html.EditorFor(model => model.PravoUnosa)
#Html.ValidationMessageFor(model => model.PravoUnosa, "", new { #class = "text-danger" })
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Sacuvaj" class="btn btn-default" />
</div>
</div>
</div>
}
Only want to edit the permissions(Admin, Gost and PravoUnosa
EDIT( Added the registration form that i used)
[HttpPost]
public ActionResult DodajiliIzmeni(Korisnik korisnikmodel)
{
using (BazaProjekatEntities4 Modelkorisnik = new BazaProjekatEntities4())
{
if(Modelkorisnik.Korisniks.Any(x=> x.Korisnickoime == korisnikmodel.Korisnickoime))
{
ViewBag.DuplicateMessage = "Korisnicko ime vec postoji.";
return View("DodajiliIzmeni", korisnikmodel);
}
Modelkorisnik.Korisniks.Add(korisnikmodel);
Modelkorisnik.SaveChanges();
}
ModelState.Clear();
ViewBag.SuccessMessage = "Registracija je uspela";
return RedirectToAction("Index", "Login");
}
You should create a view model specific for the view, which has the properties and validation attributes on them as needed by the view and use that to transfer data between your view and action method.
public class EditUserVm
{
public int Id { get; set; }
[DisplayName("Korisnicko ime:")]
public string UserName { get; set; }
[DisplayName("Admin:")]
public bool Admin { get; set; }
[DisplayName("Gost:")]
public bool Gost { get; set; }
[DisplayName("Pravo za unos:")]
public bool PravoUnosa { get; set; }
}
Now you will use this view model for your GET and POST action methods. In your GET action method, first create an object of this view model, then get your Korisniks object for the Id passed in, Read and map the property values to the view model object and pass it to the view.
public ActionResult Edit(int id)
{
using (var dbModel = new BazaProjekatEntities4())
{
var user = dbModel.Korisniks.FirstOrDefault(x => x.KorisnikID == id);
// to do: If user is NULL, return a "Not found" view to user ?
var vm = new EditUserVm { Id = id };
vm.UserName = user.UserName;
vm.Admin = user.Admin;
vm.Gost = user.Gost;
vm.PravoUnosa = user.PravoUnosa;
return View(vm);
}
}
Now makes sure your view is strongly typed to this view model because we are passing an object of the EditUserVm class to it.
#model YourNamespaceGoesHere.EditUserVm
#using (Html.BeginForm())
{
#Html.HiddenFor(a=>a.Id)
<label>#Model.UserName</label>
#Html.LabelFor(a=>a.Admin)
#Html.CheckBoxFor(a=>a.Admin)
#Html.LabelFor(a=>a.Gost)
#Html.CheckBoxFor(a=>a.Gost)
#Html.LabelFor(a=>a.PravoUnosa)
#Html.CheckBoxFor(a=>a.PravoUnosa)
<button type="submit" >Save</button>
}
Now you will use the same view model as the action method parameter. Inside the method, we will read again the User entity from the database and udpate only the field we want to
[HttpPost]
public ActionResult Edit(EditUserVm model)
{
var db = new BazaProjekatEntities4();
var user = db.Korisniks.FirstOrDefault(x => x.KorisnikID == model.Id);
// to do : Do a null check on user to be safe :)
// Map the property values from view model to entity object
user.Admin = model.Admin;
user.Gost = model.Gost;
user.PravoUnosa = model.PravoUnosa;
db.Entry(k).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
In short, create a view model with properties absolutely needed by the view/ your code and use that to transfer data between your action method and view.
The solution was very simple and it could be from the start, i just need to add the user.PotvrdiLozinku = user.Lozinka; that will tell it that the Confirm password is equal to Password (For the [Compare] that is in the User class. :)
[HttpPost]
public ActionResult Edit(EditUserVm model)
{
var db = new BazaProjekatEntities4();
var user = db.Korisniks.FirstOrDefault(x => x.KorisnikID == model.Id);
// to do : Do a null check on user to be safe :)
// Map the property values from view model to entity object
user.Admin = model.Admin;
user.PotvrdiLozinku = user.Lozinka; // this line was missing
user.Gost = model.Gost;
user.PravoUnosa = model.PravoUnosa;
db.Entry(k).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
I need two models in my view, so I created ViewModel that combines them. That is on getting method. But on the Post, my input type=submit is returning ViewModel, but values of properties inside are null. Any advice?
These are my actions for Get and Post
[HttpGet]
public ActionResult Report(int id)
{
using (SkolskaBibliotekaDBModel db = new SkolskaBibliotekaDBModel())
{
ReportZaPrikaz RZP = new ReportZaPrikaz();
var komentar = db.Komentar.FirstOrDefault(x => x.KomentarID == id);
RZP.kzp = new KomentarZaPrikaz()
{
KomentarID = komentar.KomentarID,
KomentarText = komentar.KomentarText,
KorisnikID = komentar.KorisnikID,
Reported = komentar.Reported,
VremeKomentara = komentar.VremeKomentara,
Ime = komentar.Korisnik.Ime,
Prezime = komentar.Korisnik.Prezime,
PicPath = komentar.Korisnik.PicPath,
VoteUp = komentar.VoteUp,
VoteDown = komentar.VoteDown
};
RZP.report = db.PrijavaKomentara.Create();
return View("Report",RZP);
}
}
[HttpPost]
public void Report(ReportZaPrikaz RZP)
{
using (SkolskaBibliotekaDBModel db = new SkolskaBibliotekaDBModel())
{
db.PrijavaKomentara.Add(RZP.report);
db.SaveChanges();
}
}
this is my viewmodel:
namespace SkolskaBiblioteka.ViewModels
{
public class ReportZaPrikaz
{
public KomentarZaPrikaz kzp;
public PrijavaKomentara report;
}
}
and this is my view:
#model SkolskaBiblioteka.ViewModels.ReportZaPrikaz
#using SkolskaBiblioteka.ViewModels
#{
ViewBag.Title = "Пријава коментара";
}
<div class="container">
#Html.Partial("_Komentar", Model.kzp)
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>PrijavaKomentara</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#{
Model.report.KorisnikId = ((KorisnikZaPrikaz)Session["Korisnik"]).KorisnikId;
}
#Html.HiddenFor(x => x.report.KorisnikId)
#{
Model.report.KomentarId = Model.kzp.KomentarID;
}
#Html.HiddenFor(x => x.report.KomentarId)
#{
Model.report.VremePrijave = DateTime.Now;
}
#Html.HiddenFor(x => x.report.VremePrijave)
<div class="form-group">
#Html.LabelFor(model => model.report.Tekst, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.report.Tekst, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
</div>
These conditions show up when I hit submit button.
The default model-binder would not bind fields. Try to use properties instead:
public class ReportZaPrikaz
{
public KomentarZaPrikaz kzp { get; set; }
public PrijavaKomentara report { get; set; }
}
I'm trying to format a price label so the price is always in the 0.00 format and I saw a similar question that used similar code as mine below. I'm getting an object reference not set to an instance of an object error and I know that it is because I am calling Model.Price but I'm very new to MVC and I don't understand how I set Model.Price before the page is loaded.
#Html.LabelFor(model => model.Price, "0.00", new { id = "priceLabel", Value = String.Format("{0:C}", Model.Price) })
Here is the Controller code:
[HttpGet]
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
// set the paper style list
List<SelectListItem> styles = new List<SelectListItem>();
ViewBag.paperStyle = new SelectList(styles, "Value", "Text");
// set the subject list
List<SelectListItem> subjects = new List<SelectListItem>();
ViewBag.subject = new SelectList(subjects, "Value", "Text");
// set the number of pages list
List<SelectListItem> numberOfPages = new List<SelectListItem>();
ViewBag.Urgency = new SelectList(urgency, "Value", "Text");
// set the document type list
List<SelectListItem> documentTypes = new List<SelectListItem>();
ViewBag.documentType = new SelectList(documentTypes, "Value", "Text");
// set the academic level list
List<SelectListItem> academicLevel = new List<SelectListItem>();
ViewBag.academicLevel = new SelectList(academicLevel, "Value", "Text");
// set the number of sources list
List<SelectListItem> numberOfSources = new List<SelectListItem>();
ViewBag.numberOfSources = new SelectList(numberOfSources, "Value", "Text");
// set the currency list
List<SelectListItem> currencies = new List<SelectListItem>();
currencies.Add(new SelectListItem() { Text = "$", Value = "USD", Selected = true });
currencies.Add(new SelectListItem() { Text = "£", Value = "GBP", Selected = false });
currencies.Add(new SelectListItem() { Text = "€", Value = "EUR", Selected = false });
ViewBag.currency = new SelectList(currencies, "Value", "Text");
return View();
}
[HttpPost]
public ActionResult Contact(WritingAppModel c)
{
if (ModelState.IsValid)
{
// send the email and process the payment
// if payment is ready then send email
if (isPaymentReady())
{
// send email
}
}
return View();
}
public class modelData
{
public string documentType { get; set; }
public string numberOfPages { get; set; }
public string urgency { get; set; }
}
public JsonResult getNewPrice(modelData dropdownValues)
{
// check for urgency first since that is the base price
if (dropdownValues.urgency != null)
{
currentPrice = Convert.ToDecimal(dropdownValues.urgency);
if (dropdownValues.documentType != null)
{
currentPrice = currentPrice + Convert.ToDecimal(dropdownValues.documentType);
if (dropdownValues.numberOfPages != null)
{
currentPrice = currentPrice * Convert.ToInt16(dropdownValues.numberOfPages);
}
}
}
// do something with value and return a decimal
return Json(new { currentPrice = currentPrice }, JsonRequestBehavior.AllowGet);
}
Here is the View code:
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<div class="row">
#Html.LabelFor(model => model.Name, "Name:")
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="row">
#Html.LabelFor(model => model.Email, "Email:")
#Html.TextAreaFor(model => model.Email, new { id = "email" })
#Html.ValidationMessageFor(model => model.Email)
</div>
<div class="row">
#Html.LabelFor(model => model.Topic, "Topic:")
#Html.EditorFor(model => model.Topic)
#Html.ValidationMessageFor(model => model.Topic)
</div>
<div class="row">
#Html.LabelFor(model => model.Subject, "Subject:")
#Html.DropDownListFor(model => model.Subject, (SelectList)ViewBag.subject, "--Select--", new { id = "subjectList" })
</div>
<div class="row">
#Html.LabelFor(model => model.Style, "Style:")
#Html.DropDownListFor(model => model.Style, (SelectList)ViewBag.paperStyle, "--Select--", new { id = "paperStyleList" })
</div>
<div class="row">
#Html.LabelFor(model => model.DocumentType, "Document Type:")
#Html.DropDownListFor(model => model.DocumentType, (SelectList)ViewBag.documentType, "--Select--", new { id = "documentTypeList" })
</div>
<div class="row">
#Html.LabelFor(model => model.AcademicLevel, "Academic Level:")
#Html.DropDownListFor(model => model.AcademicLevel, (SelectList)ViewBag.academicLevel, "--Select--", new { id = "academicLevelList" })
</div>
<div class="row">
#Html.LabelFor(model => model.NumberOfPages, "Number of Pages/Words:")
#Html.DropDownListFor(model => model.NumberOfPages, (SelectList)ViewBag.numberOfPages, "--Select--", new { id = "numberOfPagesList" })
</div>
<div class="row">
#Html.LabelFor(model => model.NumberOfSources, "Number of Sources:")
#Html.DropDownListFor(model => model.NumberOfSources, (SelectList)ViewBag.numberOfSources, "--Select--", new { id = "numberOfSourcesList" })
</div>
<div class="row">
#Html.LabelFor(model => model.Urgency, "Urgency:")
#Html.DropDownListFor(model => model.Urgency, (SelectList)ViewBag.urgency, "--Select--", new { id = "urgencyList" })
</div>
<div class="row">
#Html.LabelFor(model => model.Spacing, "Spacing:")
#Html.RadioButtonFor(model => model.Spacing, "Single") Single
#Html.RadioButtonFor(model => model.Spacing, "Double") Double
</div>
<div class="row">
#Html.LabelFor(model => model.Requirements, "Requirements:")
#Html.TextAreaFor(model => model.Requirements)
</div>
<div class="row">
#Html.DropDownListFor(model => model.Currency, (SelectList)ViewBag.currency, null, new { id = "currencyList" })
<h2>
#Html.LabelFor(model => model.Price, "{0:C}", new { id = "priceLabel" })
</h2>
<input type="submit" value="Submit" />
<input type="reset" value="Reset" />
</div>
}
I'm not sure what the controller looks like, but take this test version...
Controller
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new Product {Price = 9.99m};
return View(model);
}
}
I've created a Product class as an example..
public class Product
{
public decimal Price { get; set; }
}
Your view will then need to reference the model.
#model WebApplication2.Controllers.Product
#Html.LabelFor(model => model.Price, new { id = "priceLabel" })
#Html.TextBoxFor(model => model.Price, new { id = "priceLabel",
Value = String.Format("{0:C}", Model.Price) })
You can see from the controller where the model is built and passed to the view.
var model = new Product {Price = 9.99m};
return View(model);
The LabelFor will generate a label for the actual property, not the value for it.
EDIT: Based on comment.
If you only want to display the property...
#String.Format("{0:C}", Model.Price)
or. as Steve suggested...
Model:
[DisplayFormat(DataFormatString = "{0:C}")]
public decimal Price { get; set; }
View
#Html.DisplayFor(model => model.Price)
I have created a View in my MVC4 application for Creating Users. In this View, a User can have a property set for either Organization or for Sponsor, but not both. My current code is correctly displaying all of the Organizations/Sponsors depending upon what is being shown based upon a Switch selection, but when I make a selection in either DropDownList and save the new user, all the DropDownLists return is a Null value for the User.
Users Model (Partial):
[GridColumn(Title = "Org.", SortEnabled = true, Width = "100")]
public int? MemberOrgId { get; set; }
[NotMappedColumn]
public int? SponsorOrgId { get; set; }
[ForeignKey("MemberOrgId")]
[NotMappedColumn]
public virtual MemberOrganizations Organization { get; set; }
[ForeignKey("SponsorOrgId")]
[NotMappedColumn]
public virtual SponsorOrganizations Sponsor { get; set; }
Create (VIEW):
#model PROJECT.Models.Users
#{
ViewBag.Title = "Create";
Layout = "~/Areas/Admin/.../.../.../_AdminLayout.cshtml";
string cancelEditUrl = "/Admin/UserController/";
}
#using (Html.BeginForm("Create", "UserController", FormMethod.Post, new { enctype = "multipart/form-data" })) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.RegisteredDate)
<div class="container">
<div class="row">
<div class="editor-label">
#Html.LabelFor(model => model.Email)
</div>
<div class="editor-field" style="margin-bottom: 15px">
#Html.TextBoxFor(model => model.Email, new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Email)
</div>
</div>
<input type="checkbox" value="12345" name="Sponsor-Organization" checked class="userCreate-BSSwitch"/>
<div style="margin-bottom: 15px">
<div class="row switchOn">
<div class="editor-label">
#Html.LabelFor(model => model.MemberOrgId, "Organization")
</div>
<div class="editor-field">
#Html.DropDownList("OrganizationId", null, String.Empty, new { #class = "form-control", #id = "OrgIdDropDown" })
#Html.ValidationMessageFor(model => model.MemberOrgId)
</div>
</div>
<div class="row switchOff">
<dliv class="editor-label">
#Html.LabelFor(model => model.SponsorOrgId, "Sponsor")
</dliv>
<div class="editor-field" >
#Html.DropDownList("SponsorId", null, String.Empty, new { #class = "form-control", #id = "SponsorIdDropDown" })
#Html.ValidationMessageFor(model => model.SponsorOrgId)
</div>
</div>
</div>
<div class="row" id="submitRow">
<div class="btn-group ">
<button type="submit" value="Save" class="btn btn-success">Create User</button>
</div>
Cancel
</div>
</div>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
<script type="text/javascript">
jQuery(document).ready(function () {
setTimeout(function () { $("#alert").alert('close'); }, 5000);
$('.switchOff').addClass('hide');
});
$.fn.bootstrapSwitch.defaults.onText = 'Member';
$.fn.bootstrapSwitch.defaults.offText = 'Sponsor';
$.fn.bootstrapSwitch.defaults.offColor = 'info';
$.fn.bootstrapSwitch.defaults.animate = false;
//$.fn.bootstrapSwitch.defaults.size = 'large';
$(document).ready(function () {
$('input:checkbox[name="Sponsor-Organization"]').bootstrapSwitch();
});
$('input:checkbox[name="Sponsor-Organization"]').on('switchChange.bootstrapSwitch', function (event, state) {
var checked = state;
if (checked) {
$('.switchOn').removeClass('hide');
$('.switchOff').addClass('hide');
$('#SponsorIdDropDown').val("");
}
else {
$('.switchOff').removeClass('hide');
$('.switchOn').addClass('hide');
$('#OrgIdDropDown').val("");
}
});
$(document).ready(function () {
$(".btn-danger").click(function () {
var cancel = confirm("Are you sure? Entered data will be lost.")
if (cancel != true) {
event.preventDefault(); // cancel the event
}
});
});
//$('input:checkbox[name="Sponsor-Organization"]').on('switchChange.bootstrapSwitch', function(event, state) {
</script>
Controller (Create GET):
//
// GET: /Admin/
public ActionResult Create()
{
ViewBag.headerTitle = "Create a User";
ViewBag.OrganizationId = new SelectList(db.MemberOrganizations, "Id", "Name");
ViewBag.SponsorId = new SelectList(db.SponsorOrganizations, "Id", "Name");
Users newUser = new Users();
newUser.RegisteredDate = DateTime.Now;
newUser.LastVisitDate = DateTime.Now;
newUser.ProfilePictureSrc = null;
return View(newUser);
}
Controller (Create HTTP-Post):
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Users users)
{
ViewBag.headerTitle = "Create a User";
if (ModelState.IsValid)
{
WebSecurity.CreateUserAndAccount(users.Email, "defaultPassword");
Users user2 = db.Users.Where(u => u.Email == users.Email).FirstOrDefault();
user2.Enabled = true;
user2.Password = Membership.GeneratePassword(15, 7);
user2.ForumUsername = users.Name;
user2.RegisteredDate = DateTime.Now;
user2.ReceiveSystemEmails = true;
db.Entry(user2).State = EntityState.Modified;
db.SaveChanges();
string[] roleNames = new string[] { "role1", "role2", "role3" };
System.Web.Security.Roles.AddUserToRoles(users.Email, roleNames);
return RedirectToAction("Index");
}
}
Anyone have some thoughts on the matter? I've tried a few different suggestions I found in other questions, but nothing has worked as of yet. This is my first MVC application, so I feel as if I may be overlooking something very basic.
for a field to be tied to the model it has to be in a "for" helper (except display). try changing your drop downs like this
#Html.DropDownListFor(x => x.OrganizationId, null, String.Empty, new { #class = "form-control"})
#Html.DropDownListFor(x => x.SponsorId, null, String.Empty, new { #class = "form-control" })
assuming your users model has fields OrganizationId and SponsorId those fields will be tied to the drop down (set them on the get and the drop down will be set and the drop down value will be passed back to the controller through the post)
Edit
I would suggest passing your drop down list through your model. to your model add
public SelectList OrganizationList { get; set; }
public SelectList SponsorList { get; set; }
then on your controller (in the get)
newUser.OranizationList = new SelectList(db.MemberOrganizations, "Id", "Name");
newUser.SponsorList = new SelectList(db.SponsorOrganizations, "Id", "Name");
then on your view
#Html.DropDownListFor(x => x.MemberOrgId, Model.OrganizationList, new { #class = "form-control" })
public class MyModel
{
public MyModel()
{
this.myDDLList = new List<SelectListItem>();
}
public List<SelectListItem> myDDLList { get; set; }
public int ddlID { get; set; }
}
public ActionResult Index()
{
MyModel model = new MyModel();
using (YourEntities context = new YourEntities())
{
var list = context.YourTable.ToList();
foreach (var item in list)
{
model.myDDLList.Add(new SelectListItem() { Text = item.NameField, Value = item.ValueField.ToString() });
}
}
return View(model);
}
#Html.DropDownListFor(x => x.ddlID, Model.myDDLList)
I resolved the issue by using ViewData[] to pass a pre-filled select list from my controller to my view:
// GET: /Admin/
public ActionResult Create()
{
ViewBag.headerTitle = "Create a User";
ViewData["Organization"] = new SelectList(db.MemberOrganizations, "Id", "Name");
ViewData["Sponsor"] = new SelectList(db.SponsorOrganizations, "Id", "Name");
Users newUser = new Users();
newUser.RegisteredDate = DateTime.Now;
newUser.LastVisitDate = DateTime.Now;
newUser.ProfilePictureSrc = null;
return View(newUser);
}
and then in my view simply read in the ViewData[] values into my Html.DropDownList's as separate SelectList's:
#Html.DropDownList("MemberOrgId", ViewData["Organization"] as SelectList, String.Empty, new { #class = "form-control", #id = "MemberOrgId" })
#Html.DropDownList("SponsorOrgId", ViewData["Sponsor"] as SelectList, String.Empty, new { #class = "form-control", #id = "SponsorOrgId" })