Call post edit action from Razor view mvc4 - asp.net-mvc-4

This question might have been asked several times, however it is not working in my case, so please bear with me.
I have the below actions in my controller:
[HttpPost]
public ActionResult Edit(Organization obj)
{
if (ModelState.IsValid)
{
OrgRepo.Update(obj);
return RedirectToAction("Details");
}
else
return View();
}
public ActionResult Edit(int id)
{
return View();
}
I am trying to update the data into database by calling post edit action.
For this purpose, I am calling the edit action as below:
#foreach (var item in Model) {
var test = item.PartyId;
<tr id="#test">
<td class ="txt">
<input type="text"class="txt" value="#Html.DisplayFor(modelItem => item.Caption)"/>
</td>
<td class ="txt">
<input type="text"class="txt" value="#Html.DisplayFor(modelItem => item.NameInUse)"/>
</td>
<td class ="txt">
<input type="text"class="txt" value="#Html.DisplayFor(modelItem => item.Description )"/>
</td>
<td>
#using (Html.BeginForm())
{
#Html.ActionLink("Edit", "Edit", "Org", null, new { #obj = item })
}
</td>
</tr>
However when I click on edit I am getting exception:
The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ActionResult Edit(Int32)' in 'Dwiza.Controllers.OrgController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
Parameter name: parameters
My questions:
How can I fix this?
Why it get edit action is getting invoked instead of post edit?
What are better ways to invoke edit action among invoke through jQuery, or ajax or any others, if you can suggest better ways of doing it?

The #Html.ActionLink produces an a tag which can only be used to call GET. Change to a submit button to get a POST.
Normally with an Edit, you are only editing a sinble model rather than a collection on a page but going with what you have, change the cshtml to:
#model ICollection<Organization>
<table>
#foreach (var item in Model)
{
using (Html.BeginForm())
{
var test = item.PartyId;
<tr id="#test">
<td class="txt">
<input type="text" name="Caption" class="txt" value="#item.Caption"/>
</td>
<td class="txt">
<input type="text" name="NameInUse" class="txt" value="#item.NameInUse"/>
</td>
<td class="txt">
<input type="text" name="Description" class="txt" value="#item.Description" />
</td>
<td>
<input type="hidden" name="PartyId" value="#item.PartyId"/>
<button type="submit">Edit</button>
</td>
</tr>
}
}
</table>
Now each table row is wrapped by a form meaning the submit button will post that data. The name attribute on the inputs will cause the MVC model binders to bind your posted values to your model correctly.
This hidden input at the end will ensure your PartyId value gets posted back. The fact that it is in int (and not nullable) was giving the exception with your initial code I think.
HTH
EDIT
Adding controller code (note - I still think this is a little/lot strange as you should be editing only the one Organisation...
public ActionResult Edit(int id)
{
// get your organisations from your orgRepo... I'm mocking that out.
var orgs = new List<Organization> { new Organization { PartyId = 1, Description = "Org 1", Caption = "Caption 1", NameInUse = "Name 1"},
new Organization { PartyId = 2, Description = "Org 2", Caption = "Caption 2", NameInUse = "Name 2"}};
return View(orgs);
}

lordy, that is a mess dude. your form only has a link in it, and that link is to the edit action, that will invoke a get, the form will never post back. are you trying to do a form inside a table row?
#foreach (var item in Model) {
var test = item.PartyId;
<tr>
<td colspan ="4>
#using (Html.BeginForm("Edit", "Org", FormMethod.Post))
{
#Html.HiddenFor(modelItem => item.PartyId)
<table>
<tr id="#test">
<td class ="txt">
<input type="text"class="txt" value="#Html.DisplayFor(modelItem => item.Caption)"/>
</td>
<td class ="txt">
<input type="text"class="txt" value="#Html.DisplayFor(modelItem => item.NameInUse)"/>
</td>
<td class ="txt">
<input type="text"class="txt" value="#Html.DisplayFor(modelItem => item.Description )"/>
</td>
<td>
<input type="submit" value="edit" />
</td>
</tr>
</table>
}
</td>
</tr>
}
That code will do an edit inside a row, but i am just guessing at the structure from the code you posted.

Related

ASP .NET Core: Editable Grid: Insert dropdown list

Objetive: I'm trying to construct a view where the records from a table (machines) can be updated in a grid, and that each atribute of each record has the option to be chosen from a dropdownlist.
This is my Get method:
public async Task<IActionResult> Test()
{
return View(await _context.Machines.Include(t => t.MachineTypes).Include(p => p.Suppliers).Include(s=>s.Stores).AsNoTracking().ToListAsync());
}
And this is the definition for the dropdown list:
private void PopulateMachineTypeDropDownListStore(object selectedStore = null)
{
var typequery = from k in _context.Stores
orderby k.StoreName
select k;
ViewBag.StoreID = new SelectList(typequery.AsNoTracking(), "StoreID", "StoreName", selectedStore);
}
Now, to the View:
Model:
#model IEnumerable<Application.Models.Machine>
Since I need all the registers. Then the table.
Header:
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.MchName)
</th>
<th>
#Html.DisplayNameFor(model => model.StoreID)
</th>
</tr>
</thead>
Body:
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.MchName)
</td>
<td>
<div class="form-group">
<label asp-for="StoreID" class="col-md-2 control-label"></label>
<div class="col-md-10">
<select asp-for="StoreID" class="form-control" asp-items="ViewBag.StoreID">
<option value="">-- Seleccione Tienda --
</option>
</select>
<span asp-validation-for="StoreID" class="text-danger"></span>
</div>
</div>
</td>
</tr>
}
</tbody>
</table>
}
Question: I've read that is not best to use a div inside a td but it may work, altough there may be better options. Which would be the best practice?
Question: Well, this is a Test but I'm getting this error:
"'IEnumerable' does not contain a definition for 'StoreID' and no extension method 'StoreID' accepting a first argument of type 'IEnumerable' could be found (are you missing a using directive or an assembly reference?)"
I can't track the error. For me it looks fine and I don't know why it can't read the StoreID. I wonder if it's for the "asp-for" inside the div. I don't know.
Any help is appreciated.
Thanks

The Index view does not receive the list partial from the ajax call made from Searchbox partial?

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

Insert Partial View to a another Partial View

This is the main view Dept_Manager_Approval.cshtml where I have put a modal to show data.
<td>
<i title="View Details">
#Ajax.ActionLink(" ", "ViewAccessStatus", new { id = item.request_access_id },
new AjaxOptions
{
HttpMethod = "Get",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "edit-div",
}, new { #class = "fa fa-eye btn btn-success approveModal sample" })</i>
</td>
In this partial view which just a modal, ViewAccessStatus.cshtml , I have inserted in here another partial view.
<div>
<h2><span class ="label label-success">Request Creator</span> </h2>
#if (Model.carf_type == "BATCH CARF")
{
#Html.Partial("Batch_Requestor1", new {id= Model.carf_id })
}else{
<h4><span class ="label label-success">#Html.DisplayFor(model=>model.created_by)</span></h4>
}
</div>
COntroller:
public ActionResult Batch_Requestor1(int id = 0)
{
var data = db.Batch_CARF.Where(x => x.carf_id == id && x.active_flag == true).ToList();
return PartialView(data);
}
Batch_Requestor1.cshtml
#model IEnumerable<PETC_CARF.Models.Batch_CARF>
#{
ViewBag.Title = "All Requestors";
}
<br/><br/>
<table class="table table-hover">
<tr class="success">
<th>
#Html.DisplayName("Full Name")
</th>
<th>
#Html.DisplayName("Email Add")
</th>
<th>
#Html.DisplayName("User ID")
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.fname) - #Html.DisplayFor(modelItem => item.lname)
</td>
<td>
#Html.DisplayFor(modelItem => item.email_add)
</td>
<td>
#Html.DisplayFor(modelItem => item.user_id)
</td>
</tr>
}
</table>
When I run this, I've got this error
The model item passed into the dictionary is of type '<>f__AnonymousType01[System.Int32]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[PETC_CARF.Models.Batch_CARF]'.
Any ideas how will I insert another partial view?
#Html.Partial() renders a partial view. It does not call an action method that in turn renders the partial. In your case
#Html.Partial("Batch_Requestor1", new {id= Model.carf_id })
is rendering a partial view named Batch_Requestor1.cshtml and passing it a model defined by new {id= Model.carf_id } (and anonymous object) but that view expects a model which is IEnumerable<PETC_CARF.Models.Batch_CARF>.
Instead, you need to use
#Html.Action("Batch_Requestor1", new {id= Model.carf_id })
which calls the method public ActionResult Batch_Requestor1(int id = 0) and passes it the value of Model.carf_id, which will in turn render the partial view.

Html.ActionLink object parameters + MVC4

I am calling Edit action from my view that should accept an object as parameter.
Action:
[HttpPost]
public ActionResult Edit(Organization obj)
{
//remove the lock since it is not required for inserts
if (ModelState.IsValid)
{
OrganizationRepo.Update(obj);
UnitOfWork.Save();
LockSvc.Unlock(obj);
return RedirectToAction("List");
}
else
{
return View();
}
}
From View:
#foreach (var item in Model) {
cap = item.GetValForProp<string>("Caption");
nameinuse = item.GetValForProp<string>("NameInUse");
desc = item.GetValForProp<string>("Description");
<tr>
<td class="txt">
<input type="text" name="Caption" class="txt" value="#cap"/>
</td>
<td>
<input type="text" name="NameInUse" class="txt" value="#nameinuse"/>
</td>
<td>
<input type="text" name="Description" class="txt" value="#desc"/>
</td>
<td>
#Html.ActionLink("Edit", "Edit", "Organization", new { obj = item as Organization }, null)
</td>
</tr>
}
It is raising an exception: The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ActionResult Edit(Int32)' in 'PartyWeb.Controllers.Internal.OrganizationController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
Parameter name: parameters
Can somebody advise how to pass object as parameter?
Can somebody advise how to pass object as parameter?
Why are you using an ActionLink? An ActionLink sends a GET request, not POST. So don't expect your [HttpPost] action to ever be invoked by using an ActionLink. You will have to use an HTML form and include all the properties you want to be sent as input fields.
So:
<tr>
<td colspan="4">
#using (Html.BeginForm("Edit", "Organization", FormMethod.Post))
{
<table>
<tr>
#foreach (var item in Model)
{
<td class="txt">
#Html.TextBox("Caption", item.GetValForProp<string>("Caption"), new { #class = "txt" })
</td>
<td class="txt">
#Html.TextBox("NameInUse", item.GetValForProp<string>("NameInUse"), new { #class = "txt" })
</td>
<td class="txt">
#Html.TextBox("Description", item.GetValForProp<string>("Description"), new { #class = "txt" })
</td>
<td>
<button type="submit">Edit</button>
</td>
}
</tr>
</table>
}
</td>
</tr>
Also notice that I used a nested <table> because you cannot have a <form> inside a <tr> and some browser such as IE won't like it.

Retaining Form Values After Post (not part of model)

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.