When I select a product from the table and click the submit button.
The ProductID and quantity from the dropdown list is passed back to the controller.
But my controller always receives the same ProductID regardless of what product I select.
Any pointer or help much appreciated.
#foreach (var t in Model.TyreFittedList)
{
<tr>
<td class="text-center">#t.ProductID</td>
<td>#t.Brand #t.Pattern <br /> #t.Full_size <br /></td>
<td>#t.Label_Roll</td>
<td>#t.Label_Wetgrip</td>
<td>#t.Label_Noise1<span>dB</span></td>
<td>
#t.ProductUnitSalePriceMailOrder.Value.ToString("C", CultureInfo.CreateSpecificCulture("en-GB"))<br />
</td>
<td>
#Html.DropDownListFor(model => model.SelectedProductId, new SelectList(Model.Quantity, "Id", "Quantity"), "0", new { style = "width: 60px;" })
<input type="hidden" name="ProductID" value="#t.ProductID" />
<input type="submit" class="btn btn-primary btn-sm btn-Order" name="Action:Order" value="Add" />
</td>
</tr>
}
[HttpPost]
public ActionResult SubmitSearchResultsMailOrder(ApplicationViewModel model, FormCollection collection, int? ProductID)
{
if (ModelState.IsValid)
{
if (Request.Form["Action:Order"] != null)
{
int qty = model.SelectedProductId;
int? productID = ProductID;
}
}
return CurrentUmbracoPage();
}
Related
On a Blazor component, I have this table in which I'm trying to implement inline editing functionality. I've managed the visual bits, but when it comes to grabbing the new values from the changed row on button click, I have no clue how to proceed.
Each row on the table is based on this object:
public class InstanceData
{
public Guid Id { get; set; }
public string DisplayName { get; set; }
public string BaseAddress { get; set; }
public int Port { get; set; }
public string Version { get; set; }
public string AdditionalInformation { get; set; }
[JsonIgnore]
public bool IsEditing { get; set; }
}
On my razor page, table is populated like following:
<table>
#*<thead tbody blah blah>*#
#foreach (var instance in serverInstances)
{
if (instance.IsEditing)
{
<tr>
<th scope="row">#instance.GetShortenedIdentifier()</th>
<td>
<input type="text" class="form-control" placeholder="Give the instance a name" value="#instance.DisplayName" />
</td>
<td>
<input type="text" class="form-control" placeholder="e.g. http://localhost (without port)" value="#instance.BaseAddress" />
</td>
<td>
<input type="number" class="form-control" placeholder="The port number server is running on" value="#instance.Port"
min="0" max="65535" />
</td>
<td>
<input type="text" class="form-control" placeholder="For information purposes and not required" value="#instance.Version" />
</td>
<td>
<input type="text" class="form-control" placeholder="Any other details to add (e.g. Feature environment mocks instance)" value="#instance.AdditionalInformation" />
</td>
<td>
<button type="button" class="btn btn-link" #onclick="() => EnableEditing(false, instance)">
<i class="fas fa-window-close" />
</button>
<button type="button" class="btn btn-link" #onclick="() => UpdateInstance(instance)">
<i class="fas fa-check-square" />
</button>
</td>
</tr>
}
else
{
<tr>
<th scope="row">#instance.GetShortenedIdentifier()</th>
<td>#instance.DisplayName</td>
<td>#instance.BaseAddress</td>
<td>#instance.Port</td>
<td>#instance.Version</td>
<td>#instance.AdditionalInformation</td>
<td>
<button type="button" class="btn btn-link" #onclick="() => EnableEditing(true, instance)">
<i class="fas fa-pen" />
</button>
</td>
</tr>
}
</table>
#code {
private void EnableEditing(bool flag, InstanceData instanceData)
{
instanceData.IsEditing = flag;
}
private void UpdateInstance(InstanceData instanceData)
{
EnableEditing(false, instanceData);
//call the repository to update the instance here.
//show toast after done.
}
}
So, what I am trying to do is to get all those input element values to be passed into my method on #onclick="() => UpdateInstance(instance)" action. I've thought of assigning Id or fiddle with #ref but failed. What's the correct way to do this, or am I approaching this in a wrong way?
To visualise it, here's a little something with my awesome ms paint skills.
You're setting the input values using the object values but not binding them.
<input type="text" class="form-control" placeholder="Give the instance a name" value="#instance.DisplayName" />
This will set the value of the input control but won't pass updates to anything.
You need to #bind the values to the property, e.g.
<input type="text" class="form-control" placeholder="Give the instance a name" #bind="#instance.DisplayName" />
This will update the underlying object's properties with any changes.
More: https://learn.microsoft.com/en-us/aspnet/core/blazor/data-binding?view=aspnetcore-3.1
<input type="text"
class="form-control"
value="#instance.DisplayName"
#onchange="#(e => CurrentDislayName = e.Value.ToString())"
readonly="#bEditing" id="#($"id_{instance.id}")" />
#code{
[Parameter]
public string CurrentDisplayName { get; set; }
}
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:
i have the following partial view for the the _searchbox partial
#model ecomm2.Models.MainSearchBoxViewModel
<div id="search-box-wrapper" style="text-align:center">
<div id="search-box-div" style="display:inline-block">
#using (Ajax.BeginForm("GetResults", "Partials",
new AjaxOptions {
HttpMethod="get",
InsertionMode=InsertionMode.Replace,
OnSuccess="updateMainResultsDiv",
UpdateTargetId="divMainResultsList"}))
{
<table>
<tr>
<td>
<fieldset>
<label>Search: </label>
</fieldset>
</td>
<td>
<fieldset>
#Html.DropDownListFor(m => m.ProdCatId, Model.MainSearchDDLCollection, new { style="width:200px;"})
</fieldset>
</td>
<td> </td>
<td>
<fieldset>
<input type="text" name="SearchText" style="width:400px"/>
</fieldset>
</td>
<td> </td>
<td><input type="submit" value="Search" /></td>
</tr>
</table>
}
</div>
</div>
<br />
then i have added this _SearchBox partial view to the layout so each page gets a searchbox with a drown category list to filter the search.
note: _searchbox partial is called by Another action in the "Partials" controller and works fine.
the action method "GetResults" is in the "Partials" controller and this is the method that is called by ajax from _SearchBox partial
[AjaxOnly]
public ActionResult GetResults(int ProdCatId, string SearchText)
{
var Products = db.mt_Products
.Where(e => e.SearchString.Contains(SearchText) & e.ProdCatId == ProdCatId)
.Select(e => new HomeSearchResultsViewModel
{
Id=e.Id,
ProdCode=e.ProdCode.Trim(),
ProductLineName= e.mt_Brands.BrandName.Trim() +" "+ e.ProdName.Trim(),
ListPrice=e.ListPrice,
ProdImage=e.ProdImg,
StockCount=e.Stock,
BrandName=e.mt_Brands.BrandName.Trim(),
CategoryName=e.mt_ProductCategories.CatName.Trim()
}).ToList();
return PartialView("_SearchResults", Products);
}
then i have the following code in Index view of the Home controller
#model IEnumerable<ecomm2.Models.HomeSearchResultsViewModel>
#{
ViewBag.Title = "Index";
}
<h2>Welcome Admin,</h2>
<p>
</p>
<div id="divMainResultsList">
#Html.Partial("_SearchResultsList", Model)
</div>
<script type="text/javascript">
function updateMainResultsDiv() {
$('#divMainResultsList').html()
}
</script>
when i passed a value to the search box and performed a search, it showed that search values were received by the action method GetResults and LINQ generates results but result were not placed on div area. Is this div placed on right spot?
it seems a bit complicated to post all and here is the video
i try to make a simple project, that check the list of checkbox. my database is like this... !
i want to check my checkbox when hotel have the facilities...
i have code like this...
my controller
public ActionResult Facility()
{
var model = db.Facilities
.Where (htl => htl.FacilityID == hotelFacility.FacilityID)
.Select(htl => new CheckFacilityVM
{
FacilityID = htl.FacilityID,
facilityName = htl.FacilityName,
facilityAvailable = htl.IsActive == true,
})
.ToList();
return View(model);
}
my constuctor class
public Facility ShowRoomFacility(int HotelID)
{
var x = (from d in db.Facilities
where d.FacilityID == HotelID
select d).FirstOrDefault();
return x;
}
my view
#model List<XNet.WebUI.Hotel.ViewModel.CheckFacilityVM>
#{
ViewBag.Title = "Facility";
}
<h2>Facility</h2>
#using (Html.BeginForm())
{
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th> is available</th>
</tr>
</thead>
<tbody>
#for (int i = 0; i < Model.Count; i++)
{
<tr>
<td>
#Html.DisplayFor(x => x[i].FacilityID)
#Html.HiddenFor(x => x[i].FacilityID)
</td>
<td>
#Html.DisplayFor(x => x[i].facilityName)
#Html.HiddenFor(x => x[i].facilityName)
</td>
<td>
#Html.CheckBoxFor(x => x[i].facilityAvailable)
</td>
</tr>
}
</tbody>
</table>
}
<br />
<input style="width:100px;" type="button" title="Save" value="Save" onclick="location.href='#Url.Action("Index","Hotel")'" />
<input style="width:100px;" type="button" title="Reset" value="Reset" onclick="location.href='#Url.Action("Facility","Hotel")'" />
<input style="width:100px;" type="button" title="Cancel" value="Cancel" onclick="location.href='#Url.Action("Room","Hotel")'" />
how can i make checkbox is checked ??
help me please
You want to store the true/false in your database as a bit. 0 is false and 1 is true.
Then when you have a boolean property in your view model, populated by your database
public bool FacilityXAvailable { get; set; }
On your view you can then just do this
#Html.DisplayFor(model=>model.FacilityXAvailable)
That will display a checkbox checked on unchecked depending on Db value.
I have a MVC4 page that has a form with a collection of checkboxes, radio buttons and textboxes used as the search fields. Upon post the selections are parsed and the lower results grid is updated with new results. Right now all the form values are wiped out upon return and the new results are displayed in the grid - only the grid is part of the model.
I want all the form selections to retain their values after post so the user can see (and change) the selections for next post/search. The form is popuplated with viewbags.
#using (Html.BeginForm("Index", "Home", FormMethod.Post, new { id = "searchform" }))
{
#Html.ValidationSummary("Please correct the following errors")
<div style="float:left;">
<div style="float:left;">
<label>Name:</label>
#Html.TextBox("name")
</div>
<div style="float:left; margin-left:15px">
<label>Company:</label>
#Html.TextBox("company")
</div>
<div style="float:left; margin-left:65px">
<label>Date Range:</label>
#Html.TextBox("dateStart", "", new { #class = "datefield", type = "date" })
to
#Html.TextBox("dateEnd", "", new { #class = "datefield", type = "date" })
</div>
</div>
<div style="clear: both;">
Match Any Categories? <input type="radio" name="categoryMatchAll" value="false" checked="checked" />
Match All Categories? <input type="radio" name="categoryMatchAll" value="true" />
</div>
<div style="float:left;">
<div id="searchform-categories" style="float:left;">
<div class="scroll_checkboxes">
<label>Categories</label>
<ul>
#foreach (var x in ViewBag.Categories)
{
<li>
<input type="checkbox" name="categories" value="#x.Id"/>
#x.Name
</li>
}
</ul>
</div>
</div>
<div id="searchform-diversity" style="float:left; margin-left:30px">
<div class="search-selection" style="float:left;">
<label>Minority Owned</label>
<ul>
#foreach (var x in ViewBag.Minorities)
{
<li>
#Html.RadioButton("minorities", (String)x.Id.ToString())
#x.Name
</li>
}
</ul>
</div>
<div class="search-selection" style="float:left;">
<label>Diversity Class</label>
<ul>
#foreach (var x in ViewBag.Classifications)
{
<li>
#Html.RadioButton("classifications", (String)x.Id.ToString())
#x.Name
</li>
}
</ul>
</div>
</div>
</div>
<div style="clear: both;">
<input type="submit" value="Search Profiles" />
<input type="submit" value="Reset" />
</div>
}
the data grid is bound to the model as
#model IEnumerable<VendorProfileIntranet.Models.VendorProfile>
<table id="VendorTable" width="100%" class="gradeA">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.CompanyName)
</th>
<th>
#Html.DisplayNameFor(model => model.City)
</th>
<th>
#Html.DisplayNameFor(model => model.State)
</th>
<th>
#Html.DisplayNameFor(model => model.DateCreated)
</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td class="list-field">
#Html.DisplayFor(modelItem => item.Name)
</td>
<td class="list-field">
#Html.DisplayFor(modelItem => item.CompanyName)
</td>
<td class="list-field">
#Html.DisplayFor(modelItem => item.City)
</td>
<td>
#Html.DisplayFor(modelItem => item.State)
</td>
<td class="list-field">
#Html.DisplayFor(modelItem => item.DateCreated)
</td>
<td class="list-field">
#Html.ActionLink("Edit", "Edit", new { id = item.ProfileID }) |
#Html.ActionLink("View", "View", new { id = item.ProfileID }) |
#Html.ActionLink("Delete", "Delete", new { id = item.ProfileID }, new { onclick = " return DeleteConfirm()" })
</td>
</tr>
}
</tbody>
<tfoot>
<tr>
<td> </td>
</tr>
</tfoot>
if you are using html in mvc then check solution 2 from here, value="#Request["txtNumber1"]" worked fine for me,
<input type="text" id="txtNumber1" name="txtNumber1" value="#Request["txtNumber1"]"/>
hope helps someone.
So here is how I typically solve this problem. My notes are purely my opinion (religous?) about naming classes in an MVC project to keep clear their purpose.
Couple of interfaces to keep it extensible:
// be specific about what type of results, both in the name of the
// interface and the property needed, you don't want to have overlapping
// properies on your classes, I like suffixing interfaces that are specific
// to a View or Partial View with View
public interface IPersonSearchResultsView
{
IEnumerable<EFPerson> PersonSearchResults { get; }
}
public interface IPersonSearchCriteriaView
{
PersonSearchCriteriaModel PersonSearchModel { get; }
}
Couple of classes
// I like suffixing classes that I only use for MVC with Model
public PersonSearchCriteriaModel
{
public string Name {get; set;}
public string Company {get; set;}
public string DateStart {get; set;}
public string DateEnd {get; set;}
}
// I like suffixing classes that I used passed to a View/Partial View
// with ViewModel
public class PersonSearchViewModel : IPersonSearchResultsView,
IPersonSearchCriteriaView
{
public IEnumerable<EFPerson> PersonSearchResults { get; set; }
public PersonSearchCriteriaModel PersonSearchModel { get; set; }
}
Now for your controllers, I'll set them up in a way that would also allow you to do Ajax in the future.
public PersonController : Controller
{
public ActionResult Search()
{
var model = new PersonSearchViewModel();
// make sure we don't get a null reference exceptions
model.PersonSearchModel = new PersonSearchCriteriaModel ();
model.PersonSearchResults = new List<EFPerson>();
return this.View(model);
}
[HttpPost]
public ActionResult Search(PersonSearchViewModel model)
{
model.PersonSearchResults = this.GetPersonResults(model.PersonSearchModel);
return this.View(model)
}
// You could use this for Ajax
public ActionResult Results(PersonSearchViewModel model)
{
model.PersonSearchResults = this.GetPersonResults(model.PersonSearchModel);
return this.Partial("Partial-SearchResults", model)
}
private GetPersonResults(PersonSearchCriteriaModel criteria)
{
return DbContext.GetPersonResults(criteria)
}
}
Create a couple of partial-views your Views.
/Views/Person/Partial-SearchCriteria.cshtml
#model IPersonSearchCriteriaView
// the new part is for htmlAttributes, used by Ajax later
#using (Html.BeginForm(..., new { id="searchCriteria" }))
{
// Here is were the magic is, if you use the #Html.*For(m=>)
// Methods, they will create names that match the model
// and you can back back to the same model on Get/Post
<label>Name:</label>
#Html.TextBoxFor(m => Model.PersonSearchModel.Name)
// or let mvc create a working label automagically
#Html.EditorFor(m => Model.PersonSearchModel.Name)
// or let mvc create the entire form..
#Html.EditorFor(m => Model.PersonSearchModel)
}
/Views/Person/Partial-SearchResults.cshtml
#model IPersonSearchResultsView
#foreach (var person in Model.PersonSearchResults )
{
<tr>
<td class="list-field">
#Html.DisplayFor(modelItem => person.Name)
</td>
// etc
</tr>
}
And Finally the view:
/Views/Person/Search.cshtml
#model PersonSearchViewModel
#Html.Partial("Partial-SearchCriteria", Model)
// easily change the order of these
<div id="searchResults">
#Html.Partial("Partial-SearchResults", Model);
</div>
Now enabling Ajax is pretty crazy easy (simplified and my not be exactly right):
$.Ajax({
url: '/Person/Results',
data: $('#searchCriteria').serialize(),
success: function(jsonResult)
{
$('#searchResults').innerHtml(jsonResult);
});
What I typically do is pass the posted Model back into the view. This way the values are not cleared out.
Your code would look something like this:
<div style="float:left;">
<div style="float:left;">
<label>Name:</label>
#Html.TextBox("name", Model.Name)
</div>
<div style="float:left; margin-left:15px">
<label>Company:</label>
#Html.TextBox("company", Model.Company)
</div>
<div style="float:left; margin-left:65px">
<label>Date Range:</label>
#Html.TextBox("dateStart", Model.DateStart, new { #class = "datefield", type = "date" })
to
#Html.TextBox("dateEnd", Model.DateEnd, new { #class = "datefield", type = "date" })
</div>
When initially getting the form, you'll have to create a new Model, otherwise the Model will be null and throw an exception when properties are called on it.
Sample Model
public class SearchModel
{
public SearchModel()
{
Results = new List<Result>();
}
public string Name {get; set;}
public string Company {get; set;}
public string DateStart {get; set;}
public string DateEnd {get; set;}
public List<Result> Results {get; set;}
}
#foreach (var item in Model.Results)
{
<tr>
<td class="list-field">
#Html.DisplayFor(modelItem => item.Name)
</td>
<td class="list-field">
#Html.DisplayFor(modelItem => item.CompanyName)
</td>
<td class="list-field">
#Html.DisplayFor(modelItem => item.City)
</td>
<td>
#Html.DisplayFor(modelItem => item.State)
</td>
<td class="list-field">
#Html.DisplayFor(modelItem => item.DateCreated)
</td>
<td class="list-field">
#Html.ActionLink("Edit", "Edit", new { id = item.ProfileID }) |
#Html.ActionLink("View", "View", new { id = item.ProfileID }) |
#Html.ActionLink("Delete", "Delete", new { id = item.ProfileID }, new { onclick = " return DeleteConfirm()" })
</td>
</tr>
}
Here is a link on creating models for a view in MVC.