MVC Core DropDownList selected value ignored - asp.net-core

I am trying to access my page at: https://localhost:44319/Analyze/Index/6
The problem is that my drop down list always selects the first item in the list instead of the one provided by ID. While stepping through the debugger, before the View() is returned, I see that the SelectList was populated correctly.
AnalyzeController.cs
public IActionResult Index(int? Id)
{
return Index(Id ?? getStatementEndingById(Id).StatementEndingId);
}
[HttpPost]
public IActionResult Index(int StatementEndingId)
{
var statementEnding = getStatementEndingById(StatementEndingId);
ViewBag.StatementEndingId = new SelectList(
_context.StatementEnding.OrderByDescending(s => s.StatementEndingId),
"StatementEndingId",
"Name",
statementEnding);
return View(getPayments(statementEnding));
}
private StatementEnding getStatementEndingById(int? statementEndingId)
{
StatementEnding statementEnding;
if (statementEndingId.HasValue)
{
statementEnding = _context.StatementEnding.FirstOrDefault(s => s.StatementEndingId == statementEndingId);
}
else
{
statementEnding = _context.StatementEnding.OrderByDescending(s => s.StatementEndingId).FirstOrDefault();
}
return statementEnding;
}
Setting DropDownList in Razor
#Html.DropDownList("StatementEndingId", null, new { #class = "form-control mb-2 mr-sm-2" })
I am using ASP.NET Core 2.1.
Any suggestions are much appreciated. Thanks in advance.

First i would recomend to create a typed model, something like this one :
public class StatementViewModel
{
public int StatementEndingId { get; set; }
public List<SelectListItem> StatementEndings { get; set; }
}
Second fill the Model with all dropdown options (StatementEndings) and the selected one (StatementEndingId)
public IActionResult Index()
{
var model = new StatementViewModel();
model.StatementEndingId = getStatementEndingById(Id).StatementEndingId;
model.StatementEndings = _context.StatementEnding.OrderByDescending(s => s.StatementEndingId).Select(p => new SelectListItem() { Text = p.Name, Value = p.StatementEndingId }).ToList();
return View(model);
}
And for the last, in the view
#model StatementViewModel
#Html.DropDownListFor(m => m.StatementEndingId, Model.StatementEndings, null, new { #class = "form-control mb-2 mr-sm-2" })

Related

SelectList not returning the value of text only returns ID

I am quite new to asp net core and am trying to implement a select list while passing values from view to controller. All else is working fine only problem I am facing is only the ID is being passed to controller and not the text/name.
Can someone tell me where I am going wrong? Below is my code.
View Snippet
<div class="form-group">
<label>Financial Year</label>
<select asp-for="FinancialYear" asp-items="ViewBag.FinancialYear" class="selectpicker" data-dropup-auto="false" data-size="5">
</select>
</div>
Model Snippet
public class VMOM
{
public int FinancialYear { get; set; }
}
public class VMDropDown
{
public int ID { get; set; }
public string Text { get; set; }
}
Controller Snippet
[HttpGet]
public IActionResult Create()
{
VMOM vmOM = new VMOM();
ViewBag.FinancialYear = new SelectList(GetFinancialYearList(), "ID", "Text", 0).ToList();
return View(vmOM);
}
[HttpPost]
public IActionResult Create(VMOM vmOM)
{
return View(vmOM);
}
private List<VMDropDown> GetFinancialYearList()
{
List<VMDropDown> vmDropdowns = new List<VMDropDown>
{
new VMDropDown() { ID = 1, Text = "2019" },
new VMDropDown() { ID = 2, Text = "2020" }
};
return vmDropdowns;
}
A SS of the values received in action method; note that in Financial Year only the ID of the year is being diplayed and not the text value i.e, 2020
If you don't mind a little bit of javascript you can easily achieve what you want.
We add a hidden input field where its value is updated on the select change.
So when we submit the form, the hidden input's value will be submitted and binded with our model (See screenshot below).
Razor:
<form asp-action="Post" method="post">
<select class="form-control" asp-items="#ViewBag.List" asp-for="#Model.Id" id="FYear">
</select>
<input type="hidden" id="FYearText" asp-for="#Model.Year" readonly="readonly" hidden/>
<button type="submit" class="btn btn-success">Submit</button>
</form>
Model
public class VMOM
{
public int Id { get; set; }
public string Year { get; set; }
}
Controller:
[HttpGet]
public IActionResult Index()
{
var data = new List<VMOM> {
new VMOM { Id = 1, Year = "2018" },
new VMOM { Id = 2, Year = "2019" },
new VMOM { Id = 3, Year = "2020" },
new VMOM { Id = 4, Year = "2077" }
};
ViewBag.List = new SelectList(data, "Id", "Year");
return View("Index", new VMOM());
}
JS
$(document).ready(function(){
$("#FYear").on("change", function(){
$("#FYearText").val($(this).find("option:selected").text());
});
});
Result:
P.S, I am using jQuery in this example for brevity.
The simplest way is changing the ID value the same as the Text.
List<VMDropDown> vmDropdowns = new List<VMDropDown>
{
new VMDropDown() { ID = 2019, Text = "2019" },
new VMDropDown() { ID = 2020, Text = "2020" }
};

Asp.net MVC Core giving null checkbox data instead of all selected checkboxes on HTTPPost

I am trying to bind list of checkboxes.On Post Model showng the value of Job_Type as 0 .It should return all selected checkboxes.Which in my case not doing so .After hours of searching I havn't found any solution.
This is the relevent part of code in my view
<div class="form-group">
#foreach (var item in Model.Job_Type)
{
<input name="Job_Type" value="#item.valID" type="checkbox" checked="#item.IsChecked"/>
#item.text <br/>
}
</div>
My Controller:
// GET: Jobs/Create
public IActionResult Create()
{
NewJob newJob = new NewJob();
List<CheckBoxModel> chkVisatype = new List<CheckBoxModel>()
{
new CheckBoxModel {valID=1, text="ASp",IsChecked=true },
new CheckBoxModel {valID=1,text="ss",IsChecked=true },
new CheckBoxModel {valID=1,text="aa",IsChecked=true },
new CheckBoxModel {valID=1,text="dd",IsChecked=true },
};
List<CheckBoxModel> chkJobtype = new List<CheckBoxModel>()
{
new CheckBoxModel {valID=1,text="ASp",IsChecked=true },
new CheckBoxModel {valID=1,text="tt",IsChecked=true },
new CheckBoxModel {valID=1,text="ss",IsChecked=true },
new CheckBoxModel {valID=1,text="aa",IsChecked=true },
};
newJob.Job_Type = chkJobtype;
newJob.Visa_Type = chkVisatype;
return View(newJob);
}
// POST: Jobs/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("JobID,Job_Title,AddedDate,Primary_Technology,MPTJob_Length,MPTJobLengthSelection,SPTJob_Length,SPTJobLengthSelection,Job_Length,JobLengthSelection,Secondary_Technology,Description,PossibiltyForExtenshion,Email,CC_Email,URL,City,State,Country,ZipCode,Employment_Type,Job_Type,Compensation,JobExperienceLevel,Visa_Type")] NewJob newJob)
{
if (ModelState.IsValid)
{
newJob.AddedDate = DateTime.Now;
_context.Add(newJob);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(newJob);
}
My Model:
public class CheckBoxModel
{
[Key]
public int valID { get; set; }
public string text { get; set; }
public bool IsChecked { get; set; }
}
public class NewJob
{
public List<CheckBoxModel> Job_Type { get; set; }
}
If you check the request in browser Network tab, you would find only valID of checked options are sent via form data, like below. So Job_Type property is not successfully bound, which cause the issue.
If possible, you can dynamically generate expected data based on checked options, and then submit the data using jQuery AJAX etc.
In View page
#foreach (var item in Model.Job_Type)
{
<input name="Job_Type" value="#item.valID" type="checkbox" checked="#item.IsChecked" />
<span>#item.text</span>
<br />
}
Make ajax request
function myCreateFunc() {
var job_title = $('input[name="Job_Title"]').val();
var job_type = [];
$('input[name="Job_Type"]:checked').each(function (i,el) {
job_type.push({ "valID": $(el).val(), "text": $(el).next("span").text(), "IsChecked": true });
});
var job_data = { "Job_Title": job_title, "Job_Type": job_type };
$.ajax({
url: "/Home/Create",
type: 'POST',
contentType: "application/json; charset=utf-8",
data: JSON.stringify(job_data),
success: function (response) {
//code logic here
}
});
}
In controller action (with [FromBody] attribute)
[HttpPost]
public IActionResult Create([FromBody][Bind("JobID, Job_Title, Job_Type")]NewJob newJob) //in my testing sample, only define JobID, Job_Title, Job_Type properties
Test Result
Well I tired this and it works for me.
All we need to understand how checkboxes post their data. if they have a name attribute, when checked, they post name=value.If you want to get complete list posted back it would be:
#for (int i = 0; i < Model.Job_Type.Count(); i++)
{
<input hidden asp-for="Job_Type[i].valID" />
<input hidden asp-for="Job_Type[i].text" />
<input asp-for="Job_Type[i].IsChecked" type="checkbox" />
#Model.Job_Type[i].text<br />
}

MVC4 model changes not showing

I know what you're thinking, but hear me out.
I have a model:
public partial class DealerBudget
{
public int DealerBudgetID { get; set; }
public int DealerID { get; set; }
public int BudgetYr { get; set; }
public int BudgetMonth { get; set; }
public decimal BudgetAmt { get; set; }
public bool Confirmed { get; set; }
public short BudgetTypeID { get; set; }
}
A list of these is in a vm:
public class DealerBudgetVM
{
public List<CNHi.StMarys.ND.DBP.Web.Models.DealerBudget> YrBudget { get; set; }
}
They're filled in a Get:
public ActionResult Add()
{
DealerBudgetVM result = new DealerBudgetVM(); //initialised to have all 24 months
List<DealerBudget> dbList = db.DealerBudgets.Where(x => x.DealerID == dbp.dealerID && x.BudgetTypeID == (short)2 && (x.BudgetYr == DateTime.Now.Year || x.BudgetYr == DateTime.Now.Year + 1)).ToList();
//use the data from the DB if it exists
foreach (DealerBudget bud in result.YrBudget)
{
foreach (DealerBudget budDB in dbList)
{
bud.DealerID = dbp.dealerID;
bud.BudgetTypeID = 2; //Service
if (budDB.BudgetYr == bud.BudgetYr && budDB.BudgetMonth == bud.BudgetMonth)
{
bud.DealerBudgetID = budDB.DealerBudgetID;
bud.BudgetAmt = budDB.BudgetAmt;
bud.Confirmed = budDB.Confirmed;
}
}
}
return PartialView(result);
}
And displayed in a view. If each month's value is Confirmed, the textbox is disabled:
#for( int i = 0; i < 12; ++i)
{
#Html.HiddenFor(model => model.YrBudget[i].DealerBudgetID)
#Html.HiddenFor(model => model.YrBudget[i].BudgetTypeID)
#Html.HiddenFor(model => model.YrBudget[i].DealerID)
#Html.HiddenFor(model => model.YrBudget[i].BudgetYr)
#Html.HiddenFor(model => model.YrBudget[i].BudgetMonth)
#Html.HiddenFor(model => model.YrBudget[i].Confirmed)
<div class="pure-u-1-3 pure-u-md-1-6 pure-u-lg-1-12 s-box">
<span class="pure-u-1">#Html.DisplayFor(model => model.YrBudget[i].MonthDesc)</span>
#Html.TextBoxFor(model => model.YrBudget[i].BudgetAmt, (Model.YrBudget[i].Confirmed == false) ? (object)new {type="number", Value=Model.YrBudget[i].BudgetAmt.ToString("0.00")} : (object)new {disabled = "disabled", Value=Model.YrBudget[i].BudgetAmt.ToString("0.00")} )
</div>
}
The user enters new budget figures and saves:
[HttpPost]
public ActionResult Added(DealerBudgetVM vm)
{
if (ModelState.IsValid)
{
this.ModelState.Clear();
foreach (DealerBudget budVM in vm.YrBudget.Where(x => x.Confirmed == false && x.BudgetAmt > 0).ToList())
{
//If it's not in the DB, add it.
if (budVM.DealerBudgetID == 0)
{
DealerBudget budNew = new DealerBudget { BudgetYr = budVM.BudgetYr, DealerID = budVM.DealerID, BudgetMonth = budVM.BudgetMonth, BudgetTypeID = budVM.BudgetTypeID, BudgetAmt = budVM.BudgetAmt };
if (budNew.BudgetAmt > 0)
{
budNew.Confirmed = true;
budVM.Confirmed = true;
}
db.DealerBudgets.Add(budNew);
db.SaveChanges();
budVM.DealerBudgetID = budNew.DealerBudgetID;
}
else
{
//update and confirm
DealerBudget budDB = db.DealerBudgets.Where(x => x.DealerBudgetID == budVM.DealerBudgetID).FirstOrDefault();
if (budDB == null)
{
}
else
{
budDB.BudgetAmt = budVM.BudgetAmt;
budDB.Confirmed = true;
db.SaveChanges();
budVM.Confirmed = true;
}
}
}
return RedirectToAction("Index", "ServicePerformance");
}
else
{
return PartialView(vm);
}
}
...and nothing changes on the view. The new (confirmed) budget textboxes should be disabled, and they aren't.
"No problem!" you say. "this guy just needs to..."
Use ModelState.Clear(). Tried it, didn't work.
Remove keys from the ModelState. Tried it, didn't work.
Use Post-Redirect-Get. Tried it(both redirecting to the partial and to the master. Current code above still using it). Didn't work.
Clear the cache. Tried many, many methods and iterations. Nothing worked.
After the Post and save, the subsequent Get has all the correct saved values being sent to the View in the VM, but the old ones (ie user-entered values with confirmed flag=false) are still shown.
If the user then goes to another page and then returns, the page displays as expected.
All the posts I've seen here (and elsewhere) confidently declare that one of the four solutions above will fix it. I've wasted a day now banging my head against a wall trying to disable a stupid textbox.
Any other ideas? Is it because of nesting or partial views or something?

ASP.Net MVC - cannot set value of #Html.Checkbox after changing dropdownlist

I've looking all over for something similar, couldn't find nothing..
I'm using ASP.NET MVC 4. I'm building a page so the users in my app can manage the permissions associated with each role.
So i have a view with #htmlDropDownList to show all the available roles, and below, one #Html.CheckBox for each Permission of the role wich is selected above.
The first time the view is rendered, the checkboxes are all set to true or false, according to the permission of that role.All is fine, life is good :) . When the value of the drop is changed, i post the SelectedRoleId using $.ajax. Then, i fetch all the permissions of the new selected role.
While in debug, in the razor view, i can confirm the new values (true or false) inside the model are correct. The problem is that the checkboxes show the old values, before the role was changed..
This is my first question asked, so i'll have to apologize if the question is not being made the best way.
And thx in advance to all of you :)
So here's my Controller:
public ActionResult Index(int ? SelectedRoleId)
{
ManagePermissionsViewModel model = new ManagePermissionsViewModel();
if (SelectedRoleId == null)
{
model.SelectedRoleID = 1; // value 1 is the supervisor Role
}
else
{
model.SelectedRoleID = SelectedRoleId;
}
//values for the dropdownlist of Roles
var items = from x in db.UserRoles
select x;
model.RoleList = new SelectList(items, "Id", "DESCRIPTION");
//gets all the permissions of the selected role
model.EntirePermissionList = (from k in db.Permissions
select new Permission
{
IdPermission = k.Id,
PermissionDescription = k.Description,
IsSet = db.RolePermissions.Any(n => n.RoleId == model.SelectedRoleID && n.PermissionId == k.Id),
PermissionGroupId = (int)k.PermissionGroupId
}).ToList();
//Gets all the groups of Permissions
model.ListPermissionGroups = (from l in db.PermissionGroups
select new PermissionGroup
{
Id = l.Id,
Description = l.Description
}).ToList();
return View(model);
}
[HttpPost]
public ActionResult Index(FormCollection form) {
switch (form["SubmitButton"])
{
case "Save":
SavePermissions();
break;
default:
return RedirectToAction("Index", new RouteValueDictionary(new { controller = "ManagePermissions", action = "Index", SelectedRoleId = Convert.ToInt32(form["SelectedRoleId"]) }));
}
return View();
}
And here is my View:
'#model AML.Web.Models.ManagePermissionsViewModel
#using (Html.BeginForm("Index", "ManagePermissions", FormMethod.Post, new { id = "MyForm" }))
{
#Html.Label("Role :", htmlAttributes: new { #class = "control-label col-md-2" })
#Html.DropDownList("RoleId", Model.RoleList, new { id = "RoleId" })
<div>
#foreach (var item in Model.ListPermissionGroups)
{
<h3> #item.Description</h3>
foreach (var permission in Model.EntirePermissionList.Where(n => n.PermissionGroupId == item.Id))
{
<h5>
#permission.PermissionDescription
#Html.CheckBox("Chk_Permisssion", permission.IsSet)
</h5>
}
}
</div>
<input type="submit" value="Save" name="SubmitButton" class="btn btn-default" />
}
#section Scripts {
<script type="text/JavaScript">
$(document).ready(function () {
$("#RoleId").change(function (e) {
e.preventDefault();
$.ajax({
url: "/ManagePermissions/Index",
cache: false,
type: "POST",
data: { 'SelectedRoleId': $(this).val() },
dataType: "json",
success: function (result) { console.log("Sucess!"); },
error: function (error) { console.log("Error!"); }
})
});
});
</script>
}
And my viewModel:
public class ManagePermissionsViewModel
{
public int? SelectedRoleID { get; set; }
public string SelectedRoleDescription { get; set; }
public SelectList RoleList { get; set; }
public List<Permission> EntirePermissionList { get; set; }
public List<PermissionGroup> ListPermissionGroups { get; set; }
}
public class Permission
{
public int IdPermission { get; set; }
public bool IsSet { get; set; }
public string PermissionDescription { get; set; }
public int PermissionGroupId { get; set; }
}
public class PermissionGroup {
public int Id { get; set; }
public string Description{ get; set; }
}
UPDATE 1 -
Well, i think i got it. Let me post my approach
In the View:
#Html.DropDownListFor(n => n.SelectedRoleID, Model.RoleList,null,
new { onchange = "document.location.href = '/ManagePermissions/Index?SelectedRoleId=' + this.options[this.selectedIndex].value;" })
<div>
#foreach (var item in Model.ListPermissionGroups)
{
<h3> #item.Description</h3>
foreach (var permission in Model.EntirePermissionList.Where(n => n.PermissionGroupId == item.Id))
{
<h5>
#permission.PermissionDescription
<input type="checkbox" id="#permission.IdPermission" checked="#permission.IsSet">
</h5>
}
}
</div>
And in the Controller:
public ActionResult Index(int? SelectedRoleId)
{
ManagePermissionsViewModel model = new ManagePermissionsViewModel();
ModelState.Clear();
if (SelectedRoleId == null)
{
model.SelectedRoleID = 1;
}
else
{
model.SelectedRoleID = SelectedRoleId;
}
var items = from x in db.UserRoles
select x;
model.RoleList = new SelectList(items, "Id", "DESCRIPTION");
model.EntirePermissionList = (from k in db.Permissions
select new Permission
{
IdPermission = k.Id,
PermissionDescription = k.Description,
IsSet = db.RolePermissions.Any(n => n.RoleId == model.SelectedRoleID && n.PermissionId == k.Id),
PermissionGroupId = (int)k.PermissionGroupId
}).ToList();
model.ListPermissionGroups = (from l in db.PermissionGroups
select new PermissionGroup
{
Id = l.Id,
Description = l.Description
}).ToList();
ModelState.Clear();
return View(model);
}
Now each time the Drop changes value, the permissions in the checkboxes are updated. I got it to work with the attribute on the drop, "on change = Document.location.hef = URL". Is this a good approach? Or should i use something like ajax request ?
UPDATE 2
The Controller:
public async Task<ActionResult> Index(int? SelectedRoleId)
{
if (SelectedRoleId == null)
{
SelectedRoleId = 1;
}
var model = await GetSelectedPermissions(SelectedRoleId);
return this.View("Index",model);
}
[HttpGet]
public async Task<ActionResult> GetPermissions(string Id)
{
var SelectedRoleId = int.Parse(Id);
var model = await this.GetSelectedPermissions(SelectedRoleId);
return PartialView("_ManagePermissions", model);
}
private async Task<ManagePermissionsViewModel> GetSelectedPermissions(int? SelectedRoleId)
{
ModelState.Clear();
ManagePermissionsViewModel model = new ManagePermissionsViewModel();
model.SelectedRoleID = SelectedRoleId;
var items = from x in db.UserRoles
select x;
model.RoleList = new SelectList(items, "Id", "DESCRIPTION");
model.EntirePermissionList = await (from k in db.Permissions
select new Permission
{
IdPermission = k.Id,
PermissionDescription = k.Description,
IsSet = db.RolePermissions.Any(n => n.RoleId == model.SelectedRoleID && n.PermissionId == k.Id),
PermissionGroupId = (int)k.PermissionGroupId
}).ToListAsync();
model.ListPermissionGroups = await (from l in db.PermissionGroups
select new PermissionGroup
{
Id = l.Id,
Description = l.Description
}).ToListAsync();
return model;
}
The View
<h2>Permissions - Ajax with Partial View</h2>
#using (Html.BeginForm("SaveData", "ManagePermissions", FormMethod.Post, new { id = "MyForm" }))
{
#Html.Label("Role :", htmlAttributes: new { #class = "control-label col-md-2" })
#Html.DropDownListFor(n => n.SelectedRoleID, Model.RoleList, null, null)
<div id="target">
#Html.Partial("~/Views/Shared/_ManagePermissions.cshtml", Model)
</div>
<input type="submit" value="Save" name="SubmitButton" class="btn btn-default" />
}
#section Scripts {
<script type="text/javascript">
$(document).ready(function () {
$("#SelectedRoleID").change(function () {
var SelectedRoleID = $("#SelectedRoleID").val();
$("#target").load('#(Url.Action("GetPermissions","ManagePermissions",null, Request.Url.Scheme))?Id=' + SelectedRoleID);
});
});
</script>
}
And the Partial View:
<div>
#foreach (var item in Model.ListPermissionGroups)
{
<h3> #item.Description</h3>
foreach (var permission in Model.EntirePermissionList.Where(n => n.PermissionGroupId == item.Id))
{
<h5>
#permission.PermissionDescription
<input type="checkbox" id="#permission.IdPermission" checked="#permission.IsSet">
</h5>
}
}
</div>

MVC 4 multiple buttons in form - why isn't this code working

I am trying to use a variation of the code from this page:
Multiple button in MVC
But everytime I click on the buttons it goes to the index actionresult method and not one of the button methods. Index is the view name but the button clicks are happening in a partial view called "P_NewPersonForm.cshtml"
P_NewPersonForm.cshtml
#using (Html.BeginForm())
{
<div id="divClaimType">
#Html.Label("Claim type:")
#Html.DropDownListFor(m => m.modelClaim.ClaimType, new List<SelectListItem>
{
new SelectListItem{ Text="Legal", Value = "Legal" },
new SelectListItem{ Text="Immigration", Value = "Immigration" },
new SelectListItem{ Text="Housing", Value = "Housing" }
})
</div>
<div id="divClaimStatus" style="padding: 5px;">
#foreach(var item in Model.LinkerStatusOfClaim)
{
#Html.Label("Claim status:")
#Html.DropDownListFor(m => m.LinkerStatusOfClaim[0].ClaimStatusID, new SelectList(Model.modelClaimStatus, "ClaimStatusID", "ClaimStatus"))
#Html.LabelFor(m => m.LinkerStatusOfClaim[0].Notes)
#Html.TextAreaFor(m => m.LinkerStatusOfClaim[0].Notes)
#Html.LabelFor(m => m.LinkerStatusOfClaim[0].StartDate)
#Html.TextBoxFor(m => m.LinkerStatusOfClaim[0].StartDate, new { #id = "datepicker", #Value = DateTime.Now, #readonly = true, Style = "background:#cccccc;" })
<br />
#Html.ValidationMessageFor(model => model.LinkerStatusOfClaim[0].StartDate)
<br />
}
<input type="submit" value="Add another status to this claim..." name="action:add"/>
<input type="submit" value="Delete status." name="action:remove"/>
#* #Ajax.ActionLink("Add another status to this claim...", "AddClaim", "Client", new AjaxOptions { HttpMethod = "POST"})*#
</div>
}
</div>
I have one button for adding to the collection of claims and another to remove one from the collection.
ClientController
public ActionResult Index()
{
var Model = new modelPersonClaim();
// Add one item to model collection by default
LinkerStatusOfClaim LinkerStatusOfClaim = new LinkerStatusOfClaim();
Model.LinkerStatusOfClaim.Add(LinkerStatusOfClaim);
DataLayer.RepositoryClient RC = new RepositoryClient();
Model.isValidModel = true;
RC.GetClaimTypes(Model, PersonTypes.NewPerson.ToString());
return View(Model);
}
[HttpPost]
public ActionResult P_NewPersonForm(modelPersonClaim Model)
{
DataLayer.RepositoryClient RC = new RepositoryClient();
RC.GetClaimTypes(Model, PersonTypes.NewPerson.ToString());
Model.isValidModel = ModelState.IsValid;
if (ModelState.IsValid)
{
RC.CreatePerson(Model);
Model.SuccessfulInsert = true;
Model.InsertString = "Person data has been successfully inserted into the database.";
if (Model.modelClaim.ClaimMade)
{
RC.CreateClaim(Model);
}
}
else
{
Model.SuccessfulInsert = false;
Model.InsertString = "Person data could not be inserted into the database. Missing key fields.";
}
return View("Index", Model);
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple=false, Inherited = true)]
public class MultiButtonAttribute : ActionNameSelectorAttribute
{
public string Name { get; set; }
public string Argument { get; set; }
public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
{
var isValidName = false;
var keyValue = string.Format("{0}:{1}", Name, Argument);
var value = controllerContext.Controller.ValueProvider.GetValue(keyValue);
if (value != null)
{
controllerContext.Controller.ControllerContext.RouteData.Values[Name] = Argument;
isValidName = true;
}
return isValidName;
}
}
[HttpPost]
[MultiButtonAttribute(Name = "action", Argument = "Add another status to this claim...")]
public ActionResult AddClaimStatus(modelPersonClaim Model)
{
Model.LinkerStatusOfClaim.Insert(Model.LinkerStatusOfClaim.Count, new LinkerStatusOfClaim());
return View("Index", Model);
}
[HttpPost]
[MultiButtonAttribute(Name = "action", Argument = "Delete status.")]
public ActionResult RemoveClaimStatus(modelPersonClaim Model)
{
// Can't remove IF only 1
if (Model.LinkerStatusOfClaim.Count == 1)
{
}
else
{
Model.LinkerStatusOfClaim.RemoveAt(Model.LinkerStatusOfClaim.Count);
}
return View("Index", Model);
}
When I click one the buttons it hits the public override bool IsValidName twice. Once for each button. But then because the action name is always index, it goes to the index method and not one of the button methods.
Does anyone have any ideas how to fix this?
Something is wrong with this part:
var keyValue = string.Format("{0}:{1}", Name, Argument);
var value = controllerContext.Controller.ValueProvider.GetValue(keyValue);
Your attribute is this:
[MultiButtonAttribute(Name = "action", Argument = "Add another status to this claim...")]
So in that case keyValue will become: "action:Add another status to this claim..." while your HTML states: <input type="submit" value="Add another status to this claim..." name="action:add"/>, so I think Argument in your attribute should be add.