Load Edit view and Create view in different ViewPages in mvc - c#

I have following get method to add a form data and edit form data
Also have table call AB_Product_vs_Field in that table I have following columns
Product_ID
Field_ID
Field_Value_EN
Field_Value_AR
once I pass Product_ID and Field_ID page number it can find if there any record exist in AB_Product_vs_Field
if it has a specific record I can load relevant values
else it doesn't have a record I can load insert as a new record
[HttpGet]
public ActionResult Add_Field_Values(int? page, string Product_ID,string FieldID)
{
var pager = new PaginationModel.Pager(dummyItems.Count(), page);
ViewBag.Product_ID = Product_ID;
ViewBag.FieldID = FieldID;
//check specific row exist or not in AB_Product_vs_Field table
if ((db.AB_Product_vs_Field.Any(u => u.Product_ID == Product_ID)) & (db.AB_Product_vs_Field.Any(u => u.Field_ID == FieldID)))
{
//edit a product field values
var product_values = new ProductEdit
{
ListProductFields = db.AB_Product_vs_Field.Where((p => p.Field_ID == FieldID)).Where(p => p.Product_ID == Product_ID).ToList(),
ListProductLables = db.AB_ProductTypeCategoryField.Where(p => p.ProductFieldID == FieldID).ToList(),
Pager = pager,
};
return View("~/Views/Home/Edit_Field_Values.cshtml", product_values);
}
else
{
//add new product field values
var model = new AddNewProduct
{
ListProductFields_Add = db.AB_ProductTypeCategoryField.OrderBy(i => i.ProductFieldID).Skip((pager.CurrentPage - 1) * pager.PageSize).Take(pager.PageSize).ToList(),
Pager = pager
};
return View(model);
}
}
theses are the the models that relate to above controller
AddNewProduct model class
public class AddNewProduct
{
public string Product_ID { get; set; } }
public string Field_ID { get; set; }
public string ProductFieldNameEn { get; set; }
public string ProductFieldNameAr { get; set; }
public IList<AB_ProductTypeCategoryField> ListProductFields { get; set; }
public IEnumerable<string> Items { get; set; }
public PaginationModel.Pager Pager { get; set; }
public int PageSize { get; set; }
public int PageCount { get; set; }
public int CurrentPageIndex { get; set; }
}
this is ProductEdit model class
public class ProductEdit
{
public string Product_ID { get; set; }
public string Field_ID { get; set; }
public string ProductFieldNameEn { get; set; }
public string ProductFieldNameAr { get; set; }
public IList<AB_Product_vs_Field> ListProductFields { get; set; }
public IList<AB_ProductTypeCategoryField> ListProductLables { get; set; }
public IEnumerable<string> Items { get; set; }
public PaginationModel.Pager Pager { get; set; }
public int PageSize { get; set; }
public int PageCount { get; set; }
public int CurrentPageIndex { get; set; }
}
this is the view of Add New Product
#model project_name.Models.AddNewProduct
<h4>Add New Product</h4>
#using (Html.BeginForm("Add_Field_Values", "Home", new { Product_ID = ViewBag.Product_ID }, FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div style="visibility:hidden"> #ViewBag.Product_ID </div>
<div style="visibility:hidden"> #ViewBag.FieldID </div>
#for (int i = 0; i < Model.ListProductFields.Count; i++)
{
<div class="form-group">
#Html.LabelFor(x => x.ListProductFields[i].ProductFieldNameEn, Model.ListProductFields[i].ProductFieldNameEn, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.HiddenFor(m => m.ListProductFields[i].ProductFieldID
#Html.TextAreaFor(m => m.ListProductFields[i].Field_Value_EN, new { #class = "form-control summernote", #row = 5 })
</div>
</div>
<div class="form-group">
#Html.LabelFor(x => x.ListProductFields[i].ProductFieldNameAr, Model.ListProductFields[i].ProductFieldNameAr, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.HiddenFor(m => m.ListProductFields[i].ProductFieldID)
#Html.TextAreaFor(m => m.ListProductFields[i].Field_Value_AR, new { #class = "form-control summernote", #row = 5 })
</div>
</div>
<!-- pagination section -->
<div class="form-group">
<div class="col-md-10">
<!-- pager -->
#if (Model.Pager.EndPage > 1)
{
<ul class="pagination">
#if (Model.Pager.CurrentPage > 1)
{
<li>
First
</li>
<li>
Previous
</li>
}
#for (var page = Model.Pager.StartPage; page <= Model.Pager.EndPage; page++)
{
<li class="#(page == Model.Pager.CurrentPage ? "active" : "")">
#page
</li>
}
#if (Model.Pager.CurrentPage < Model.Pager.TotalPages)
{
<li>
Next
</li>
<li>
Last
</li>
}
</ul>
}
</div>
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save Details" class="btn btn-success" />
</div>
</div>
}
</div> }
#section scripts{}
this is Edit view of product field values
#model project_name.Models.ProductEdit
<h4>Add New Product</h4>
#using (Html.BeginForm("Add_Field_Values", "Home", new { Product_ID = ViewBag.Product_ID }, FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div style="visibility:hidden"> #ViewBag.Product_ID </div>
<div style="visibility:hidden"> #ViewBag.FieldID </div>
<div class="form-group">
#Html.LabelFor(x => x.ListProductLables[0].ProductFieldNameEn, Model.ListProductLables[0].ProductFieldNameEn, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.HiddenFor(m => m.ListProductFields[0].Field_ID)
#if (Model.ListProductFields[0].Field_ID == "F000014" | Model.ListProductFields[0].Field_ID == "F000015")
#Html.TextAreaFor(m => m.ListProductFields[0].Field_Value_EN, new { #class = "form-control summernote", #row = 5 })
</div>
</div>
<div class="form-group">
#Html.LabelFor(x => x.ListProductLables[0].ProductFieldNameAr, Model.ListProductLables[0].ProductFieldNameAr, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.HiddenFor(m => m.ListProductFields[0].Field_ID)
#Html.TextAreaFor(m => m.ListProductFields[0].Field_Value_AR, new { #class = "form-control summernote", #row = 5 })
</div>
</div>
<!-- pagination section -->
<div class="form-group">
<div class="col-md-10">
<!-- pager -->
#if (Model.Pager.EndPage > 1)
{
<ul class="pagination">
#if (Model.Pager.CurrentPage > 1)
{
<li>
First
</li>
<li>
Previous
</li>
}
#for (var page = Model.Pager.StartPage; page <= Model.Pager.EndPage; page++)
{
<li class="#(page == Model.Pager.CurrentPage ? "active" : "")">
#page
</li>
}
#if (Model.Pager.CurrentPage < Model.Pager.TotalPages)
{
<li>
Next
</li>
<li>
Last
</li>
}
</ul>
}
</div>
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save Details" class="btn btn-success" />
</div>
</div>
</div>
}
#section scripts{}
This add view supposed to add record one by one upto 15 record per one product , those values are save to AB_Product_vs_Field for first record its working. but once I click next or number 2 I'm getting following error
Index was out of range. Must be non-negative and less than the size of
the collection. Parameter name: index
error occur in this line
#Html.HiddenFor(m => m.ListProductFields[0].Field_ID)
in Add_Field_Values page

Related

Combox causing razor page not to render

I should expect to see a drop down box with items from the staff remembers table but instead my view does not render. This there for makes the page appear broken I was wondering also is their a way to get the error that caused the page not to render correclty.
#model FuelActivityTrackerDal.ViewModels.ActivityEditViewModal
<div class="container py-5">
<div class="row">
<div class="col-md-10 mx-auto">
<form>
<div class="form-group row">
<div class="col-sm-6">
<label for="inputFirstname">Activty Name</label>
#Html.TextBoxFor(model => model.Name, new { #class = "whatever-class", #cols = 10, #rows = 25 })
</div>
<div class="col-sm-3">
<label for="inputLastname">Activity Start Date</label>
</div>
</div>
<div class="form-group row">
<div class="col-sm-6">
#Html.TextAreaFor(model => model.Description, new { #class = "whatever-class", #cols = 10, #rows = 25 })
</div>
<div class="col-sm-3">
<label for="inputAddressLine2">HoursLeftOnProject </label>
<input type="text" class="form-control" id="inputAddressLine2" placeholder="HoursLeftOnProject ">
</div>
</div>
<div class="form-group row">
<div class="col-sm-6">
<label for="inputCity">Status </label>
<input type="text" class="form-control" id="inputCity" placeholder="Status ">
</div>
<div class="col-sm-3">
<label for="inputState">ActivityType </label>
<input type="text" class="form-control" id="inputState" placeholder="ActivityType ">
</div>
<div class="col-sm-3">
<label for="inputPostalCode">SOP</label>
<div class="form-group">
#Html.LabelFor(x => Model.StaffID, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-5">
<div class="form-group">
#Html.LabelFor(x => Model.StaffID, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-5">
#Html.DropDownListFor(x => Model.StaffID, new SelectList(Model.StaffMemmbers, "Value", "Text"), htmlAttributes: new { #class = "form-control", #id = "Region" })
#Html.ValidationMessageFor(x => x.StaffID, "", new { #class = "text-danger" })
</div>
</div>
</div>
</div>
</div>
</div>
<button type="button" class="btn btn-primary px-4 float-right">Save</button>
<button type="button" class="btn btn-primary px-4 float-right">Cancel</button>
</form>
</div>
</div>
</div>
However I am using the ActivityEditViewModal to populate my view.
public class ActivityEditViewModal
{
public int ActivityHeaderId { get; set; } //(int, null)
public DateTime? ActivityDate { get; set; } //(date, null)
public string Name { get; set; } //(nvarchar(350), null)
public DateTime? ActivityEndDate { get; set; } //(datetime, null)
public string Description { get; set; } //(nvarchar(max), null)
public int? ActivityLinesId { get; set; } //(int, null)
public int? HoursLeftOnProject { get; set; } //(time(7), null)
public int Status { get; set; } //(nchar(10), null)
public int ActivityType { get; set; } //(int, null)
public DateTime? CreatedDate { get; set; } //(date, null)
public string CreatedBy { get; set; } //(nvarchar(50), null)
public bool? isActive { get; set; } //(bit, null)
public bool? isDeleted { get; set; } //(bit, null)
public bool? isArchived { get; set; } //(bit, null)
public int? SOP { get; set; } //(nvarchar(50), null)
public int? DepartmentId { get; set; } //(int, null)
public string EmployeeName { get; set; } //(nvarchar(301), null)
public string StaffName { get; set; }
public int StaffID { get; set; }
public IEnumerable<SelectListItem> StaffMemmbers { get; set; }
}
In my Activity Repo I am populating the staff members are such which you can see from screen shot is working.
public List<ActivityEditViewModal> GetAllActivites()
{
var staffRepo = new StaffRepositry(_db);
List<ActivityHeader> activity = new List<ActivityHeader>();
activity = _db.ActivityHeader.AsNoTracking()
.Include(x => x.StaffMembers)
.ToList();
if (activity != null)
{
List<ActivityEditViewModal> activityDisplay = new List<ActivityEditViewModal>();
foreach (var x in activity)
{
var customerDisplay = new ActivityEditViewModal()
{
ActivityHeaderId = x.ActivityHeaderId,
ActivityDate =x.ActivityDate,
Name=x.Name,
ActivityEndDate = x.ActivityEndDate,
Description = x.Description,
StaffID =(int)x.StaffId
};
customerDisplay.StaffMemmbers = staffRepo.GetStaffs();
activityDisplay.Add(customerDisplay);
}
return activityDisplay;
}
return null;
}
public IEnumerable<SelectListItem> GetStaffs()
{
List<SelectListItem> staff = _db.Staff
.OrderBy(n => n.FirstName)
.Select(n =>
new SelectListItem
{
Value = n.StaffID.ToString(),
Text = n.FirstName + " " + n.LastName
}).ToList();
var staffip = new SelectListItem()
{
Value = null,
Text = "--- select staff ---"
};
staff.Insert(0, staffip);
return new SelectList(staff, "Value", "Text");
}
}
The result is a full broken page. When i take out the code for the dropdown it works fine.

How to add validation Rule for dynamically created multiple input in ASP.net?

Account Model Class:
[Table("Accounts")]
public class Account
{
public int Id { get; set; }
public string CompanyName { get; set; }
public float Interval { get; set; }
}
Mobile Model Class:
public class Mobile
{
public int Id { get; set; }
public string MobileNo { get; set; }
public virtual Account Account { get; set; }
public static Mobile Add(string mobile)
{
Mobile mobiles = new Mobile();
mobiles.MobileNo = mobile;
return mobiles;
}
}
Thus an account can have multiple mobile numbers. Now I create a form where multiple mobile numbers can be inserted:
#model PowerSupply.Models.CompanyAccountViewModel
#{
ViewBag.Title = "Register";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h3>Register</h3> <br />
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group row">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "col-sm-2 col-md-1 col-form-label" })
<div class="col-sm-10 col-md-3">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group row">
#Html.LabelFor(model => model.Interval, htmlAttributes: new { #class = "col-sm-2 col-md-1 col-form-label" })
<div class="col-sm-10 col-md-3">
#Html.EditorFor(model => model.Interval, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Interval, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group row">
#Html.LabelFor(model => model.Mobile, htmlAttributes: new { #class = "col-sm-2 col-md-1 col-form-label" })
<div class="col-sm-10 col-md-3">
<span class="add-new-icon glyphicon glyphicon-plus-sign" id="add_mobile"> </span>
<input name="Mobile" class="form-control" id="mobile_no" />
</div>
</div>
<div class="form-group row new_mobile_wrapper">
<div class="col-md-offset-3">
<div class="new_mobile_container">
</div>
</div>
</div>
<div class="form-group row">
<div class="col-md-offset-2 col-sm-10 col-md-2">
<input type="submit" value="Register" class="btn btn-primary col-sm-offset-1" />
</div>
</div>
}
the form look likes:
And Finally I set validation as follows:
public CompanyAccountViewModel Handle(CompanyAccountRegistrationResponseMessage message, CompanyAccountViewModel viewModel, ModelStateDictionary modelState)
{
if(!message.ValidationResult.IsValid)
{
foreach(var error in message.ValidationResult.Errors)
{
switch (error.PropertyName)
{
case "CompanyName":
modelState.AddModelError("Name",error.ErrorMessage);
break;
case "Interval":
modelState.AddModelError("Interval",error.ErrorMessage);
break;
}
}
}
return viewModel;
}
public class CompanyAccountRegistrationRequestMessageValidator : AbstractValidator<CompanyAccountRegistrationRequestMessage>
{
public CompanyAccountRegistrationRequestMessageValidator()
{
RuleFor(x=>x.CompanyName).NotEmpty().WithMessage("Please specify a Company Name");
RuleFor(x=>x.Interval).ExclusiveBetween(0,10).WithMessage("Interval value must be between 1 and 9");
}
}
This two validation Rules works perfectly. I want to apply validation to Mobile too, ie: mobile number should be unique. How can I do this?
Modification:
public class CompanyAccountViewModel
{
public string Name { get; set; }
public float Interval { get; set; }
public List<string> Mobile { get; set; }
}

Model Binding in List

I have a list inside ViewModel but when I make the Post to the Controller it's not binding it and shows an error on Parameter: null, Value: Null.
If you could help me out on this.
ViewModel:
public class OperaRateImportRuleViewModel
{
public SelectList ResortsSelectList { get; set; }
[Required]
[DisplayName("Resorts")]
public List<string> ListResort { get; set; }
public List<Rules> ExtraRuleList { get; set; }
public OperaRateImportRuleViewModel()
{
ExtraRuleList = new List<Rules>();
ListResort = new List<string>();
}
}
Controller:
public ActionResult EditRules(string id)
{
OperaRateImportRuleViewModel model = new OperaRateImportRuleViewModel();
var getRulesForResort = service.GetAllOperaRateRules().Where(x => x.ResortCode == id).ToList();
foreach (var item in getRulesForResort)
{
var ruleModel = new Rules()
{
Id = item.Id,
IsReferenceRule = item.IsReferenceRule,
PercentVariation = item.PercentVariation == null ? 0 : Decimal.Round(item.PercentVariation.Value, 2),
RateCode = item.RateCode,
ResortCode = item.ResortCode,
RoomType = item.RoomType,
SingleRoomDifference = item.SingleRoomDifference == null ? 0 : Decimal.Round(item.SingleRoomDifference.Value, 2),
SupplementValue = item.SupplementValue == null ? 0 : Decimal.Round(item.SupplementValue.Value, 2)
};
model.ExtraRuleList.Add(ruleModel);
}
return View(model);
}
[HttpPost]
public ActionResult EditRules(OperaRateImportRuleViewModel model)
{
foreach (var item in model.ExtraRuleList)
{
var rule = service.GetAllOperaRateRules().Where(x => x.Id == item.Id).FirstOrDefault();
rule.RateCode = item.RateCode;
rule.ResortCode = item.ResortCode;
rule.RoomType = item.RoomType;
rule.PercentVariation = item.PercentVariation;
rule.SupplementValue = item.SupplementValue;
rule.SingleRoomDifference = item.SingleRoomDifference;
rule.IsReferenceRule = item.IsReferenceRule;
service.Edit(rule);
}
return RedirectToAction("ManageRules");
}
And finally my View:
for (int i = 0; i < Model.ExtraRuleList.Count; i++)
{
#Html.HiddenFor(x => Model.ExtraRuleList[i].Id)
<div class="row">
<div class="col-md-2">
<div class="form-group">
#Html.TextBoxFor(x => x.ExtraRuleList[i].ResortCode, new { #class = "form-control" })
</div>
</div>
<div class="col-md-2">
<div class="form-group">
#Html.TextBoxFor(x => x.ExtraRuleList[i].ResortCode, new { #class = "form-control" })
</div>
</div>
<div class="col-md-2">
<div class="form-group">
#Html.TextBoxFor(x => x.ExtraRuleList[i].RoomType, new { #class = "form-control" })
</div>
</div>
<div class="col-md-1">
<div class="form-group">
#Html.TextBoxFor(x => x.ExtraRuleList[i].PercentVariation, new { #class = "form-control textBoxSize" })
</div>
</div>
<div class="col-md-1">
<div class="form-group">
#Html.TextBoxFor(x => x.ExtraRuleList[i].SupplementValue, new { #class = "form-control textBoxSize" })
</div>
</div>
<div class="col-md-1">
<div class="form-group">
#Html.TextBoxFor(x => x.ExtraRuleList[i].SingleRoomDifference, new { #class = "form-control textBoxSize" })
</div>
</div>
<div class="col-md-1">
<div class="form-group">
#Html.LabelFor(m => m.ExtraRuleList[i].IsReferenceRule, new { #class = "checkbox-label" })
#Html.CheckBoxFor(x => x.ExtraRuleList[i].IsReferenceRule)
</div>
</div>
<div class="col-xs-2">
<div class="form-group">
<span id="deleteSeason" title="Delete" onclick="$(this).closest('.row').remove().trigger(review());" class="glyphicon glyphicon-remove text-danger row-action"></span><span> </span>
</div>
</div>
</div>
}
<input type="submit" value="Edit" class="btn btn-primary" />
Back
Error:
Error when Binding
Much appreciated!
Thanks :)
EDIT
ViewModel Rules:
public class Rules
{
public int Id { get; set; }
[DisplayName("Rate Code")]
public string RateCode { get; set; }
[DisplayName("Resort Code")]
public string ResortCode { get; set; }
[DisplayName("Room Type")]
public string RoomType { get; set; }
[DisplayName("Percent Variation")]
public decimal? PercentVariation { get; set; }
[DisplayName("Supplement Value")]
public decimal? SupplementValue { get; set; }
[DisplayName("Single Room Difference")]
public decimal? SingleRoomDifference { get; set; }
[DisplayName("")]
public bool IsReferenceRule { get; set; }
public string HotelString { get; set; }
}
Your error is thrown because your IsReferenceRule property is decorated with [DisplayName("")]. You need to either delete it, or give it a value, for example
[DisplayName("Is Reference Rule ")]
public bool IsReferenceRule { get; set; }
but in any case, you should be using the DisplayAttribute, not the DisplayNameAttribute
[Display(Name = "Is Reference Rule ")]
Specifically, the error occurs when the public override IEnumerable<ModelValidationResult> Validate(object container) method of DataAnnotationsModelValidator is called. The offending line in the source code is context.DisplayName = Metadata.GetDisplayName(); which returns null because of the missing value in the attribute.

Display list of objects and set a value field for each input MVC

I have the following class defined as my ViewModel
public class CreateApplicationViewModel
{
public Step1ViewModel Step1 { get; set; }
public Step2StandAloneViewModel Step2StandAlone { get; set; }
public Step2ChildViewModel Step2Child { get; set; }
public Step3ViewModel Step3 { get; set; }
public Step4ViewModel Step4 { get; set; }
}
I'm trying to display items in the Step4ViewModel which consists of the following:
public class Step4ViewModel
{
public List<DataDetails> DataDetails = new List<DataDetails>();
}
public class DataDetails
{
public string GroupCode { get; set; }
public string GroupDesc { get; set; }
public decimal DetailSequence { get; set; }
public string DetailCode { get; set; }
public string DetailDesc { get; set; }
public string YesNoFlag { get; set; }
public string NumberFlag { get; set; }
public string ValueFlag { get; set; }
public string DateFlag { get; set; }
public string ListValuesFlag { get; set; }
public string CommentFlag { get; set; }
public string CalcRateFlag { get; set; }
public string ColumnSequence { get; set; }
public string TextFlag { get; set; }
public string CheckboxFlag { get; set; }
public string YesNoValue { get; set; }
public int NumberValue { get; set; }
public DateTime DateValue { get; set; }
public string ListValue { get; set; }
public string CommentValue { get; set; }
public string TextValue { get; set; }
public bool CheckboxValue { get; set; }
}
In my controller I populate the Step4ViewModel.DataDetails like so:
private Step4ViewModel GetCaseDataDetails(string caseType)
{
Step4ViewModel model = new Step4ViewModel();
List<DataDetails> data = new List<DataDetails>();
List<DataDetailsValues> values = new List<DataDetailsValues>();
var dataDetails = (from tb1 in db.DEFAULT_CASE_DATA_VW
join tb2 in db.CASE_DATA_DETAIL on tb1.CASE_DATA_GROUP_ID equals tb2.CASE_DATA_GROUP_ID
where tb1.BUS_CASE_CODE == caseType
orderby tb2.DETAIL_SEQUENCE
select new { tb1, tb2 });
foreach (var detail in dataDetails.ToList())
{
DataDetails i = new DataDetails();
DataDetailsValues j = new DataDetailsValues();
i.CalcRateFlag = detail.tb2.CALC_RATE_FLAG;
i.CheckboxFlag = detail.tb2.CHECKBOX_FLAG;
i.ColumnSequence = detail.tb2.COLUMN_SEQUENCE;
i.CommentFlag = detail.tb2.COMMENT_FLAG;
i.DateFlag = detail.tb2.DATE_FLAG;
i.DetailCode = detail.tb2.DETAIL_CODE;
i.DetailDesc = detail.tb2.DETAIL_DESC;
i.DetailSequence = detail.tb2.DETAIL_SEQUENCE;
i.GroupCode = detail.tb1.GROUP_CODE;
i.GroupDesc = detail.tb1.GROUP_DESC;
i.ListValuesFlag = detail.tb2.LIST_VALUES_FLAG;
i.NumberFlag = detail.tb2.NUMBER_FLAG;
i.TextFlag = detail.tb2.TEXT_FLAG;
i.ValueFlag = detail.tb2.VALUE_FLAG;
i.YesNoFlag = detail.tb2.YES_NO_FLAG;
data.Add(i);
}
model.DataDetails = data;
return model;
}
My thought process with the Step4ViewModel is that for every DataDetail I will display the DetailDesc as a label and then beside of it I will have an input for the NumberValue, YesOrNoValue, NumberValue, DateValue, ListValue, CommentValue, TextValue, or CheckboxValue depending on the control type and then post that data to server. I am able to successfully display each DataDetail.DetailDesc, but for each input, which also renders, the values I enter into the inputs never post back to the server. Here is what my view looks like:
#model Portal.Models.ViewModel.CreateApplicationViewModel
#{
ViewBag.Title = "Step 4/5";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using System.Linq
<h4>Case Data Details</h4>
#using (Html.BeginForm("Step4", "CreateApplication", FormMethod.Post, new { #class = "col-sm-12" }))
{
foreach (var group in Model.Step4.DataDetails.GroupBy(item => item.GroupDesc))
{
<div class="panel panel-primary">
<div class="panel-heading">#Html.Encode(group.Key)</div>
<div class="panel-body">
#for (var i = 0; i < group.Count(); i++)
{
<div class="form-group">
<div class="row">
<div class="col-xs-6">
<label class="form-label">#Model.Step4.DataDetails[i].DetailDesc</label>
</div>
<div class="col-xs-6">
#if (Model.Step4.DataDetails[i].TextFlag == "Y")
{
#Html.TextBoxFor(val => Model.Step4.DataDetails[i].TextValue, new { #class = "form-control" })
}
else if (Model.Step4.DataDetails[i].CheckboxFlag == "Y")
{
#Html.CheckBoxFor(val => Model.Step4.DataDetails[i].CheckboxValue, new { #class = "checkbox" })
}
</div>
</div>
</div>
}
</div>
</div>
}
<div class="col-sm-12">
<div class="row">
#Html.ActionLink("Cancel", "Welcome", "Home", null, new { #class = "btn btn-default" })
<button class="btn btn-default" onclick="history.go(-1);">Previous</button>
<button type="submit" class="btn btn-default">Next</button>
</div>
</div>
Controller to which post data
[HttpPost]
public ActionResult Step4(Step4ViewModel step4)
{
if (ModelState.IsValid)
{
CreateApplicationViewModel model = (CreateApplicationViewModel)Session["case"];
// model.Step4 = step4;
Session["case"] = model;
return View();
}
return View();
}
I was thinking this could be due the grouping, which I do to separate each group into a separate HTML panel element, but my inputs are rendering with the index number in the name. Any help or suggestions on a better way to accomplish this would be greatly appreciated. Cheers!
UPDATE
Here is my updated post controller and view:
#model Portal.Models.ViewModel.CreateApplicationViewModel
#{
ViewBag.Title = "Step 4/5";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using System.Linq
<h4>Case Data Details</h4>
#using (Html.BeginForm("Step4", "CreateApplication", FormMethod.Post, new { #class = "col-sm-12" }))
{
int index = 0;
foreach (var group in Model.Step4.DataDetails.GroupBy(item => item.GroupDesc))
{
<div class="panel panel-primary">
<div class="panel-heading">#Html.Encode(group.Key)</div>
<div class="panel-body">
<input type="hidden" name="Step4.DataDetails.Index" value="#index" />
#for (var i = 0; i < group.Count(); i++)
{
<div class="form-group">
<div class="row">
<div class="col-xs-6">
<label class="form-label">#Model.Step4.DataDetails[i].DetailDesc</label>
</div>
<div class="col-xs-6">
#if (Model.Step4.DataDetails[i].TextFlag == "Y")
{
#Html.TextBoxFor(val => val.Step4.DataDetails[i].TextValue, new { #class = "form-control" })
}
else if (Model.Step4.DataDetails[i].CheckboxFlag == "Y")
{
#Html.CheckBoxFor(val => val.Step4.DataDetails[i].CheckboxValue, new { #class = "checkbox" })
}
</div>
</div>
</div>
}
</div>
</div>
index++;
}
<div class="col-sm-12">
<div class="row">
#Html.ActionLink("Cancel", "Welcome", "Home", null, new { #class = "btn btn-default" })
<button class="btn btn-default" onclick="history.go(-1);">Previous</button>
<button type="submit" class="btn btn-default">Next</button>
</div>
</div>
}
[HttpPost]
public ActionResult Step4(CreateApplicationViewModel step4)
{
if (ModelState.IsValid)
{
CreateApplicationViewModel model = (CreateApplicationViewModel)Session["case"];
// model.Step4 = step4;
Session["case"] = model;
return View();
}
return View();
}
UPDATE 2
I am able to get the form input if I pass a FormCollection to the HttpPost controller. Any ideas as to why I can get these values as a FormCollection but not as the model?
You are posting list of complex objects. But MVC DefaultModelBinder can’t able to bind to your DataDetails object because Index must be in sequence when posting the form with list of complex objects. In your case due to nested for loop, this sequence is broken. So what you can do is take one separate variable and initialize with default 0 value like this - I have tried to modify your code.
#using (Html.BeginForm("Step4", "CreateApplication", FormMethod.Post, new { #class = "col-sm-12" }))
{
int index = 0;
foreach (var group in Model.Step4.DataDetails.GroupBy(item => item.GroupDesc))
{
<div class="panel panel-primary">
<div class="panel-heading">#Html.Encode(group.Key)</div>
<div class="panel-body">
<input type="hidden" name="Step4.DataDetails.Index" value="#index" />
#for (var i = 0; i < group.Count(); i++)
{
<div class="form-group">
<div class="row">
<div class="col-xs-6">
<label class="form-label">#Model.Step4.DataDetails[i].DetailDesc</label>
</div>
<div class="col-xs-6">
#if (Model.Step4.DataDetails[i].TextFlag == "Y")
{
#Html.TextBoxFor(val => val.Step4.DataDetails[i].TextValue, new { #class = "form-control" })
}
else if (Model.Step4.DataDetails[i].CheckboxFlag == "Y")
{
#Html.CheckBoxFor(val => val.Step4.DataDetails[i].CheckboxValue, new { #class = "checkbox" })
}
</div>
</div>
</div>
}
</div>
</div>
index++;
}
<div class="col-sm-12">
<div class="row">
#Html.ActionLink("Cancel", "Welcome", "Home", null, new { #class = "btn btn-default" })
<button class="btn btn-default" onclick="history.go(-1);">Previous</button>
<button type="submit" class="btn btn-default">Next</button>
</div>
</div>
}
Look at the hidden field i have added in the view. That do the trick to post your data even with the broken sequences. Hope this help you.
I was able to get the model back to the controller by taking the idea of using an index integer and incrementing it from the answer above and implementing the idea in a different way in my view:
#model Portal.Models.ViewModel.CreateApplicationViewModel
#{
ViewBag.Title = "Step 4/5";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using System.Linq
<h4>Case Data Details</h4>
#using (Html.BeginForm("Step4", "CreateApplication", FormMethod.Post, new { #class = "col-sm-12" }))
{
int index = 0;
foreach (var group in Model.Step4.DataDetails.GroupBy(item => item.GroupDesc))
{
<div class="panel panel-primary">
<div class="panel-heading">#Html.Encode(group.Key)</div>
<div class="panel-body">
#for (var i = 0; i < group.Count(); i++)
{
<div class="form-group">
<div class="row">
<div class="col-xs-6">
<label class="form-label">#Model.Step4.DataDetails[i].DetailDesc</label>
</div>
<div class="col-xs-6">
#Html.TextBoxFor(val => val.Step4.DataDetails[index].TextValue)
#Html.HiddenFor(val => val.Step4.DataDetails[index].GroupCode)
</div>
</div>
</div>
index++;
}
</div>
</div>
}
<div class="col-sm-12">
<div class="row">
#Html.ActionLink("Cancel", "Welcome", "Home", null, new { #class = "btn btn-default" })
<button class="btn btn-default" onclick="history.go(-1);">Previous</button>
<button type="submit" class="btn btn-default">Next</button>
</div>
</div>
}
The above code in the view gives me the proper index of every element and allows me to post

Values lost when sent to controller

I want to send my EmailFormModel, which contains the Ressurs-list, to the controller where i want to do stuff with it. However I'm never able to access the values in my EmailFormModel in my controller. I tried to overcome this problem by using Sessions, but still it doesnt work.
The list Ressurs contains several Ressursbehov, but there is never more than one EmailFormModel.
My controller
namespace WebApplication6.Controllers
{
public class AppController : Controller
{
const string SESSION_SAVED_MODEL = "savedModel";
[HttpGet]
public ActionResult Index()
{
Session[SESSION_SAVED_MODEL] = new EmailFormModel();
return View(Session[SESSION_SAVED_MODEL]);
}
public ActionResult Sent()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Index(EmailFormModel model)
{
//other irrelevant code
if (Request.Params["Ekstra_Ressurs"] != null)
{
model.Ressurs.Add(new RessursBehov());
Session[SESSION_SAVED_MODEL] = model;
}
}
return View(model);
}
}
My model
namespace WebApplication6.Models
{
public class EmailFormModel
{
[Required, Display(Name = "Prosjektnummer")]
public string Prosjektnummer { get; set; }
[Required, Display(Name = "Prosjektnavn")]
public string Prosjektnavn { get; set; }
[Required, Display(Name = "Prosjekttype")]
public string Prosjekttype { get; set; }
[Required, Display(Name = "Prosjektleder")]
public string Prosjektleder { get; set; }
public List<RessursBehov> Ressurs = new List<RessursBehov>()
{
new RessursBehov() };
}
public class RessursBehov
{
[Required, Display(Name = "Ressurstype")]
public string Ressurstype { get; set; }
[Required, Display(Name = "Navn på ressurs")]
public string Navn_På_Ressurs { get; set; }
[Required, Display(Name = "Ukenummer")]
public int? Ukenummer { get; set; }
[Required, Display(Name = "Antall timer")]
public int? Antall_Timer { get; set; }
[Required, Display(Name = "Antall uker")]
public int? Antall_Uker { get; set; }
}
}
}
My View
#model WebApplication6.Models.EmailFormModel
#{
ViewBag.Title = "Registrer nytt prosjekt";
List<SelectListItem> prosjektTypeListe = new List<SelectListItem>()
{
new SelectListItem { Text = "Prosjekt", Value = "Prosjekt" },
new SelectListItem { Text = "Forvaltning", Value = "Forvaltning" }
};
List<SelectListItem> ressurstypeliste = new List<SelectListItem>()
{
new SelectListItem { Text = "utvikler", Value = "utvikler" },
new SelectListItem { Text = "frontendutvikler", Value = "frontendutvikler" },
new SelectListItem { Text = "epi-utvikler", Value = "epi-utvikler" },
new SelectListItem { Text = "webnodesutvikler", Value = "webnodesutvikler" },
new SelectListItem { Text = "designer", Value = "designer" },
new SelectListItem { Text = "rådgiver", Value = "rådgiver" },
new SelectListItem { Text = "prosjektleder", Value = "prosjektleder" }
};
}
<div class="title">
<div class="text-center">
<h2>#ViewBag.Title</h2>
</div>
</div>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="rows">
<div class="row">
<div class="col-md-4"></div>
#Html.LabelFor(m => m.Prosjektnummer, new { #class = "col-md-1 text-center" })
<div class="col-md-7">
#Html.TextBoxFor(m => m.Prosjektnummer, new { #class = "html_label" })
#Html.ValidationMessageFor(m => m.Prosjektnummer)
</div>
</div>
<div class="row">
<div class="col-md-4"></div>
#Html.LabelFor(m => m.Prosjektnavn, new { #class = "col-md-1 text-center" })
<div class="col-md-7">
#Html.TextBoxFor(m => m.Prosjektnavn, new { #class = "html_label" })
#Html.ValidationMessageFor(m => m.Prosjektnavn)
</div>
</div>
<div class="row">
<div class="col-md-4"></div>
#Html.LabelFor(m => m.Prosjekttype, new { #class = "col-md-1 text-center" })
<div class="col-md-7">
#Html.DropDownListFor(m => m.Prosjekttype, prosjektTypeListe, "-- Velg Prosjekttype --", new { #class = "dropdown" })
</div>
</div>
<div class="row">
<div class="col-md-4"></div>
#Html.LabelFor(m => m.Prosjektleder, new { #class = "col-md-1 text-center" }) <!--tar inn m som parameter og returnerer m.prosjektleder-->
<div class="col-md-7">
#Html.TextBoxFor(m => m.Prosjektleder, new { #class = "html_label" })
#Html.ValidationMessageFor(m => m.Prosjektleder)
</div>
</div>
#for (var i = 0; i < Model.Ressurs.Count; i++)
{
<div class="row">
<div class="col-md-4"></div>
#Html.LabelFor(m => Model.Ressurs[i].Ressurstype, new { #class = "col-md-1 text-center" })
<div class="col-md-7">
#Html.DropDownListFor(m => Model.Ressurs[i].Ressurstype, ressurstypeliste, "-- Velg ressurstype --", new { #class = "dropdown" })
</div>
</div>
<div class="row">
<div class="col-md-3"></div>
#Html.LabelFor(m => Model.Ressurs[i].Navn_På_Ressurs, new { #class = "col-md-2 text-right" })
<div class="col-md-7">
#Html.TextBoxFor(m => Model.Ressurs[i].Navn_På_Ressurs, new { #class = "html_label" })
#Html.ValidationMessageFor(m => Model.Ressurs[i].Navn_På_Ressurs)
</div>
</div>
<div class="row">
<div class="col-md-4"></div>
#Html.LabelFor(m => Model.Ressurs[i].Ukenummer, new { #class = "col-md-1 text-center" })
<div class="col-md-7">
#Html.TextBoxFor(m => Model.Ressurs[i].Ukenummer, new { #class = "html_label" })
#Html.ValidationMessageFor(m => Model.Ressurs[i].Ukenummer)
</div>
</div>
<div class="row">
<div class="col-md-4"></div>
#Html.LabelFor(m => Model.Ressurs[i].Antall_Timer, new { #class = "col-md-1 text-center" })
<div class="col-md-7">
#Html.TextBoxFor(m => Model.Ressurs[i].Antall_Timer, new { #class = "html_label" })
#Html.ValidationMessageFor(m => Model.Ressurs[i].Antall_Timer)
</div>
</div>
<div class="row">
<div class="col-md-4"></div>
#Html.LabelFor(m => Model.Ressurs[i].Antall_Uker, new { #class = "col-md-1 text-center" })
<div class="col-md-7">
#Html.TextBoxFor(m => Model.Ressurs[i].Antall_Uker, new { #class = "html_label" })
#Html.ValidationMessageFor(m => Model.Ressurs[i].Antall_Uker)
</div>
</div>
}
<br />
<div class="row">
<div class="col-md-5"></div>
<div class="col-md-2">
<input type="submit" class="btn btn-default" value="Legg til ressurser" name="Ekstra_Ressurs" />
</div>
<div class="col-md-2">
<input type="submit" class="btn btn-primary" value="Send inn mail" name="Sendknapp" />
</div>
</div>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
In order to reach model in HttpPost Index action
1) You should pass EmailFormModel type model to View in the GET Index action method.
EmailFormModel model = new EmailFormModel();
Session[SESSION_SAVED_MODEL]=model;
return View(model);
2) You should use Model at the lambda expressions
#Html.TextBoxFor(m => Model.Prosjektleder, new { #class = "html_label" })
change all ms with Model.
All you have to do is add #Name in html attribute then you wont need to use session also .
#Html.DropDownListFor(m => m.Prosjekttype, prosjektTypeListe , "-- Velg Prosjekttype --", new { #class = "dropdown" , #Name = "Prosjekttype" })

Categories