I've tryed to merge my create and edit actions into a save action, but for some reason, when I try to insert a new Cliente, the modelState trys to validate de ID colum. If I comment out the hidden field ID in the view, it works.
Would you give me a clue, please!?
View
#model WebApplicationCursoASPNET_V3.ViewModels.FormularioClienteViewModel
#{
ViewBag.Title = "Novo";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2> Cliente</h2>
#using (#Html.BeginForm("Gravar", "Cliente"))
{
<div class="form-group">
#Html.LabelFor(m => m.cliente.Nome)
#Html.TextBoxFor(m => m.cliente.Nome, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.cliente.Nome, "", new { #class = "text-danger" })
</div>
<div class="form-group">
#Html.LabelFor(m => m.cliente.TipoAssinaturaId)
#Html.DropDownListFor(m => m.cliente.TipoAssinaturaId, new SelectList(Model.tiposAssinatura, "Id", "Nome"), "<< Selecione a assinatura >>", new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.cliente.TipoAssinaturaId, "", new { #class = "text-danger" })
</div>
<div class="form-group">
#Html.LabelFor(m => m.cliente.Aniversario)
#Html.TextBoxFor(m => m.cliente.Aniversario, "{0:d}", new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.cliente.Aniversario)
</div>
<div class="checkbox">
<label>
#Html.CheckBoxFor(m => m.cliente.EstaInscritoEmAssinaturas) Está inscrito em assinaturas
</label>
</div>
#Html.HiddenFor(m => m.cliente.Id)
#Html.ValidationMessageFor(m => m.cliente.Id, "", new {#class="text-danger"})
<br>
<button type="submit" class="btn btn-primary">Gravar</button>
}
Controller
[HttpPost]
public ActionResult Gravar(FormularioClienteViewModel dadosFormulario)
{
if (dadosFormulario.cliente.Id == 0)
{
if (ModelState.IsValid)
{
_context.Clientes.Add(dadosFormulario.cliente);
_context.SaveChanges();
return RedirectToAction("Index", "Cliente");
}
var vwModel = new FormularioClienteViewModel
{
cliente = dadosFormulario.cliente,
tiposAssinatura = _context.TipoAssinaturas.OrderBy(m => m.Nome).ToList()
};
return View("Form", vwModel);
}
var clienteDB = _context.Clientes.SingleOrDefault(c => c.Id == dadosFormulario.cliente.Id);
if (clienteDB == null)
{
return HttpNotFound();
}
clienteDB.Nome = dadosFormulario.cliente.Nome;
clienteDB.TipoAssinaturaId = dadosFormulario.cliente.TipoAssinaturaId;
clienteDB.Aniversario = dadosFormulario.cliente.Aniversario;
clienteDB.EstaInscritoEmAssinaturas = dadosFormulario.cliente.EstaInscritoEmAssinaturas;
_context.SaveChanges();
return RedirectToAction("Index", "Cliente");
}
Model
public class Cliente
{
public int Id { get; set; }
[Display(Name = "Nome do cliente")]
[Required]
[StringLength(255,ErrorMessage = "Tamanho máximo de 255 caracteres")]
public string Nome { get; set; }
[Display(Name = "Está inscrito em assinaturas")]
public bool EstaInscritoEmAssinaturas { get; set; }
public TipoAssinatura TipoAssinatura { get; set; }
[Display(Name = "Tipo de assinatura")]
public int TipoAssinaturaId { get; set; }
public DateTime? Aniversario { get; set; }
}
Error msg: O campo Id é obrigatório. / Field Id is required
Ideally, it is recommended to use different calls for save and update with different DTO.
In your case, now you need to make Id nullable and validate it with custom logic in Update.
public int? Id { get; set; }
Related
when i tried to submit my edit form i get this issue and i don't know why
productsController edit get
public async Task<ActionResult> Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
//ProductsModel productsModel = await db.ProductsModels.FindAsync(id);
var products = await db.ProductsModels.Include(a =>a.categorieId).Include(a => a.users).FirstAsync(a => a.id == id);
if (products == null)
{
return HttpNotFound();
}
var selectedOwnerId = products.users?.Id ?? string.Empty;
var users = db.Users.Select(userItem => new SelectListItem
{
Text = userItem.Email,
Value = userItem.Id,
Selected = userItem.Id == selectedOwnerId
}).ToSafeReadOnlyCollection();
var selectedCategoryId = products.categorieId.id;
var productCategories = db.ProductCategoriesModels
.Select(a => new SelectListItem
{
Value = a.id.ToString(),
Text = a.name,
Selected = a.id == selectedCategoryId
}).ToSafeReadOnlyCollection();
var viewmodel = new productCreatEditViewModel()
{
Products = products,
productCategories = productCategories,
users = users
};
//ViewBag.users = userList;
//ViewBag.productcategorieId = new SelectList(db.ProductCategoriesModels, "id", "Name", productsModel.productcategorieId);
return View(viewmodel);
}
productsController edit post
// POST: Products/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details see https://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit([Bind(Include = "id,name,calorie,price,productcategorieId,userId")] ProductsModel productsModel)
{
if (ModelState.IsValid)
{
db.Entry(productsModel).State = EntityState.Modified;
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
ViewBag.productcategorieId = new SelectList(db.ProductCategoriesModels, "id", "Name", productsModel.productcategorieId);
return View(productsModel);
}
edit view
#model koelkast.ViewModels.productCreatEditViewModel
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>ProductsModel</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.Products.id)
<div class="form-group">
#Html.LabelFor(model => model.Products.name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Products.name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Products.name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Products.calorie, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Products.calorie, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Products.calorie, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Products.price, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Products.price, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Products.price, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Products.categorieId.name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => Model.Products.categorieId.id,Model.productCategories, new { Name = "productCategoriesId", #class ="form-control"})
#Html.ValidationMessageFor(model => model.productCategories, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Products.users.Email, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => Model.Products.users.Id,Model.users, new {Name = "UserId", #class = "form-control" })
#Html.ValidationMessageFor(model => model.Products.users.Email, "", new { #class = "text-danger" })
</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>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
ViewModel
The model item passed into the dictionary is of type 'koelkast.Models.ProductsModel', but this dictionary requires a model item of type 'koelkast.ViewModels.productCreatEditViewModel'.
namespace koelkast.ViewModels
{
public class productCreatEditViewModel
{
[Required]
public ProductsModel Products { get; set; }
[Required]
public ICollection<SelectListItem> productCategories { get; set; }
[Required]
public ICollection<SelectListItem> users { get; set; }
}
}
productModel
namespace koelkast.Models
{
public class ProductsModel
{
[Key]
public int id { get; set; }
[Required,Display(Name = "name")]
public string name { get; set; }
//display name is de naam die hij gaat laten zien als nnaam in je view
[Required, Display(Name = "calorie")]
public int calorie { get; set; }
[Required, Display(Name = "price")]
public float price { get; set; }
[Display(Name = "categories")]
//hier zet je die foreing key
//zoals je kunt zien roep ik alleen de model aan
public int? productcategorieId { get; set; }
[ForeignKey("productcategorieId")]
public virtual ProductCategoriesModel categorieId { get; set; }
//je zegt hier dus dat dit de Id is(userId)
//van applicationUser table users
public string UserId { get; set; }
[ForeignKey("UserId")]
public virtual ApplicationUser users { get; set; }
}
}
https://i.stack.imgur.com/Qaq67.png
you have a bug here, fix it
public async Task<ActionResult> Edit(ProductsModel productsModel)
{
}
you have 2 choices
1.Change ProductsModel to ProductCreatEditViewModel
or
Return ProductCreatEditViewModel as model
var viewmodel = new productCreatEditViewModel()
{
Products = productsModel,
productCategories = productCategories,
users = users
};
return View(viewModel);
I am using a Dropdownlist in my modal I have it working perfectly with textboxes. I’ve tried changing my Model to multiple different properties (String, Int, SelectListItem). I feel I must be extremely close to getting this to work. I would like my validation message to appear when im using Dropdownlists as well. When the validation message is suppose to appear I get the error message ‘The ViewData item that has the key 'PartVM.IDenteredBy' is of type 'System.Int32' but must be of type 'IEnumerable'.’ Here is my View, Model, and Action.
public class UpdatePartViewModel
{
public int PartID { get; set; }
[Required]
[Display(Name = "Part Number")]
public string PartNumber { get; set; }
//[Required]
[Display(Name = "Entered By")]
public string EnteredBy { get; set; }
public SelectListItem SLIenteredBy { get; set; }
public IEnumerable<SelectListItem> EnteredByOptions { get; set; }
public int IDenteredBy { get; set; }
[Display(Name = "Date Entered")]
public DateTime DateEntered { get; set; }
[Display(Name = "Machine Types")]
public List<int> MachineTypes { get; set; }
//public string MachineTypesString { get; set; }
}
public class FindPartModel
{
[Display(Name = "Entered By")]
public string PNEnteredBy { get; set; }
public IEnumerable<SelectListItem> PNEnteredByOptions { get; set; }
public findPartNumberListAttributes[] info { get; set; }
public List<findPartNumberListAttributes> reportList { get; set; }
public UpdatePartViewModel PartVM { get; set; }
}
//PNControls.cshtml VIEW
#model Messer_PartNumbers.Models.FindPartModel
#{ HtmlHelper.UnobtrusiveJavaScriptEnabled = true; }
#Html.AntiForgeryToken()
#Html.HiddenFor(x => x.PartVM.PartID)
#Html.HiddenFor(x => x.PartVM.PartGroup)
<div class="form-group">
#Html.LabelFor(x =>x.PartVM.PartNumber, htmlAttributes: new { #class="control-label col-3" })
<div class="col-9">
#Html.TextBoxFor(x => x.PartVM.PartNumber, new { #class="form-control", #readonly="readonly" })
#Html.ValidationMessageFor(x => x.PartVM.PartNumber, "", new { #class="text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(x => x.PartVM.EnteredBy, htmlAttributes: new { #class = "control-label col-3" })
<div class="col-9">
#*#Html.TextBoxFor(x => x.PartVM.EnteredBy, new { #class="form-control" })*#
#*#Html.DropDownListFor(x => x.PartVM.SLIenteredBy, Model.PNEnteredByOptions as IEnumerable<SelectListItem>, "Select User", new { #class = "form-control" })*#
#*#Html.DropDownList("DDLenteredBy", Model.PNEnteredByOptions as IEnumerable<SelectListItem>, new { #class="form-control" })*#
#Html.DropDownListFor(x => x.PartVM.IDenteredBy, Model.PNEnteredByOptions as IEnumerable<SelectListItem>, "Select User", new { #class = "form-control" })
#*#Html.ValidationMessageFor(x => x.PartVM.EnteredBy, "", new { #class = "text-danger" })*#
#*#Html.ValidationMessageFor(x => x.PartVM.SLIenteredBy, "", new { #class = "text-danger" })*#
#Html.ValidationMessageFor(x => x.PartVM.IDenteredBy, "", new { #class = "text-danger" })
</div>
</div>
#using (Ajax.BeginForm("PartNumberUpdate", "Parts", new AjaxOptions() { HttpMethod = "POST", UpdateTargetId = "PartNumControls", OnSuccess = "ajaxPartUpdate" }))
{
<div class="modal" id="modalPNUpdate" tabindex="-1" role="dialog" aria-labelledby="lblPNUpdate" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">Part Number Details</h3>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body" id="PartNumControls">
#Html.Partial("PNControls")
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal">Close</button>
<input type="submit" class="btn btn-primary" value="Save" />
</div>
</div>
</div>
</div>
}
[HttpPost]
[ValidateAntiForgeryToken]
[HandleError]
public ActionResult PartNumberUpdate(FindPartModel model)
{
if (ModelState.IsValid)
{
var partNumber = context.PartNumbers.Where(x => x.PartNumber1 == model.PartVM.PartNumber).FirstOrDefault();
// Updating the Parts data with the new Models Information.
partNumber.PartNumber1 = model.PartVM.PartNumber;
partNumber.PartGroup = model.PartVM.PartGroup != null ? model.PartVM.PartGroup : partNumber.PartGroup;
partNumber.Last4Number = model.PartVM.Last4Numbers;
//var str = Request.Form["DDLenteredBy"];
//if(model.PartVM.EnteredBy != null)
//{ var enteredByID = context.Employees.Where(e => e.Name == model.PartVM.EnteredBy).Select(x => x.ID).FirstOrDefault();
// partNumber.EnteredBy = enteredByID; }
/* testvar2 = testVar1 != null ? testvar1 : testvar2; || testVar2 = testVar1 ?? testVar2 */
partNumber.EnteredBy = model.PartVM.IDenteredBy;
partNumber.DateEntered = model.PartVM.DateEntered;
/// UPDATE PartNumber Record
context.Entry(partNumber).State = EntityState.Modified;
context.SaveChanges();
ViewBag.ValidMessage = "PartNumber Record Updated";
string returnStr = "refresh";
ModelState.Clear();
return Json(returnStr);
}
TempData["ErrorState"] = "x";
return PartialView("PNControls", model);
}
public ActionResult PNControls()
{
return View(new FindPartModel());
}
I needed to repopulate my Dropdownlists when the ModelState was invalid.
Now my validation with ajax works exactly as expected. I needed this at the end of my PartNumberUpdate Action.
}
/// Populate DropDownLists in Modal to UPDATE fields
var fetcher = new DataFetcher();
model.PNEnteredByOptions = fetcher.EnteredByInfo();
//ViewBag.DDLenteredby = fetcher.EnteredByInfo();
model.PNMachineTypeOptions = fetcher.machineTypeInfo();
model.PNSoftwareTypeOptions = fetcher.softwareTypeInfo();
model.PNManufacturerOptions = fetcher.manufactuerInfo();
model.PNUsageOptions = fetcher.usageInfo();
model.PNUnitsOptions = fetcher.unitsInfo();
TempData["ErrorState"] = "x";
return PartialView("PNControls", model);
}
So I have some custom validation implemented to prevent similar records being entered into the db. The only problem I have is that it is not presenting the user an error/validation message but rather an error page.
Where am I going wrong? Or how do I correctly implement this?
Validation:
public class ValidSimilarRequests : ValidationAttribute
{
private LotusWorksEntities db = new LotusWorksEntities();
protected override ValidationResult
IsValid(object value, ValidationContext validationContext)
{
var model = (Models.HolidayRequestForm)validationContext.ObjectInstance;
int empID = Convert.ToInt32(model.EmployeeID);
DateTime _startdate = Convert.ToDateTime(model.StartDate);
DateTime _finishdate = Convert.ToDateTime(model.FinishDate);
var holidayexist = db.HolidayRequestForms.Any( x => x.EmployeeID==empID && x.StartDate <= _startdate && x.FinishDate >= _finishdate );
if (holidayexist)
{
return new ValidationResult
("A holiday Request for this date range has already been requested");
}
else
{
return ValidationResult.Success;
}
}
}
Model:
public partial class HolidayRequestForm
{
public int RequestID { get; set; }
[ValidSimilarRequests(ErrorMessage =
"A holiday Request for this date range has already been requested")]
public int EmployeeID { get; set; }
[ValidSameWeek(ErrorMessage =
"Holiday Request Must be made on a weekly Period")]
[DisplayFormat(DataFormatString = "{0:dd/MMM/yy}", ApplyFormatInEditMode = true)]
public System.DateTime StartDate { get; set; }
[ValidStartFinishDate(ErrorMessage =
"Finish Date can not be Greater than Start date.")]
[DisplayFormat(DataFormatString = "{0:dd/MMM/yy}", ApplyFormatInEditMode = true)]
public System.DateTime FinishDate { get; set; }
[Range(0.0001, int.MaxValue, ErrorMessage = "Hours Requested must be greater than zero. ")]
public decimal HoursTaken { get; set; }
public string Comments { get; set; }
public int YearCreated { get; set; }
public int MonthCreated { get; set; }
public int DayCreated { get; set; }
public Nullable<int> YearOfHoliday { get; set; }
public Nullable<bool> Approved { get; set; }
public string SubmittedBy { get; set; }
public string ApprovedBy { get; set; }
public Nullable<int> WorkWeek { get; set; }
public Nullable<int> MonthOfHoliday { get; set; }
public virtual Employee Employee { get; set; }
}
The Error Page shows:
Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.
Controller:
[Authorize(Roles = "Admin,User,SuperUser")]
public ActionResult Create()
{
ViewBag.EmployeeID = new SelectList(db.Employees, "EmployeeID", "FullName");
return View();
string name = Session["Name"].ToString();
var EmployeeIDCatch = db.Employees.Where(s => s.Email.Equals(name)).Select(s => s.EmployeeID);
}
// POST: HolidayRequestForms/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "RequestID,StartDate,FinishDate,HoursTaken,Comments,YearCreated,MonthCreated,DayCreated,YearOfHoliday,Approved,SubmittedBy,ApprovedBy")] HolidayRequestForm holidayRequestForm)
{
if (ModelState.IsValid)
{
if (Session["Name"] == null)
{
TempData["msg"] = "Your Session Expired - Please Login";
return RedirectToAction("Login", "Account");
}
string name = Session["Name"].ToString();
var employeeID = db.Employees.Where(s => s.Email.Equals(name)).Select(s => s.EmployeeID).FirstOrDefault();
holidayRequestForm.EmployeeID = employeeID;
var submittedby = db.Employees.Where(s => s.Email.Equals(name)).Select(s => s.Email).FirstOrDefault();
holidayRequestForm.SubmittedBy = submittedby;
//Saves changes and begins Email Actions
db.HolidayRequestForms.Add(holidayRequestForm);
db.SaveChanges();
SendMailToAreaManager();
SendMailToManager();
SendMailToAdmin();
return RedirectToAction("Index", "Calendar");
}
ViewBag.EmployeeID = new SelectList(db.Employees, "EmployeeID", "FullName", holidayRequestForm.EmployeeID);
return View(holidayRequestForm);
}
VIEW:
#model HolidayTracker.Models.HolidayRequestForm
<div>
<div class="col-md-12">
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<h2 align="center">Holiday Request Form</h2>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.StartDate, "Start Date", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.StartDate, "Start Date", new { htmlAttributes = new { #class = "form-control", #style = "width:400px", autocomplete = "off" } })
#Html.ValidationMessageFor(model => model.StartDate, "", new { #class = "text-warning" })
<p id="warning" style="color:orange"></p>
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.FinishDate, "Finish Date", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.FinishDate, new { htmlAttributes = new { #class = "form-control",#style = "width:400px", autocomplete = "off" } })
#Html.ValidationMessageFor(model => model.FinishDate, "", new { #class = "text-danger" })
<p id="warningFD" style="color:orange"></p>
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.HoursTaken, "Hours Requested", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.HoursTaken, new { htmlAttributes = new { #class = "form-control", #style = "width:400px" } })
#Html.ValidationMessageFor(model => model.HoursTaken, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Comments, htmlAttributes: new { #class = "control-label col-md-2"})
<div class="col-md-10">
#Html.TextAreaFor(
model => model.Comments,
new { placeholder = "Enter Dates and how many Hours per Date Here. ", style = "width: 400px; height: 200px;" })
#Html.ValidationMessageFor(model => model.Comments, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Submit" class="btn btn-warning" />
</div>
</div>
}
</div>
</div>
</div>
I'm using begincollectionitem component, and when trying to save data is giving error at line db.SaveChanges();. I use MVC 4 e Razor.
This message error:
The operation failed: The relationship could not be changed because
one or more of the foreign-key properties is non-nullable. When a
change is made to a relationship, the related foreign-key property is
set to a null value. If the foreign-key does not support null values,
a new relationship must be defined, the foreign-key property must be
assigned another non-null value, or the unrelated object must be
deleted.
A minha implementação é esta:
Model
public class ProdutoPadrao : IEntidadeBase
{
[Key]
public int ProdutoPadraoID { get; set; }
[Display(Name = "Descrição")]
public string Descricao { get; set; }
[Display(Name = "Detalhe")]
public string Detalhe { get; set; }
public virtual ICollection<ProdutoPadraoCaracteristica> ListaProdutoCaracteristica { get; set; }
}
public class ProdutoPadraoCaracteristica : IEntidadeBase
{
[Key]
public int ProdutoPadraoCaracteristicaID { get; set; }
public int ProdutoPadraoID { get; set; }
public string Descricao { get; set; }
public int TipoCaracteristicaID { get; set; }
[ForeignKey("ProdutoPadraoID")]
public virtual ProdutoPadrao ProdutoPadrao { get; set; }
}
Controller GET
[ControleDeAcesso(TipoAcao.Normal)]
[Authorize]
public ActionResult Detalhar(int id)
{
using (var db = new ERPContext())
{
var produtoPadrao = db.ProdutoPadrao.Include("ListaProdutoCaracteristica").Where(w => w.ProdutoPadraoID == id).ToList().FirstOrDefault();
var retorno = EntidadeBaseExt.ValidarRegistro(produtoPadrao, TipoAcao.Visualizar);
if (retorno != "")
{
TempData["MsgRetornoError"] = retorno;
return RedirectToAction("Index", "Home");
}
ViewBag.ListaCaracteristica = new SelectList(ListagemPadrao.ListaTipoCaracteristica(), "Key", "Texto");
ViewBag.ListaUnidadeMedida = new SelectList(db.UnidadeMedida.ToListERP().Select(l => new ItemLPesquisa { Key = l.UnidadeMedidaID, Texto = l.Descricao }).ToArray(), "Key", "Texto");
return View(produtoPadrao);
}
}
Controller POST
[Authorize]
[HttpPost]
[ControleDeAcesso(TipoAcao.Normal)]
public ActionResult Detalhar(string btnSubmit, ProdutoPadrao model)
{
if (!ModelState.IsValid)
{
return View(model);
}
using (var db = new ERPContext())
{
var produtoPadrao = db.ProdutoPadrao.Include("ListaProdutoCaracteristica").Where(w => w.ProdutoPadraoID == model.ProdutoPadraoID).ToList().FirstOrDefault();
var retorno = FlexGestor.Helpers.EntidadeBaseExt.ValidarRegistro(produtoPadrao, TipoAcao.Gravar);
if (retorno != "")
{
TempData["MsgRetornoError"] = retorno;
return RedirectToAction("Index", "Home");
}
if (btnSubmit != "Excluir")
UpdateModel(produtoPadrao);
FlexGestor.Helpers.EntidadeBaseExt.AtribuirValores(produtoPadrao, btnSubmit);
db.Entry(produtoPadrao).State = EntityState.Modified;
db.SaveChanges();
if (btnSubmit == "Excluir")
return RedirectToAction("Index", controller);
return RedirectToAction("Detalhar", controller, new { id = model.ProdutoPadraoID });
}
}
View
#model FlexGestor.Models.ProdutoPadrao
#using (Html.BeginForm())
{
<div class="row">
#Html.TituloPagina("Visualizando Produto Padrão", "Clique para abrir a ajuda", "#help_produtoPadrao")
#Html.HiddenFor(m => m.ProdutoPadraoID)
<div class="col-md-12">
#Html.LabelFor(m => m.Descricao) #Html.ValidationMessageFor(m => m.Descricao)
#Html.TextBoxFor(m => m.Descricao, new { #class = "form-control" })
</div>
<div class="col-md-12">
#Html.LabelFor(m => m.Detalhe) #Html.ValidationMessageFor(m => m.Detalhe)
#Html.TextAreaFor(m => m.Detalhe, new { #class = "form-control", #rows = "4" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ListaProdutoCaracteristica)
<div class="controls">
<ul id="PhonesEditor" style="list-style-type: none">
#if (Model.ListaProdutoCaracteristica != null)
{
foreach (var item in Model.ListaProdutoCaracteristica)
{
Html.RenderPartial("_CustomerPhonesEditor", item);
}
}
</ul>
</div>
<p><a id="addAnother" class="small-button">AddPhone</a></p>
</div>
<div class="row">
<div class="col-md-12">
#Html.BotaoTelaDetalhar()
</div>
</div>
}
View Detail
#model FlexGestor.Models.ProdutoPadraoCaracteristica
#using (Html.BeginCollectionItem("ListaProdutoCaracteristica"))
{
#Html.HiddenFor(m => m.ProdutoPadraoID)
#Html.HiddenFor(m => m.ProdutoPadraoCaracteristicaID)
<div class="col-md-3">
#Html.LabelFor(m => m.TipoCaracteristicaID) #Html.ValidationMessageFor(m => m.TipoCaracteristicaID)
#Html.DropDownList("TipoCaracteristicaID", (SelectList)ViewBag.ListaCaracteristica, String.Empty,
new { #class = "form-control" })
</div>
<div class="col-md-9">
#Html.LabelFor(m => m.Descricao) #Html.ValidationMessageFor(m => m.Descricao)
#Html.TextBoxFor(m => m.Descricao, new { #class = "form-control" })
</div>
<div class="form-group">
<div class="controls">
<a onclick="$(this).parent().parent().parent().remove();" class="small-button" style="float: left;">Delete</a>
</div>
</div>
}
The below line is causing the problem
model.ListaProdutoCaracteristica = null;
It would cause the below property to be null, but it is not a nullable type
public int ProdutoPadraoID { get; set; }
If you want to be able to orphan records in this way, then you need to change it to a nullable int:
public int? ProdutoPadraoID { get; set; }
When I submit my form, the values are not being bound to the view model. I can't see what I'm doing wrong. Does anyone see something in my code I'm missing.
Here's a portion of the View:
#model FacilitiesCostIndex.ViewModels.AddAsset.TheViewModel
<div id="addAssetForm-div">
#using (Html.BeginForm("Submit", "AddAsset", FormMethod.Post, new { id = "AddAssetForm" }))
{
<span class="formTitle">#ViewBag.Title</span><br />
<fieldset id="topRow">
<legend></legend>
<!--Location-->
<span id="location" class="notes">- Location -</span><br />
<!--Site-->
<span id="site-span">
#Html.LabelFor(model => model.SiteId, new { #class = "formLabel" })
#Html.DropDownListFor(model => model.SiteId, Model.SiteItems, new { id = "siteDrpDwn", #class = "formDropDown" })
#Html.ValidationMessageFor(model => model.SiteId, string.Empty, new { id = "siteVldMsg", #class = "formValidationMessage" })
</span>
<!--Floor-->
<span id="floor-span">
#Html.LabelFor(model => model.FloorId, new { #class = "formLabel" })
<span id="floorDrpDwnContainer" data-populateurl="#Url.Action("PopulateFloorDrpDwn", "AddAsset")" data-unpopulateurl="#Url.Action("UnpopulateFloorDrpDwn", "AddAsset")">
#{Html.RenderPartial("AddAsset/UnpopulatedFloorDrpDwn", new FacilitiesCostIndex.ViewModels.AddAsset.FloorDrpDwnViewModel());}
</span>
#Html.ValidationMessageFor(model => model.FloorId, string.Empty, new { id = "floorVldMsg", #class = "formValidationMessage" })
</span>
<!--Zone-->
<span id="zone-span">
#Html.LabelFor(model => model.ZoneId, new { #class = "formLabel" })
<span id="zoneDrpDwnContainer" data-populateurl="#Url.Action("PopulateZoneDrpDwn", "AddAsset")" data-unpopulateurl="#Url.Action("UnpopulateZoneDrpDwn", "AddAsset")">
#{Html.RenderPartial("AddAsset/UnpopulatedZoneDrpDwn", new FacilitiesCostIndex.ViewModels.AddAsset.ZoneDrpDwnViewModel());}
</span>
#Html.ValidationMessageFor(model => model.ZoneId, string.Empty, new { id = "zoneVldMsg", #class = "formValidationMessage" })
</span><br />
</fieldset>
<fieldset id="leftColumn">
<legend></legend>
<!--Install Date-->
<div id="installDate-div" class="leftColumnItem">
#Html.LabelFor(model => model.InstallDate, new { id="installDateLbl" }) <br />
#Html.TextBoxFor(model => model.InstallDate, new { id="installDateTxt" })
</div>
<!--Name-->
<div id="assetName-div" class="leftColumnItem">
#Html.LabelFor(model => model.AssetName, new { #class="formLabel" }) <br />
#Html.TextBoxFor(model => model.AssetName, new { id="assetNameTxt", #class = "formTextbox" })
</div>
<!--Asset Number-->
<div id="assetNumber-div" class="leftColumnItem">
#Html.LabelFor(model => model.AssetNumber, new { #class="formLabel" }) <br />
#Html.TextBoxFor(model => model.AssetNumber, new { id="assetNumberTxt", #class = "formTextbox" })
</div>
<!--Description-->
<div id="description-div" class="leftColumnItem">
#Html.LabelFor(model => model.Description, new { #class="formLabel" }) <br />
#Html.TextBoxFor(model => model.Description, new { id="descriptionTxt", #class = "formTextbox" })
</div>
<!--Group-->
<div id="group-div" class="leftColumnItem">
#Html.LabelFor(model => model.GroupId, new { #class = "formLabel" }) <br />
#Html.DropDownListFor(model => model.GroupId, Model.GroupItems, new { id = "groupDrpDwn", #class = "formDropDown" })
#Html.ValidationMessageFor(model => model.GroupId, string.Empty, new { id = "groupVldMsg", #class = "formValidationMessage" })
</div>
Here's a portion of the ViewModel:
public class TheViewModel
{
[Display(Name = "Site")]
public int SiteId { get; set; }
public IEnumerable<SelectListItem> SiteItems { get; private set; }
[Display(Name = "Floor")]
[Required(ErrorMessage = "Please select a Floor.")]
public int FloorId { get; set; }
[Display(Name = "Zone")]
[Required(ErrorMessage = "Please select a Zone.")]
public int ZoneId { get; set; }
[Display(Name = "Name")]
[Required(ErrorMessage = "Please enter an Asset Name.")]
public string AssetName { get; set; }
[Display(Name = "Asset Number")]
[Required(ErrorMessage = "Please enter an Asset Number.")]
public string AssetNumber { get; set; }
[Display(Name = "Description")]
public string Description { get; set; }
[Display(Name = "INSTALL DATE")]
[Required(ErrorMessage = "Please enter an install date.")]
public DateTime? InstallDate { get; set; }
[Display(Name = "Group")]
[Required(ErrorMessage = "Please select a Group.")]
public int GroupId { get; set; }
public IEnumerable<SelectListItem> GroupItems { get; private set; }
public TheViewModel()
{
SiteId = -1;
SetSiteItems();
GroupId = -1;
SetGroupItems();
}
Here's code for the controller:
[HttpPost]
public ActionResult Submit(TheViewModel model)
{
DateTime DateEntered = DateTime.Now;
AssetModel AnAsset = new AssetModel();
AnAsset.AssetName = model.AssetName;
AnAsset.AssetNumber = model.AssetNumber;
AnAsset.AssetTypeId = model.AssetTypeId;
AnAsset.GroupId = model.GroupId;
AnAsset.ZoneId = model.ZoneId;
AnAsset.Description = model.Description;
//Note: Conversion from nullable to non-nullable type is dealt with.
if (model.InstallDate.HasValue)
{
AnAsset.InstallDate = model.InstallDate.Value;
}
//Send asset to insert method.
new AssetRepositoryModel().Insert(AnAsset);
return View();
}
Appreciate any help you can give me. Thanks.
probably solved using binding in Global.asax and defining your TheViewModelBinder class inherited from IModelBinder?
ModelBinders.Binders.Add( typeof(TheViewModel), new TheViewModelBinder() );
and binder class is something like this:
public class TheViewModelBinder : IModelBinder {
public object BindModel( ControllerContext controllerContext, ModelBindingContext bindingContext ) {
var theViewModel = new TheViewModel();
theViewModel.SiteId = int.Parse(request.Form.Get( "SiteId" ));
//other your code here
}
}