I have used range validation but this is not working. I am adding model,controller and view code.Please help(i have added only related fields only in this code).
Model is :
public class TicketDetailModel : TicketModelBase
{
public WorkOnTicketCreateModel WorkOnTicketCreateModel { get; set; }
}
public class TicketModelBase
{
[Required]
[Range(1, int.MaxValue, ErrorMessage = "Please enter a value bigger than {0}")]
public int EstimatedTime { get; set; }
public virtual List<WorkOnTicket> WorkOnTickets { get; set; }
}
public class WorkOnTicketCreateModel : WorkOnTicketModelBase
{
[Required]
[Display(Name = "AssignedToUser")]
public int AssignedToUserId { get; set; }
public IEnumerable<SelectListItem> AssignedUser { get; set; }
[Required]
[Display(Name = "Ticket Status")]
public int TicketStatusId { get; set; }
public TicketStatus TicketStatusVal { get; set; }
public IEnumerable<SelectListItem> TicketStatus { get; set; }
}
public class WorkOnTicketModelBase
{
public int Id { get; set; }
[Required]
public int EstimateHours { get; set; }
[Required]
[Range(1, int.MaxValue, ErrorMessage = "Please enter a value bigger than {0}")]
public int WorkedHours { get; set; }
}
Contoller:
[HttpPost]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Details(TicketDetailModel model, IEnumerable<HttpPostedFileBase> file)
{
using (ITransaction transaction = this.nhSession.BeginTransaction())
{
var ticketObj = this.nhSession.QueryOver<Ticket>().Where(t => t.Id == model.Id).SingleOrDefault();
var workOnTicket = new WorkOnTicket();
workOnTicket.Ticket = ticketObj;
workOnTicket.WorkedHours = model.WorkOnTicketCreateModel.WorkedHours;
workOnTicket.EstimateHours = model.WorkOnTicketCreateModel.EstimateHours;
ticketObj.WorkOnTickets.Add(workOnTicket);
this.nhSession.Save(ticketObj);
transaction.Commit();
}
return RedirectToAction("Details", new { id = model.Id, milestoneId = model.Milestone.Id, projectId = model.Project.Id });
}
View:-
#model AnkTech.TicketManagement.Web.Models.Ticket.TicketDetailModel
#using (Html.BeginForm("Details", "Ticket", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.ValidationSummary(true)
#Html.TextBoxFor(model => model.WorkOnTicketCreateModel.EstimateHours, new { #id = "work_remaining", #class = "s-mini", size = "2" })
Worked hours: #Html.TextBoxFor(model => model.WorkOnTicketCreateModel.WorkedHours, new { #id = "worked_hours", #class = "s-mini", size = "2" })
<input type="submit" value="Submit" tabindex="2" name="commit" id="submit-comment"
class="gray-btn">
}
I have deleted all rmaining fields. i have added only fields to which related i am asking, please help.
You need to use ModelState.IsValid to check that the model is actually valid. Currently you assign validation attributes but never check them:
[HttpPost]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Details(TicketDetailModel model, IEnumerable file) {
if (!ModelState.IsValid)
{
// Handle error
}
else
{
using (ITransaction transaction = this.nhSession.BeginTransaction()) {
var ticketObj = this.nhSession.QueryOver<Ticket>().Where(t => t.Id == model.Id).SingleOrDefault();
var workOnTicket = new WorkOnTicket();
workOnTicket.Ticket = ticketObj;
workOnTicket.WorkedHours = model.WorkOnTicketCreateModel.WorkedHours;
workOnTicket.EstimateHours = model.WorkOnTicketCreateModel.EstimateHours;
ticketObj.WorkOnTickets.Add(workOnTicket);
this.nhSession.Save(ticketObj);
transaction.Commit();
}
}
return RedirectToAction("Details", new { id = model.Id, milestoneId = model.Milestone.Id, projectId = model.Project.Id });
}
Related
I am creating a simple WebApi for Recipes. A recipe contains both ingredients and instructions. I think I got most of the WebApi down, except for the Update() part.
I am not quite sure if I am doing it the right way. My code looks very long and complicated.
Is there an easier way to update parent and all children?
public async Task<IActionResult> Update(int id, [FromBody] RecipeViewModel recipeViewModel)
{
var recipeToUpdate = _unitOfWork.RecipeRepository.Get(filter: r => r.RecipeId == id,
includeProperties: "Ingredients,Instructions").FirstOrDefault();
recipeToUpdate.Name = recipeViewModel.Name;
recipeToUpdate.Description = recipeViewModel.Description;
recipeToUpdate.Image = recipeViewModel.Image;
foreach (var oldIngredient in recipeToUpdate.Ingredients)
{
var newIngredient = recipeViewModel.Ingredients.Where(ingredient => ingredient.IngredientId == oldIngredient.IngredientId).FirstOrDefault();
if (newIngredient == null)
{
recipeToUpdate.Ingredients.Remove(oldIngredient);
_unitOfWork.IngredientRepository.Delete(oldIngredient);
}
else
{
oldIngredient.Value = newIngredient.Value;
oldIngredient.Name = newIngredient.Name;
oldIngredient.Position = newIngredient.Position;
oldIngredient.Unit = newIngredient.Unit;
_unitOfWork.IngredientRepository.Update(newIngredient);
}
}
foreach (var newIngredient in recipeViewModel.Ingredients)
{
var oldIngredient = recipeToUpdate.Ingredients.Where(ingredient => ingredient.IngredientId == newIngredient.IngredientId).FirstOrDefault();
if (oldIngredient == null)
{
recipeToUpdate.Ingredients.Add(newIngredient);
_unitOfWork.IngredientRepository.Insert(newIngredient);
}
else
{
oldIngredient.Value = newIngredient.Value;
oldIngredient.Name = newIngredient.Name;
oldIngredient.Position = newIngredient.Position;
oldIngredient.Unit = newIngredient.Unit;
_unitOfWork.IngredientRepository.Update(oldIngredient);
}
}
foreach (var oldInstruction in recipeToUpdate.Instructions)
{
var newInstruction = recipeViewModel.Instructions.Where(instruction => instruction.InstructionId == oldInstruction.InstructionId).FirstOrDefault();
if (newInstruction == null)
{
recipeToUpdate.Instructions.Remove(oldInstruction);
_unitOfWork.InstructionRepository.Delete(oldInstruction);
}
else
{
oldInstruction.Position = newInstruction.Position;
oldInstruction.Description = newInstruction.Description;
_unitOfWork.InstructionRepository.Update(oldInstruction);
}
}
foreach (var newInstruction in recipeViewModel.Instructions)
{
var oldInstruction = recipeToUpdate.Instructions.Where(instruction => instruction.InstructionId == newInstruction.InstructionId).FirstOrDefault();
if (oldInstruction == null)
{
recipeToUpdate.Instructions.Add(newInstruction);
_unitOfWork.InstructionRepository.Insert(newInstruction);
}
else
{
oldInstruction.Position = newInstruction.Position;
oldInstruction.Description = newInstruction.Description;
_unitOfWork.InstructionRepository.Update(oldInstruction);
}
}
_unitOfWork.RecipeRepository.Update(recipeToUpdate);
await _unitOfWork.Save()
}
And these are my models and my view model:
public class Recipe
{
public int RecipeId { get; set; }
[DataType(DataType.DateTime)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd HH:mm:ss}")]
public DateTime? CreationDate { get; set; }
[JsonIgnore]
public virtual IdentityUser? Creator { get; set; }
[Required(ErrorMessage = "A recipe must have a name"), MaxLength(254)]
public string? Name { get; set; }
[Required(ErrorMessage = "A recipe must have a description"), MaxLength(254)]
public string? Description { get; set; }
public virtual ICollection<Ingredient>? Ingredients { get; set; }
public virtual ICollection<Instruction>? Instructions { get; set; }
public string? Image { get; set; }
}
public class Ingredient
{
public int IngredientId { get; set; }
public int Position { get; set; }
[Required(ErrorMessage = "An ingredient must have a value")]
public Decimal? Value { get; set; }
[Required(ErrorMessage = "An ingredient must have a unit")]
public string? Unit { get; set; }
[Required(ErrorMessage = "An ingredient must have a name")]
public string? Name { get; set; }
}
public class Instruction
{
public int InstructionId { get; set; }
public int Position { get; set; }
[Required(ErrorMessage = "An instruction cannot be empty")]
public string? Description { get; set; }
}
public class RecipeViewModel
{
[Required(ErrorMessage = "A recipe must have a name"), MaxLength(254)]
public string? Name { get; set; }
[Required(ErrorMessage = "A recipe must have a description"), MaxLength(254)]
public string? Description { get; set; }
public ICollection<Ingredient>? Ingredients { get; set; }
public ICollection<Instruction>? Instructions { get; set; }
public string? Image { get; set; }
}
Appreciate any help, thanks.
I am trying to create an edit form which includes a selectlist that gets the data from the database. I am unable to display the form since I cannot map the viewmodel with the actual model using Automapper.
Contact.cs:
public int ContactId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string? EmailAddress { get; set; }
public int CompanyId { get; set; }
[ForeignKey("CompanyId")]
public Company Company { get; set; }
ContactEditViewModel.cs:
public int ContactId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string? EMailAddress { get; set; }
[Range(1, int.MaxValue, ErrorMessage = "Please select a company.")]
public int CompanyId { get; set; }
public SelectList? Company { get; set; }
Edit View
<div class="form-group">
<label asp-for="Company" class="control-label"></label>
<div class="input-group mb-3">
<select asp-for="CompanyId" class="form-select" asp-items="#Model.Company"></select>
</div>
</div>
ContactsController Edit Action:
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var contact = await _context.Contacts.FirstOrDefaultAsync(c => c.ContactId == id);
var model = new ContactEditVM
{
Company = new SelectList(_context.Companies, "CompanyId", "CompanyName"),
};
//var contact = mapper.Map<ContactEditVM>(await contactRepository.GetAsync(id));
mapper.Map(model, contact);
if (contact == null)
{
return NotFound();
}
//ViewData["CompanyId"] = new SelectList(_context.Companies, "CompanyId", "CompanyName", contact.Company);
return View(model);
}
MappingConfiguration
public class MapConfig : Profile
{
public MapConfig()
{
CreateMap<Contact, ContactListVM>().ReverseMap();
CreateMap<Contact, ContactCreateVM>().ReverseMap();
CreateMap<Contact, ContactEditVM>().ReverseMap();
}
}
The error I get is:
AutoMapperMappingException: Missing type map configuration or unsupported mapping.
Mapping types:
SelectList -> Company
Microsoft.AspNetCore.Mvc.Rendering.SelectList -> ENV.Data.Company
Destination Member:
Company
...
If I create a new instance of my viewmodel and assign values to it manually, without using Automapper, it works as intended. So what is wrong with my mapping?
Does it work if you outcomment the "Company" from your Contact.cs and outcomment the "Company" from your ContactEditViewModel.cs?
I think you need to define a mapping which tells autoMapper how to map a "SelectedList?" to a "Company".
For Example:
var autoMapperConfig = new MapperConfiguration(cfg =>
{
cfg.CreateMap<WalletData/*Source*/, BP_WalletDTO/*Destination*/>()
.ForMember(dest => dest.Id, memberOptions => memberOptions.MapFrom(src => src.Id))
.ForMember(dest => dest.Type, memberOptions => memberOptions.MapFrom(src => src.Type))
.ForMember(dest => dest.Attributes, memberOptions => memberOptions.MapFrom(src => new BP_WalletAttributesDTO
{
CryptocoinId = src.Attributes.Cryptocoin_id,
CryptocoinSymbol = src.Attributes.Cryptocoin_symbol,
Balance = src.Attributes.Balance,
IsDefault = src.Attributes.Is_default,
Name = src.Attributes.Name,
PendingTransactionsCount = src.Attributes.Pending_transactions_count,
Deleted = src.Attributes.Deleted,
IsIndex = src.Attributes.Is_index,
}));
});
Maybe this helps
I really thought I understood what I was doing, but here goes. I decided I need more properties in my View so I created a ViewModel called ViewDataset and replaced the original Dataset model in the View. On my HttpGet TestDataset the View Model is populated correctly with data from the Viewmodel:
My original dataset that was working is below:
public class Dataset
{
public int Dataset_ID { get; set; }
public int Category_ID { get; set; }
public string Provider { get; set; }
public string Name { get; set; }
public string Institution { get; set; }
public string Description { get; set; }
public string Location { get; set; }
public bool Domestic { get; set; }
public bool International { get; set; }
public bool Includes_PHI { get; set; }
public bool PHI_Limited { get; set; }
public bool Includes_PIL { get; set; }
public bool PIL_Limited { get; set; }
public bool Citation_Requirements { get; set; }
public string Citation_Comments { get; set; }
public Nullable<System.DateTime> Availability_Beg_DT { get; set; }
public Nullable<System.DateTime> Availability_End_DT { get; set; }
public bool Subscription_Renewal { get; set; }
public Nullable<System.DateTime> Subscription_Renewal_DT { get; set; }
public bool Retention_Expiry { get; set; }
public Nullable<System.DateTime> Retention_Expiry_DT { get; set; }
public bool Data_Destruction { get; set; }
public Nullable<System.DateTime> Data_Destruction_DT { get; set; }
public string Data_Destruction_Instructions { get; set; }
public Nullable<int> Contract_ID { get; set; }
public bool Draft_Status { get; set; }
public bool Admin_Only { get; set; }
public string Dataset_Alias { get; set; }
public bool Loc_Amazon { get; set; }
public bool Loc_IT_Research { get; set; }
public bool Loc_Research_Proj { get; set; }
public bool Loc_Secure_Data { get; set; }
public bool Loc_Mercury { get; set; }
public bool Loc_Research_CC { get; set; }
public bool Loc_Research_VM { get; set; }
public bool Loc_External { get; set; }
public bool Access_Url { get; set; }
public bool Access_Download_App { get; set; }
public bool Access_Lab_Terminal { get; set; }
public bool Access_Email_Req { get; set; }
public bool Access_File_Download { get; set; }
public bool Access_Other { get; set; }
public string Location_Notes { get; set; }
public string Access_Notes { get; set; }
public Nullable<System.DateTime> Date_Added { get; set; }
public Nullable<System.DateTime> Date_Modified { get; set; }
public string Added_By_User { get; set; }
public string Updated_By_User { get; set; }
public bool External_Collaborators
{
get; set;
}
}
Here is my new ViewDataset (viewmodel)
public class ViewDataset
{
public Dataset dataset;
public List<SelectListItem> categories_list;
}
Here is my is a sample of my view ... couple of lines, but the view is populated correctly with data from the ViewDataset model
#model ResearchDataInventoryWeb.Models.ViewDataset
<td>
#Html.TextBoxFor(model => model.dataset.Institution, new { placeholder = "<Institution>", #class = "input-box" })
</td>
<td>
#Html.TextBoxFor(model => model.dataset.Name, new { placeholder = "<Dataset Name>", #class = "input-box" })
</td>
#Html.CheckBoxFor(model => model.dataset.Domestic) <span class="display-checkbox">Domestic</span>
#Html.CheckBoxFor(model => model.dataset.International) <span class="display-checkbox">International</span>
#Html.CheckBoxFor(model => model.dataset.Includes_PHI) <span class="display-checkbox">Includes PHI </span>
#Html.CheckBoxFor(model => model.dataset.Includes_PIL) <span class="display-checkbox">Includes PII </span><br />
#Html.CheckBoxFor(model => model.dataset.External_Collaborators) <span class="display-checkbox">External Collaborators Allowed (Sharable)</span>
#Html.CheckBoxFor(model => model.dataset.Citation_Requirements) <span class="display-checkbox">Citation Requirements</span>
<input type="submit" value="TestPost" />
Here is my HttpPost TestDataset : The model Viewdataset (dataset, categories_list) properties that I am passing back from the view are NULL, am I missing something?
[HttpPost]
public ActionResult TestDataset(ViewDataset viewdataset)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:4251/");
//HTTP POST
viewdataset.dataset.Category_ID = 2;
viewdataset.dataset.Dataset_ID = 1;
viewdataset.dataset.Location = "Fingers Crossed";
viewdataset.dataset.Institution = "Not Null";
var dataset = viewdataset.dataset;
// var postTask = client.PostAsJsonAsync<Dataset>("api/datasets/1", dataset);
var postTask = client.PostAsJsonAsync("api/datasets/1", dataset);
postTask.Wait();
var result = postTask.Result;
if (result.IsSuccessStatusCode)
{
return RedirectToAction("Index");
}
}
ModelState.AddModelError(string.Empty, "Server Error. Please contact administrator.");
return View(viewdataset);
}
Here if my HttpGet TestDataset in case you need to see it
public async Task<ActionResult> TestDataset()
{
//Hosted web API REST Service base url
string Baseurl = "http://localhost:4251/";
List<Dataset> dataset = new List<Dataset>();
List<Category> categories = new List<Category>();
var parm = "1";
var returned = new Dataset();
var ViewDataset = new ViewDataset();
using (var client = new HttpClient())
{
//Passing service base url
client.BaseAddress = new Uri(Baseurl);
client.DefaultRequestHeaders.Clear();
//Define request data format
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//Sending request to find web api REST service resource GetAllEmployees using HttpClient
HttpResponseMessage Res = await client.GetAsync("api/Datasets/" + parm);
HttpResponseMessage Res2 = await client.GetAsync("api/Categories");
//Checking the response is successful or not which is sent using HttpClient
if (Res.IsSuccessStatusCode)
{
//Storing the response details recieved from web api
var EmpResponse = Res.Content.ReadAsStringAsync().Result;
//Deserializing the response recieved from web api and storing into the Employee list
returned = JsonConvert.DeserializeObject<Dataset>(EmpResponse);
}
if (Res2.IsSuccessStatusCode)
{
//Storing the response details recieved from web api
var CatResp = Res2.Content.ReadAsStringAsync().Result;
//Deserializing the response recieved from web api and storing into the Employee list
categories = JsonConvert.DeserializeObject<List<Category>>(CatResp);
}
// Create the Categories Select List
var categoryList = new List<SelectListItem>();
foreach (Category c in categories)
{
categoryList.Add(new SelectListItem
{
Value = c.Category_ID.ToString(),
Text = c.Description,
Selected = (c.Category_ID == returned.Category_ID ? true : false)
});
}
ViewDataset.dataset = returned;
ViewDataset.categories_list = categoryList;
//returned.External_Collaborators = returned.External_Collaborators == null || false ? false : true;
//returning the employee list to view
return View(ViewDataset);
}
}
Try to change
public class ViewDataset
{
public Dataset dataset;
public List<SelectListItem> categories_list;
}
to
public class ViewDataset
{
public Dataset dataset { get; set; }
public List<SelectListItem> categories_list { get; set; }
}
In a crud asp.net core 2.2 web app, I need to avoid saving a property of form object to db. How do I do that?
I've tried using [Editable(false)] data annotation on the ListBin property to prevent saving property value to db.
[Table("supply_lists")]
public partial class SupplyLists
{
[Column("id")]
public int Id { get; set; }
[Column("category_id")]
public int CategoryId { get; set; }
[Required]
[Column("coursecode")]
[StringLength(200)]
public string Coursecode { get; set; }
[Required]
[Column("title")]
[StringLength(200)]
public string Title { get; set; }
[Required]
[Column("filename")]
[StringLength(200)]
public string Filename { get; set; }
[Column("isactive")]
public bool Isactive { get; set; }
[Column("date", TypeName = "smalldatetime")]
public DateTime Date { get; set; }
[Column("list_bin")]
public byte[] ListBin { get; set; }
[ForeignKey("CategoryId")]
[InverseProperty("SupplyLists")]
public virtual SupplyListCategory Category { get; set; }
}
[ModelMetadataType(typeof(MetaDataTypeModel))]
public partial class SupplyLists
{
}
public class MetaDataTypeModel
{
[Editable(false)]
public byte[] ListBin { get; set; }
[Display(Name = "Is Active")]
public bool Isactive { get; set; }
[Display(Name ="Course Code")]
public string Coursecode { get; set; }
[Display(Name = "Category")]
public int CategoryId { get; set; }
[DataType(DataType.Date)]
public DateTime Date { get; set; }
}
public class EditModel : PageModel
{
private readonly SupplyListCore22.Models.SupplyListsContext _context;
private readonly IHostingEnvironment _env;
public EditModel(SupplyListCore22.Models.SupplyListsContext context, IHostingEnvironment env)
{
_context = context;
_env = env;
}
[BindProperty]
public SupplyLists SupplyLists { get; set; }
[BindProperty]
public FileUpload FileUpload { get; set; }
public async Task<IActionResult> OnGetAsync(int? id)
{
if (id == null)
{
return NotFound();
}
SupplyLists = await _context.SupplyLists
.Include(s => s.Category).FirstOrDefaultAsync(m => m.Id == id);
if (SupplyLists == null)
{
return NotFound();
}
ViewData["CategoryId"] = new SelectList(_context.SupplyListCategory, "Id", "Category");
return Page();
}
public async Task<IActionResult> OnPostAsync()
{
//if (!ModelState.IsValid)
//{
// return Page();
//}
_context.Attach(SupplyLists).State = EntityState.Modified;
await _context.SaveChangesAsync();
if (FileUpload.UploadSupplyList != null)
{
var fileUploadData = await utilities.utilities.ProcessFormFile(FileUpload.UploadSupplyList, ModelState);
if (ModelState.ErrorCount > 0)
{
ViewData["CategoryId"] = new SelectList(_context.SupplyListCategory, "Id", "Category");
return Page();
}
var sl = _context.SupplyLists.Find(SupplyLists.Id);
sl.ListBin = fileUploadData;
await _context.SaveChangesAsync();
}
return RedirectToPage("./Index");
}
It set the ListBin to null in db which is not what I wanted when saving changes (I wanted to preserve the old value of ListBin in db).
I have this model:
public partial class Group
{
public Group()
{
this.ParameterGroup = new HashSet<ParameterGroup>();
}
public string GroupId { get; set; }
public string Responsibility { get; set; }
public virtual Text GroupDescText { get; set; }
public virtual Text GroupNameText { get; set; }
public virtual ICollection<ParameterGroup> ParameterGroup { get; set; }
}
public partial class Text
{
public Text()
{
this.ParamName = new HashSet<Parameter>();
this.ParamDesc = new HashSet<Parameter>();
this.EnumElemName = new HashSet<EnumElem>();
this.IoDeviceInfoText = new HashSet<IoDeviceInfo>();
this.IoCatText = new HashSet<IoDeviceInfo>();
this.GroupDesc = new HashSet<Group>();
this.GroupName = new HashSet<Group>();
this.Type = new HashSet<Type>();
this.ParamDispPath = new HashSet<Parameter>();
this.EnumElemText = new HashSet<EnumElem>();
this.TextValue = new HashSet<TextValue>();
}
public string TextId { get; set; }
public string XmlId { get; set; }
public virtual ICollection<Parameter> ParamName { get; set; }
public virtual ICollection<Parameter> ParamDesc { get; set; }
public virtual ICollection<EnumElem> EnumElemName { get; set; }
public virtual ICollection<IoDeviceInfo> IoDeviceInfoText { get; set; }
public virtual ICollection<IoDeviceInfo> IoCatText { get; set; }
public virtual ICollection<Group> GroupDesc { get; set; }
public virtual ICollection<Group> GroupName { get; set; }
public virtual ICollection<Type> Type { get; set; }
public virtual ICollection<Parameter> ParamDispPath { get; set; }
public virtual ICollection<EnumElem> EnumElemText { get; set; }
public virtual ICollection<TextValue> TextValue { get; set; }
}
This is my Controller:
public class GroupController : Controller
{
// GET: Group
public ActionResult Index()
{
return PartialView("Index", GroupModel.Instance.getGroups());
}
public ActionResult Edit(string id)
{
Group group = KebaContext.SessionBasedContext().GroupSet.Where(g => g.GroupId == id).FirstOrDefault();
List<Language> langs = KebaContext.SessionBasedContext().LanguageSet.ToList();
foreach(Language l in langs)
{
if(group.GroupDescText == null)
{
group.GroupDescText = new Text();
TextValue value = new TextValue();
value.TextId = Guid.NewGuid().ToString("N");
value.LangId = l.LangId;
value.Value = "";
group.GroupDescText.TextValue.Add(value);
}
if (group.GroupNameText == null)
{
group.GroupNameText = new Text();
TextValue value = new TextValue();
value.TextId = Guid.NewGuid().ToString("N");
value.LangId = l.LangId;
value.Value = "";
group.GroupNameText.TextValue.Add(value);
}
if (group.GroupDescText != null && group.GroupDescText.TextValue.Where(x => x.LangId == l.LangId).FirstOrDefault() == null) //just one lang is available
{
TextValue value = new TextValue();
value.TextId = group.GroupDescText.TextValue.First().TextId;
value.LangId = l.LangId;
value.Value = "";
group.GroupDescText.TextValue.Add(value);
}
if (group.GroupNameText != null && group.GroupNameText.TextValue.Where(x => x.LangId == l.LangId).FirstOrDefault() == null) //just one lang is available
{
TextValue value = new TextValue();
value.TextId = group.GroupNameText.TextValue.First().TextId;
value.LangId = l.LangId;
value.Value = "";
group.GroupNameText.TextValue.Add(value);
}
}
return View(group);
}
[HttpPost]
public ActionResult Edit(Group xyz)
{
return RedirectToAction("Index", "Types");
}
}
This is my View:
#using System.Web.Mvc.Html;
#model Keba.Data.EF.Group
#{
ViewBag.Title = "Group Editing";
}
<h2>Edit Group</h2>
<div id="groupEdit">
#using (Html.BeginForm("Edit", "Group", FormMethod.Post))
{
#Html.HiddenFor(model => model.GroupId);
<table class="userEditAddTable">
<tr><th>Responsibility</th><td>#Html.EditorFor(model => model.Responsibility)</td></tr>
#foreach (var name in Model.GroupNameText.TextValue)
{
#Html.HiddenFor(model => name.LangId)
#Html.HiddenFor(model => name.Value)
<tr><th>GroupNameText(#Html.DisplayFor(model => name.LangId))</th><td> #Html.TextBoxFor(model => name.Value)</td></tr>;
}
#foreach (var desc in Model.GroupDescText.TextValue)
{
#Html.HiddenFor(model => desc.LangId)
#Html.HiddenFor(model => desc.Value)
<tr><th>GroupDescText(#Html.DisplayFor(model => desc.LangId))</th><td> #Html.TextBoxFor(model => desc.Value)</td></tr>;
}
</table>
<br />
<div id="buttons">
<input name="Save" type="submit" value="Save" class="button" />
<input name="Cancel" type="submit" value="Cancel" class="button" />
</div>
}
</div>
Problem:
If I try to change the value of a Text in the group model e.g. GroupNameText.TextValue.Value send it to the controller (submit). The properties GroupNameText and GroupDescText are null.
I have also tried the solution with propertybinding ([Bind(Include = "GroupDescText,GroupNameText")] Group xyz) which also doesn't work
First, remember that only properties that are posted (i.e. have a form input element representing them) will be populated.
Second, the names of the input elements must match up to what the model binder expects on post, or it will discard the values, as it won't know what to do with them. In particular, with enumerables, this means you need to use for loops rather than foreach, so that Razor can create the right name binding:
#for (var i = 0; i < Model.GroupNameText.TextValue; i++)
{
#Html.HiddenFor(m => m.GroupNameText.TextValue[i].LangId)
#Html.HiddenFor(m => m.GroupNameText.TextValue[i].Value)
...
}
That will result in a name attribute like GroupNameText.TextValue[0].LangId, which the model binder should be able to bind appropriately, whereas your field names are currently just LangId, which is meaningless on post.
Have a look at this similar to your approach is to have a list in the view, you might need to have partials.