Error post using begincollectionitem MVC C# - c#

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; }

Related

C# MVC Ajax Form Modal DropDownList Validation Error

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);
}

How to bind an object in a view to the controller?

This may be a dumb question but I'm kind of new with the razor. I'm trying to create a dynamic form. I have a list of object of fields and show them dynamically in my page. But, when I want to save the selected value of my field for a dropdown(example), I don't know how to save the object of my foreach to my model in the controller (I can save my value with no harm).
Index.cshtml:
<div class="row">
#foreach (var buildingBlock in buildingBlocks)
{
<div class="col-sm">
<div class="card">
<div class="card-body">
<h5 class="card-title">#buildingBlock.BuildingBlockTitle</h5>
#foreach (Test.Test.Models.BuildingBlockField buildingBlockField in buildingBlockFields)
{
<div class="form-group">
<label for="companyName">Company Name</label>
//I tried that but it's not working (Obviously :))
#Html.EditorFor(model => buildingBlockField)
#Html.DropDownListFor(model => model.buildingBlockFields[0].Values, buildingBlockField.OptionDetails, "Select Contract", new { #class = "selectpicker", multiple = "multiple" })
</div>
}
</div>
</div>
</div>
}
</div>
BuildingBlockField:
public class BuildingBlockField
{
public int BuildingBlockFieldID{ get; set; }
public int BuildingBlockID { get; set; }
public List<SelectListItem>? OptionDetails { get; set; }
public string FieldTitle { get; set; }
public FieldType Type { get; set; }
public bool IsMultiple { get; set; }
public int[] Values { get; set; }
public string Value { get; set; }
}
model controller:
public class ContractInformationsModel
{
public List<BuildingBlockField> buildingBlockFields { get; set; }
}
HomeController:
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.BuildingBlocks = Models.BuildingBlock.getBuildingBlocks();
ViewBag.BuildingBlockFields = Models.BuildingBlockField.getBuildingBlockFields();
return View();
}
[HttpPost]
public ActionResult generateWordContract(ContractInformationsModel contractInformations)
{
return View("Index");
}
}
I expect to find in my controller object contractInformations to find a list of buildingBlockFields with all the information and not only the value.
Thank you
Edit :
This seems to work but i have to do it for every property and hide then. Is there any other solution ?
#for (var i = 0; i < buildingBlockFields.Count(); i++){
<div class="form-group">
#Html.HiddenFor(model => model.buildingBlockFields[i].BuildingBlockFieldID, new { Value = buildingBlockFields[i].BuildingBlockFieldID })
#Html.HiddenFor(model => model.buildingBlockFields[i].FieldTitle, new { Value = buildingBlockFields[i].FieldTitle })
#Html.HiddenFor(model => model.buildingBlockFields[i].Type, new { Value = buildingBlockFields[i].Type })
#Html.DropDownListFor(model => model.buildingBlockFields[0].Values, buildingBlockFields[i].OptionDetails, "Select Contract", new { #class = "selectpicker", multiple = "multiple" })
</div>
}
Since you are passing ContractInformationsModel model to your view, which has a list of type BuildingBlockField, your html should contain the building block field ID and a "counter" that can identify indexes in that list.
#{
// declare counter
int i = 0
}
#foreach (BuildingBlockField buildingBlockField in buildingBlockFields)
{
<div class="form-group">
<label for="companyName">#buildingBlockField.FieldTitle</label>
#Html.HiddenFor(model=>model.buildingBlockFields[i].BuildingBlockFieldID)
#Html.TextBoxFor(model => model.buildingBlockFields[i].FieldTitle, new { #class = "form-control", Value = #buildingBlockField.FieldTitle })
#Html.DropDownListFor(model => model.buildingBlockFields[i].Values, buildingBlockField.OptionDetails, "Select Contract", new { #class = "selectpicker", multiple = "multiple" })
</div>
#i++
}

ModelState is validating Id in a insert

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; }

Can not insert my dropdownlist data in database with foreign key in mvc4

I want to pack my data in form with foreign key and send that to database.I collect data from database with controller and show in my view and when I complete the form can not send that to database and see the exception
my controller code is
public ActionResult Register()
{
testContext test = new testContext();
List<SelectListItem> listselecteditem = new List<SelectListItem>();
foreach (Gender item in test.genders)
{
SelectListItem selectlist = new SelectListItem()
{
Text = item.GenderType,
Value = item.GenderID.ToString(),
};
listselecteditem.Add(selectlist);
}
ViewBag.Datalist = new SelectList(listselecteditem, "Value", "Text");
return View();
}
this controller get data from database and send to dropdownlist
and this controller save my data in database
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Register(Person p)
{
using (testContext test=new testContext())
{
if (ModelState.IsValid)
{
try
{
test.persons.Add(p);
test.SaveChanges();
ViewBag.Message="Success";
}
catch (Exception ec)
{
ViewBag.Message = ec.Message;
}
}
}
return View(p);
}
this is my view
#model testmvc.Models.Person
<div class="container">
<div class="row">
<div class="pull-right col-sm-offset-3 col-sm-6">
<div class="panel panel-default">
<div class="panel-heading ">
<p>register</p>
</div>
<div class="panel-body">
#using (Html.BeginForm("Register", "RegisterLogin", FormMethod.Post, new { #class = "form-horizontal" }))
{
#Html.ValidationSummary(true)
<fieldset>
#Html.AntiForgeryToken()
#if (ViewBag.Messsage != null)
{
<div class="alert alert-success">
<p>#ViewBag.Message</p>
</div>
}
<div class="form-group">
#Html.TextBoxFor(model => model.Fullname, new { #class = "form-control", #placeholder = "Full name" })
</div>
<div class="form-group">
#Html.TextBoxFor(model => model.Username, new { #class = "form-control input-sm", #id = "last_name", #placeholder = "Username" })
</div>
<div class="form-group">
#Html.TextBoxFor(model => model.EmailAddress, new { #class = "form-control input-sm", #id = "email", #placeholder = "Email address" })
</div>
<div class="form-group">
#Html.TextBoxFor(model => model.Password, new { #class = "form-control input-sm floatlabel", #id = "first_name", #placeholder = "Password" })
</div>
<div class="form-group">
#Html.TextBoxFor(model => model.Comfirmpassword, new { #class = "form-control input-sm", #id = "last_name", #placeholder = "confirmpassword" })
</div>
<div class="form-group">
#*<select>
#foreach (var item in ViewBag.DataList)
{
<option>#item.Text</option>
}
</select>*#
#Html.DropDownList("Datalist",String.Empty)
</div>
<div class="form-group">
#Html.TextBoxFor(model => model.Birthday, new { #class = "form-control input-sm", #id = "password_confirmation", #placeholder = "Birthday yyyy/dd/mm" })
</div>
<div>
<input type="submit" value="Register" class="btn btn-primary">
</div>
</fieldset>
}
</div>
</div>
</div>
</div>
</div>
and my model code
public partial class Person
{
[Key]
public int personID { get; set; }
[Required]
public String Fullname { get; set; }
[Required]
public String Username { get; set; }
[Required]
public String Password { get; set; }
[Required]
[NotMapped]
public String Comfirmpassword { get; set; }
[Required]
public String EmailAddress { get; set; }
[DataType(DataType.DateTime)]
[Required]
public DateTime Birthday { get; set; }
public int GenderID { get; set; }
[ForeignKey("GenderID")]
public virtual Gender Gender { get; set; }
}
[Table("Gender")]
public partial class Gender
{
[Key]
public int GenderID { get; set; }
[Required]
public String GenderType { get; set; }
public virtual ICollection<Person> Persons { get; set; }
}
this exception said there is not any viewdata key with "Datalist". how can I solve that and what is my code problem
The reason you are getting this exception is because inside [HttpPost] action you didn't populate the ViewBag.Datalist property, the way you did in your Get action. Since you redisplay the same view and this view requires this information in order to properly render the dropdown, you will need to populate it. To avoid repetition you could place this logic in a separate method:
private SelectList GetGenders()
{
using (testContext test = new testContext())
{
List<SelectListItem> listselecteditem = new List<SelectListItem>();
foreach (Gender item in test.genders)
{
SelectListItem selectlist = new SelectListItem()
{
Text = item.GenderType,
Value = item.GenderID.ToString(),
};
listselecteditem.Add(selectlist);
}
return new SelectList(listselecteditem, "Value", "Text");
}
}
which you are going to call in your 2 actions:
public ActionResult Register()
{
ViewBag.Datalist = GetGenders();
return View();
}
and:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Register(Person p)
{
using (testContext test = new testContext())
{
if (ModelState.IsValid)
{
try
{
test.persons.Add(p);
test.SaveChanges();
ViewBag.Message = "Success";
}
catch (Exception ec)
{
ViewBag.Message = ec.Message;
}
}
}
ViewBag.Datalist = GetGenders();
return View(p);
}

Unable to set selected item from DropDownList to controller

In my view the DropDownList shows the correct fields but when I select one in "edit or create" the field will be saved/modified as NULL. When debugging I can see that the new value is not send. I think there is a mismatch between ID and SurveyID...
View:
#model Project_ASP_2012.Models.QuestionGroup
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>QuestionGroup</legend>
#Html.HiddenFor(model => model.ID)
<div class="editor-label">
#Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Description)
#Html.ValidationMessageFor(model => model.Description)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.SurveyID, "Survey")
</div>
<div class="editor-field">
#Html.DropDownList("Id", String.Empty)
#Html.ValidationMessageFor(model => model.SurveyID)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Model:
public class Survey : IEntity
{
[Key]
[Display(Name = "SurveyID")]
public int ID { get; set; }
[Required(ErrorMessage = "Survey title is required.")]
[Display(Name = "Survey Title")]
[MaxLength(20, ErrorMessage = "Title cannot be longer than 20 characters.")]
public string Title { get; set; }
[MaxLength(50, ErrorMessage = "Description cannot be longer than 50 characters.")]
public string Description { get; set; }
public virtual ICollection<QuestionGroup> QuestionGroups { get; set; }
}
public class QuestionGroup : IEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[MaxLength(50, ErrorMessage = "Description cannot be longer than 50 characters.")]
public string Description { get; set; }
[Display(Name = "SurveyID")]
public int? SurveyID { get; set; }
public virtual Survey Survey { get; set; }
}
Controller:
public ActionResult Edit(int id)
{
QuestionGroup questiongroup = unitOfWork.QuestionGroupRepository.GetById(id);
if (questiongroup == null)
{
return HttpNotFound();
}
PopulateSurveysDropDownList(questiongroup.SurveyID);
return View(questiongroup);
}
//
// POST: /QuestionGroup/Edit/5
[HttpPost]
public ActionResult Edit(QuestionGroup questiongroup)
{
try
{
if (ModelState.IsValid)
{
unitOfWork.UoWContext.Entry(questiongroup).State = EntityState.Modified;
unitOfWork.SaveChanges();
return RedirectToAction("Index");
}
}
catch (DataException)
{
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
}
PopulateSurveysDropDownList(questiongroup.SurveyID);
return View(questiongroup);
}
private void PopulateSurveysDropDownList(object selectedSurvey = null)
{
var surveyQuery = unitOfWork.SurveyRepository.Get(
orderBy: q => q.OrderBy(d => d.Title));
ViewBag.Id = new SelectList(surveyQuery, "Id", "Title", selectedSurvey);
}
In your view you have dropdown for Id instead of SurveyId. Additionaly you have ID twice - in dropdown and in hidden field.
<div class="editor-field">
#Html.DropDownList("Id", String.Empty)
#Html.ValidationMessageFor(model => model.SurveyID)
</div>
Try changing:
private void PopulateSurveysDropDownList(object selectedSurvey = null)
{
var surveyQuery = unitOfWork.SurveyRepository.Get(
orderBy: q => q.OrderBy(d => d.Title));
ViewBag.Id = new SelectList(surveyQuery, "Id", "Title", selectedSurvey);
}
....
<div class="editor-field">
#Html.DropDownList("Id", String.Empty)
#Html.ValidationMessageFor(model => model.SurveyID)
</div>
To:
private void PopulateSurveysDropDownList(object selectedSurvey = null)
{
var surveyQuery = unitOfWork.SurveyRepository.Get(
orderBy: q => q.OrderBy(d => d.Title));
//don't provide the select value here. you will bind to it in your view
ViewBag.SurveySelectList = new SelectList(surveyQuery, "Id", "Title");
}
....
<div class="editor-field">
//selected value will be whatever SurveyID is on your model.
#Html.DropDownListFor(model => model.SurveyID, ViewBag.SurveySelectList, String.Empty)
#Html.ValidationMessageFor(model => model.SurveyID)
</div>
Hope that helps.

Categories

Resources