Model binding with multiple rows in ASP.NET Core MVC - asp.net-core

I've been stuck on this for so long, any help or direction is appreciated.
Basically I want my controller to pass a json data like this:
Initially, I wanted to do it with model binding, but at this moment even jQuery will be fine.
Model class:
public class Orders
{
public int Id { get; set; }
public int CustomerId { get; set; }
public string ItemName { get; set; }
public double Price { get; set; }
public IEnumerable<SelectListItem> CustomersList { get; set; }
}
Controller code:
// GET: OrdersController/Create
public ActionResult Create()
{
var listCustomers = dbContext.Customers
.Select(x => new SelectListItem
{
Value = x.Id.ToString(),
Text = x.DepName
});
var orders = new Orders()
{
CustomersList = listCustomers
};
//var orders = new List<Orders>();
return View(orders);
}
// POST: OrdersController/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(List<Orders> ordersList)
{
Orders newOrders = new Orders();
foreach (var order in ordersList)
{
newOrders.Id = 0;
newOrders.CustomerId = order.CustomerId;
newOrders.ItemName = order.ItemName;
newOrders.Price = order.Price;
}
// I will be processing newOrders into application/json and sending to the backend API
}
View markup:
#model List<NameSpace.Web.Models.Orders>
#{
ViewData["Title"] = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="row">
<div class="col-md-8">
<div class="form-group">
#Html.LabelFor(model => model.CustomerId, htmlAttributes: new { #class = "control-label col-md-6" })
#Html.DropDownListFor(model => model.CustomerId, Model.CustomersList, "Select Customer ", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.DepId, "", new { #class = "text-danger" })
</div>
</div>
<hr>
<div class="col-md-12">
<div class=''></div>
<thead>
<tr>
//<th style="width:150px">Cust. Id</th>
<th style="width:150px">Item Name</th>
<th style="width:150px">Price</th>
</tr>
</thead>
<tbody id="tblOrdersBody">
<tr>
//<td><input name='Orders[0].CustomerId' class="form-control" /></td>
<td><input name='Orders[0].ItemName' class="form-control" /></td>
<td><input name='Orders[0].Price' class="form-control" /></td>
</tr>
</tbody>
<tfooter>
<tr><a hre="#" class="btn btn-success" id="addOrder"></a> </tr>
</tfooter>
</table>
<div class="row">
<div class="tile-footer d-flex justify-content-around">
#Html.ActionLink("Cancel", "Index", null, new { #class = "btn btn-danger" })
<input id="btnSave" type="submit" value="Save Order" class="btn btn-primary" />
</div>
</div>
</div>
</div>
}
#section Scripts {
<script>
var i = 1;
$(document).on("click", "#addOrder", function () {
$("#tblOrdersBody").append("<tr>"
//+ "<td><input name='Orders[" + i + "].CustomerId' class='form-control' /></td>"
+ "<td><input name='Orders[" + i + "].ItemName' class='form-control'/></td>"
+ "<td><input name='Orders[" + i + "].Price' class='form-control'/></td>"
+ "<td><button type='button' class='btn btn-danger' id='btnRemove' </buuton></td>"
+ "</tr > ");
i++;
});
</script>
}
I have seen many similar questions , the closest one being this one, but I could figure it out, the controller receives 0 in item counts

public ActionResult Create(List ordersList)
You action parameter named ordersList, please try to modify the name attribute of your input(s) on view page, like below.
<tbody id="tblOrdersBody">
<tr>
<td><input name='ordersList[0].CustomerId' class="form-control" /></td>
<td><input name='ordersList[0].ItemName' class="form-control" /></td>
<td><input name='ordersList[0].Price' class="form-control" /></td>
</tr>
</tbody>
JS code
<script>
var i = 1;
$(document).on("click", "#addOrder", function () {
$("#tblOrdersBody").append("<tr>"
+ "<td><input name='ordersList[" + i + "].CustomerId' class='form-control' /></td>"
+ "<td><input name='ordersList[" + i + "].ItemName' class='form-control'/></td>"
+ "<td><input name='ordersList[" + i + "].Price' class='form-control'/></td>"
+ "<td><button type='button' class='btn btn-danger' id='btnRemove' </buuton></td>"
+ "</tr > ");
i++;
});
</script>
Test Result

Related

IList returning count=0 on posting back updated checkboxes

I'm using asp.net-core with razor pages. I'm trying to update the checkboxes in the table.
When clicking on button save I pass with asp-route-for because I want to know how many items are in the list But my IList usersAccessRights is returning count = 0 and skips my foreach in update function. Is there other way to receive how many items and update the table checkboxes?
cshtml.cs:
public IActionResult OnPost(int id, string groupAccessName, bool chkDefaultGroup, IList<OutputAccessRights> usersAccessRights, string returnUrl = null){
Update(Convert.ToInt16(groupAccessID),usersAccessRights);
return RedirectToAction("Group AccessDetails", "Form", new { id = GroupAccessID, searchString = SearchString, searchInt = SearchInt }).WithSuccess("Success!", "Updated item!");
}
private void Update(short GroupAccessID, IList<OutputAccessRights> usersAccessRights)
{ Security Security = new Security();
IDataReader dr;
byte MainMenuId = 0;
byte SubMenuId = 0;
string Operation = "";
string OperationId = "";
foreach (var item in usersAccessRights)
{
MainMenuId = Convert.ToByte(item.MainMenuID);
SubMenuId = Convert.ToByte(item.SubMenuID);
//*** Add
OperationId = "A";
if (item.ChkAddRight == true)
Operation = "ADD";
else
Operation = "REMOVE";
Security.GroupAccessRightsMaintain(BellaMain.GlobalVariable.SystemID, Convert.ToInt16(GroupAccessID), MainMenuId, SubMenuId, OperationId, Operation);
//*** Delete
cshtml - button save:
<div class="col-sm-4">
#if (Model.Details != true)
{
<button type="submit" class="btn btn-primary" asp-page="Group AccessDetails" asp-route-usersAccessRights="#Model.UsersAccessRights">#Localizer["Save"]</button>
}
<a asp-page="Group Access" asp-route-searchString="#Model.SearchString" asp-route-searchInt="#Model.SearchInt">#Localizer["Back to Group"]</a>
</div>
cshtml-table UsersAccessRights:
#if (Model.UsersAccessRights != null)
{<table class="table table-striped table-bordered dataTable tableAccessRights" id="tableAccessRights" style="width:100%">
<thead>
<tr>
<th>
MainMenu
</th>
<th>
SubMenu
</th>
<th>
Operation
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.UsersAccessRights){ <tr>
<td>
#if (Model.GroupAccessID == 0)
{
<input type="checkbox" class="form-check-inline" name="#item.ChkUserAccessRights" id="chkUserAccessRights" asp-for="#item.ChkUserAccessRights"/>
#Html.DisplayFor(modelItem => item.MainMenuDescription)
}
else
{
#if (Model.Details != true)
{
<input type="checkbox" class="form-check-inline" name="#item.ChkUserAccessRights" id="chkUserAccessRights" asp-for="#item.ChkUserAccessRights"/>
#Html.DisplayFor(modelItem => item.MainMenuDescription)
<span class="text-danger"></span>
}
else
{
<input type="checkbox" class="form-check-inline" name="#item.ChkUserAccessRights" id="chkUserAccessRights" disabled readonly="readonly" />
#Html.DisplayFor(modelItem => item.MainMenuDescription)
}
}
</td>
<td>
#Html.DisplayFor(modelItem => item.SubMenuDescription)
</td>
<td>
#if (Model.GroupAccessID == 0)
{
<input type="checkbox" class="form-check-inline" name="#item.ChkAddRight" id="chkAddRight" asp-for="#item.ChkAddRight"/>
<label for="chkAddRight">Insert</label>
}
else
{
#if (Model.Details != true)
{
<input type="checkbox" class="form-check-inline" name="#item.ChkAddRight" id="chkAddRight" asp-for="#item.ChkAddRight"/>
<label for="chkAddRight">Insert</label>
<span class="text-danger"></span>
}
else
{
<input type="checkbox" class="form-check-inline" name="#item.ChkAddRight" id="chkAddRight" disabled readonly="readonly" asp-for="#item.ChkAddRight"/>
<label for="chkAddRight">Insert</label>
}
}
}
Here is a simple demo like below:
1.Model:
public class OutputAccessRights
{
public int Id { get; set; }
public bool ChkUserAccessRights { get; set; }
public string SubMenuDescription { get; set; }
public string MainMenuDescription { get; set; }
public bool ChkAddRight { get; set; }
}
2.Edit.cshtml:
<form method="post">
<table class="table table-striped table-bordered dataTable tableAccessRights" id="tableAccessRights" style="width:100%">
<thead>
<tr>
<th>
MainMenu
</th>
<th>
SubMenu
</th>
<th>
Operation
</th>
</tr>
</thead>
<tbody>
#for (var i = 0; i < Model.UsersAccessRights.Count(); i++)
{
<tr>
<td>
<input class="form-check-inline"asp-for="UsersAccessRights[i].ChkUserAccessRights" />
#Model.UsersAccessRights[i].MainMenuDescription
</td>
<td>
#Model.UsersAccessRights[i].SubMenuDescription
</td>
<td>
<input class="form-check-inline" asp-for="UsersAccessRights[i].ChkAddRight" />
<label for="chkAddRight">Insert</label>
</td>
</tr>
}
</tbody>
</table>
<button type="submit" class="btn btn-primary" >Save</button>
</form>
3.Edit.cshtml.cs:
public class EditModel : PageModel
{
private readonly RazorContext _context;
public EditModel(RazorContext context)
{
_context = context;
}
[BindProperty]
public IList<OutputAccessRights> UsersAccessRights { get; set; }
public async Task<IActionResult> OnGetAsync()
{
UsersAccessRights = await _context.OutputAccessRights.ToListAsync();
if (UsersAccessRights == null)
{
return NotFound();
}
return Page();
}
public async Task<IActionResult> OnPostAsync(IList<OutputAccessRights> usersAccessRights)
{
//do your stuff...
}
}
4.Result:

Razor Engine Issue in MVC4

When I declare a text box in view page the below error will appear
The type arguments for method 'System.Web.Mvc.Html.InputExtensions.TextBoxFor<TModel,TProperty>(System.Web.Mvc.HtmlHelper<TModel>,
System.Linq.Expressions.Expression<System.Func<TModel,TProperty>>)'
cannot be inferred from the usage. Try specifying the type arguments
explicitly
even I included
<compilation debug="true" targetFramework="4.0">
<!-- ... -->
</compilation>
this in webconfig file
but the same error shows .
............
my code
#Html.TextBoxFor(x => x.Entity, new { #id = "Entityname" })
//..........
model
public string Entity { set; get; }
//.........
//..............
.cshtml page
#model BOSSNew.Models.NewQuantifierM
#{Layout = "../Shared/_Layout.cshtml";}
<div class="breadCrumbHolder">
#{Html.RenderAction("BreadCrumb", "Base", new { menulist = new string[] { "Quantifier", "New Quantifier" }, CurrentURL = new string[] { "#", "#" } });}
</div>
<div class="divContentPane">
<div class="contentPaneHead">
<span class="contentPaneTitle">Users Details </span>
</div>
<table class="ClsTable ClsPad0">
<tr class="even">
<th>#LabelHelper.GetLabel("THLentity", 3)
</th>
<td>
#Html.TextBoxFor(x => x.Entity, new { #id = "Entityname" })
<img title="" id="selectentit" style="margin: 5px" onclick="getentity('txtentity','optentity')"
alt="" src="../../../Name.Controls/Themes/Name-Theme/images/entity.png">
</td>
</tr>
</table>
</div>
//.............
Any idea ?
Any help will be appreciated
You haven't defined model for a view, so you can't use
x => x.Field
expression.
It should look more or less like that:
SomeView.cshtml
#model SomeModel
#{Layout = "../Shared/_Layout.cshtml";}
<div class="breadCrumbHolder">
#{Html.RenderAction("BreadCrumb", "Base", new { menulist = new string[] { "Quantifier", "New Quantifier" }, CurrentURL = new string[] { "#", "#" } });}
</div>
<div class="divContentPane">
<div class="contentPaneHead">
<span class="contentPaneTitle">Users Details </span>
</div>
<table class="ClsTable ClsPad0">
<tr class="even">
<th>#LabelHelper.GetLabel("THLentity", 3)
</th>
<td>
#Html.TextBoxFor(x => x.Entity, new { #id = "Entityname" })
<img title="" id="selectentit" style="margin: 5px" onclick="getentity('txtentity','optentity')"
alt="" src="../../../Name.Controls/Themes/Name-Theme/images/entity.png">
</td>
</tr>
</table>
</div>
SomeModel.cs
public class SomeModel
{
public string Entity { set; get; }
}
And finally in your action method...
public ActionResult SomeMethod()
{
var model = new SomeModel();
//here fill the entity field
return View(model);
}

Get value in Create Action

My model.
public class CustomUserTeam
{
public bool IsCation { get; set; }
public int SelectedPlayer { get; set; }
public IEnumerable<SelectListItem> Player { get; set; }
}
My Create View
#model List<superselector.Models.CustomUserTeam>
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm("Create", "UserPlayers", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Team</h4>
<hr />
#Html.ValidationSummary(true)
<table>
<tr>
<th>
Player
</th>
<th>
Caption
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
<div class="form-group">
<div class="col-md-10">
#Html.DropDownListFor(model => item.SelectedPlayer, item.Player)
#Html.ValidationMessageFor(model => item.SelectedPlayer)
</div>
</div>
</td>
<td>
<div class="form-group">
<div class="col-md-10">
#Html.RadioButtonFor(model => item.IsCation, true)
#Html.ValidationMessageFor(model => item.IsCation)
</div>
</div>
</td>
</tr>
}
</table>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
My Create Action
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(List<CustomUserTeam> utvm)// I get null here
{
if (ModelState.IsValid)
{
//db.tblUserTeams.Add(tbluserteam);
//db.SaveChanges();
return RedirectToAction("Index");
}
return View(utvm);
}
public ActionResult Create()
{
//UserTeamViewModel utvm = new UserTeamViewModel();
List<CustomUserTeam> UserTeam = new List<CustomUserTeam>();
List<tblPlayer> batsmen = db.tblPlayers.Where(x => x.tblPlayerSpeciality.Id == 1 || x.tblPlayerSpeciality.Id == 3).OrderBy(x => x.PlayerName).ToList();
List<tblPlayer> Bowlers = db.tblPlayers.Where(x => x.Speciality == 2 || x.Speciality == 3).OrderBy(x => x.PlayerName).ToList();
List<tblPlayer> wk = db.tblPlayers.Where(x => x.Speciality == 4).OrderBy(x => x.PlayerName).ToList();
for (int i = 0; i < 6; i++)
{
UserTeam.Add(new CustomUserTeam() { Player = new SelectList(batsmen, "playerId", "PlayerName") });
}
UserTeam.Add(new CustomUserTeam() { Player = new SelectList(wk, "playerId", "PlayerName") });
for (int i = 0; i < 4; i++)
{
UserTeam.Add(new CustomUserTeam() { Player = new SelectList(Bowlers, "playerId", "PlayerName") });
}
return View(UserTeam);
}
The problem is when i click on "Create" on View, I get null in the Create Action's argument
I dont know whats wrong

Mvc 4 model binding not working dynamically added partial view

I am trying to create a form where in user can add controls. I have main view
#model MVCDynamicFormGenerator.Models.FormViewModel
#{
ViewBag.Title = "Create";
}
#using (#Html.BeginForm())
{
<fieldset>
#Html.HiddenFor(form => form.Form.Uid)
#Html.Hidden("ListFields", ViewData["ListFields"])
<p>
#Html.LabelFor(form => form.Form.FormName)
#Html.TextBoxFor(form => form.Form.FormName)
</p>
<div id="FormFieldList">
#foreach (var formfield in Model.FormFields)
{
switch (formfield.ControlType)
{
case ("Textbox"):
Html.RenderPartial("Textbox", formfield);
break;
}
}
</div>
<h4>
[+] Add a Field
</h4>
<div id="FieldType">
<table>
<tr>
<th>
Select a Field Type
</th>
</tr>
<tr>
<td>
#Html.DropDownList("FieldTypes", new SelectList(Model.FormFields[0].FormFieldTypes, "Value", "Text"), new { id = "SelectedFieldUid" })
#Html.ActionLink("Add Field", "NewFormField", new { formId = ViewContext.FormContext.FormId, selectedFieldType = "SelectedFieldUid" }, new { id = "newFormField" })
#Html.ValidationMessageFor(model => model.FormFields)
</td>
</tr>
</table>
</div>
<p>
<input type="submit" value="Create" />
<input type="button" value="Cancel" '#Url.Action("List")');" />
</p>
</fieldset>
}
On dropdown change I am loading a partial view which is working(User can add n number of times)
#model MVCDynamicFormGenerator.Models.FormFieldViewModel
<div class="FormField">
#using (#Html.BeginForm())
{
<table>
<tr>
<th>
Form Field
</th>
<th>
Field Type
</th>
</tr>
<tr>
<td style="width: 45%;">
#Html.TextBoxFor(formfield => formfield.FormFieldName)
#Html.ValidationMessageFor(formfield => formfield.FormFieldName)
</td>
<td style="width: 25%;">
#Html.DropDownListFor(formfield => formfield.SelectedFormFieldType,
new SelectList(Model.FormFieldTypes, "Value", "Text",
Model.SelectedFormFieldType),
new { disabled = "disabled" })
#Html.HiddenFor(formfield => formfield.SelectedFormFieldType)
#Html.ValidationMessageFor(formfield => formfield.SelectedFormFieldType)
</td>
</tr>
</table>
}
</div>
/// form models
public class FormViewModel
{
//Properties
public Form Form { get; set; }
public List<FormFieldViewModel> FormFields { get; set; }
//Constructor
public FormViewModel()
{
Form = new Form();
FormFields = new List<FormFieldViewModel>();
}
}
public class FormFieldViewModel
{
public string FormFieldName { get; set; }
public string SelectedFormFieldType { get; set; }
}
controller methods
[HttpPost]
public ActionResult Create(FormViewModel viewModel)
{
return View();
}
All the field information related to main view gets available but FormFieldViewModel list gives zero count
Any help or suggestion to fix this

knockoutjs and jquery UI slider

I have list collection like:
{Id : "101", Name :"XXX", Fare: 200 },
{Id : "102", Name :"YYY", Fare: 400 },
{Id : "103", Name :"ZZZ", Fare: 500 },
Now I want to implement Jquery UI slider in knockoutJs with min and maximum fare, based on it I will filter my list.
How I can pass min and max value from observable array min and max fare to Slider using knockoutjs?
Updated with Code:
Html
<div class="row">
<div class="span3 well">
<h4>Filter</h4>
<hr />
<div>
<strong>Fare Range</strong>
<br />
Rs <span id="minFare" data-bind="text : minFare" ></span>
- Rs
<span id="maxFare" data-bind="text : maxFare" ></span>
<div id="slider-range"></div>
</div>
<hr />
<div>
<strong >Bus Type</strong>
<ul data-bind="foreach : busTypes">
<li>
<input type="checkbox" > <span data-bind="text : $data"></span>
</li>
</ul>
</div>
</div>
<div class="span9">
<div class="well">
<strong>Sort </strong>
<div data-bind="foreach: sortingColumns" class="btn-group inline " data-toggle="buttons-checkbox">
<div class="btn" data-bind="text : columnName, click : $root.sort">
</div>
</div>
</div>
<section id="no-more-tables">
<table class="table-bordered table-striped table-condensed cf">
<thead class="cf">
<tr>
<th>
Travel
</th>
<th>
Deparr
</th>
<th>
Arrive
</th>
<th class="numeric">
Seat
</th>
<th class="numeric">
Fare
</th>
</tr>
</thead>
<tbody data-bind="foreach: busResults">
<tr>
<td data-bind="text: CompanyName" data-title="Travel">
</td>
<td data-bind="text: DepartureTime" data-title="Depart">
</td>
<td data-bind="text: ArrivalTime" data-title="Arrive">
</td>
<td data-bind="text: Seats" data-title="Seat" class="numeric">
</td>
<td data-bind="text: Fare" data-title="Fare" class="numeric">
</td>
<td>
<a class="btn btn-info" href="#" >Select</a>
</td>
</tr>
</tbody>
</table>
</section>
</div>
</div>
Js
$(function () {
$("#slider-range").slider({
range: true,
min: $("#minFare").text(),
max: $("#maxFare").text(),
values: [75, 300],
slide: function (event, ui) {
$("#minFare").text(ui.values[0]);
$("#maxFare").text(ui.values[1]);
//$("#amount").val("$" + ui.values[0] + " - $" + ui.values[1]);
}
});
//$("#amount").val("$" + $("#slider-range").slider("values", 0) +
//" - $" + $("#slider-range").slider("values", 1));
});
knockoutjs ViewModel
function busResultsViewModel(param) {
var self = this;
var baseUri = "/api/BusApi/" + param;
self.busResults = ko.observableArray();
self.currentItem = ko.observable('');
self.sortDirection = ko.observable(false);
//Sort By Name
self.sort = function (item) {
var colName = item.columnName == "Travel" ? "CompanyName" : item.columnName;
self.sortDirection(!self.sortDirection());
var test = self.busResults.sort(function (obj1, obj2) {
if (obj1[colName] == obj2[colName]) return 0;
else if (obj1[colName] < obj2[colName])
return -1;
else
return 1;
});
if (self.sortDirection())
self.busResults(test);
else
self.busResults(test.reverse());
};
//Min/Max Fare // Tried
self.minFare = ko.dependentObservable(function () {
var min = 0;
ko.utils.arrayForEach(self.busResults, function (item) {
alert(item.Fare);
if (item.Fare < min) {
min = item.Fare;
}
});
return min;
} );
self.minFare = ko.observable("0");
self.maxFare = ko.observable("800");
self.busTypes = ko.observableArray(["AC", "Non-AC"]);
//Sorting Coumns
self.sortingColumns = ko.observableArray([
{ columnName: "Travel" },
{ columnName: "Fare" }
]);
$.getJSON(baseUri, self.busResults);
}
Model Structure
public class BusResult
{
public int Id { get; set; }
public string CompanyName { get; set; }
public string DepartureDate { get; set; }
public string DepartureTime { get; set; }
public string ArrivalDate { get; set; }
public string ArrivalTime { get; set; }
public string Amenities { get; set; }
public short JourneyHours { get; set; }
public short Seats { get; set; }
public decimal Fare { get; set; }
public IList<string> BusTypes {get; set;}
}
Finally got working:
Html
<span id="minFare" data-bind="text : minFare"></span> - Rs
<span id="maxFare" data-bind="text : maxFare"></span>
<div id="slider-range"></div>
Js
Slider
$("#slider-range").slider({
range: true,
min: vm.minFare(),
max: vm.maxFare(),
step: 1,
values: [vm.minFare(), vm.maxFare()],
slide: function (event, ui) {
vm.minFare(ui.values[0]);
vm.maxFare(ui.values[1]);
}
});
Vm
//Min & Max Slider
function vm()
{
var self = this;
self.minFare = ko.observable();
self.minFare.subscribe(function (newValue) {
//TODO: Filter, min fare changed
});
self.maxFare = ko.observable();
self.maxFare.subscribe(function (newValue) {
//TODO: Filter, max fare changed
});
}