Post item form IEnumerable<T> - asp.net-mvc

I have a view who's model is of type IEnumerable:
#model IEnumerable<Customer>
and in this view I show a list of customers:
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Firstnames)
</td>
<td>
#Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
<a asp-action="Edit" asp-route-id="#item.ID">Edit</a> |
</td>
</tr>
}
However, clicking Edit puts the selected customer id on the URL and calls the [HttpGet] Edit action.
This approach means anybody can simply change the id parameter on the URL to read someone else's data.
How do I change this so that clicking Edit "Posts" the customer id to a an action method such as below?
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> GetForEdit(int id)
{
await _context.SaveChangesAsync();
return RedirectToAction("Edit", id);
}

Related

Post Html table created by a model in MVC view to controller

I created a list based on the scaffolding
#model IEnumerable<FleetLink.Domain.Entities.UserTable>
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
<table>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Master_IP)
#Html.TextBoxFor(modelItem=>item.Master_IP)
</td>
<td>
#Html.DisplayFor(modelItem => item.Master_Name)
</td>
</tr>
<tr><td><input type="submit" value="Submit" /></td></tr>
</table>
}
In my controller I have a get and a post method for index
[HttpPost]
public ActionResult Index(List<UserTable> list)
{
return View();
}
[HttpGet]
public ActionResult Index()
{
var users= from userTable in _repo.GetUsers()
select userTable;
return View(users);
}
I was expecting it would call post method when I clicked on submit and would pass the entire tables data to the Index HTTPPost method. But it is always calling the get method of Index. The goal is to pass entire table data after user edits it so I can save all table data at once. Please advice on what I am doing wrong.
I resolved this issue by changing the foreach to for(int i=0....) as well as changing the #using (Html.BeginForm("Index", "Home", FormMethod.Post)) to
#using (Html.BeginForm(FormMethod.Post))
Thanks

How to add Edit, Delete and Search functionality in single view in MVC?

I'm new to MVC.
on MSDN i've studied that there should be folder in view with the same name of controller. For every Action Method in the controller we have to create a View in the same folder.
I'm creating a test application in which:
I have a homeController with an Index ActionMethod. Corresponding to it i have a View in View/home/Index, which simply show the listing of the employees.
I know i can add a [HTTP POST] Index ActionMethod in the homeController.
But i want to add the Delete and Search functionality on the view. So that a user can search the employees with there name and can delete an employee on the same page.
I don't know how can i move ahead for this functionality.
Still i'm using this code.
homeController
public ActionResult Index()
{
ViewBag.text = "Records Listing";
var q = from p in objEmp.tbemployees select p;
return View(q);
}
Index.cshtml
#model IEnumerable<MvcApplication6.Models.tbemployee>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>#ViewBag.text</h1>
<table style="font-size:15px;">
<tr>
<th>
Name
</th>
<th>
Address
</th>
<th>
Sallary
</th>
</tr>
#foreach (var item in Model)
{
<tr >
<td style="padding:7px;">
#Html.DisplayFor(mm => item.ename)
</td>
<td style="padding:7px;">
#Html.DisplayFor(mm => item.eadd)
</td>
<td style="padding:7px;">
#Html.DisplayFor(mm => item.esal)
</td>
<td style="padding:7px; color:Blue; text-decoration:underline;">
#Html.ActionLink("Edit", "Edit", new { id = item.empno })
</td>
</tr>
}
</table>
Thanks.
For the Delete you could add a column in the table that will invoke a controller action and pass it the current record id:
<tr>
<td style="padding:7px;">
#Html.DisplayFor(mm => item.ename)
</td>
<td style="padding:7px;">
#Html.DisplayFor(mm => item.eadd)
</td>
<td style="padding:7px;">
#Html.DisplayFor(mm => item.esal)
</td>
<td style="padding:7px; color:Blue; text-decoration:underline;">
#Html.ActionLink("Delete", "Delete", new { id = item.empno })
#Html.ActionLink("Edit", "Edit", new { id = item.empno })
</td>
</tr>
and your Delete action:
public ActionResult Delete(int id)
{
... use the passed id to delete the record from the database
return RedirectToAction("Index");
}
for the Edit functionality you could have a controller action that will fetch the record and render a view that will allow for editing:
public ActionResult Edit(int id)
{
var employee = objEmp.tbemployees.FirstOrDefault(x => x.Id == id);
if (employee == null)
{
// no employee with the specified id was found
return new HttpNotFound();
}
return View(employee);
}
and then you could have a corresponding ~/Views/Home/Edit.cshtml view:
#model Employee
#using (Html.BeginForm())
{
<div>
#Html.LabelFor(x => x.ename)
#Html.EditorFor(x => x.ename)
</div>
<div>
#Html.LabelFor(x => x.eadd)
#Html.EditorFor(x => x.eadd)
</div>
...
<button type="submit">Save</button>
}
and of course a corresponding action to update the record when this form is submitted:
[HttpPost]
public ActionResult Edit(Employee employee)
{
... update the employee record
return RedirectToAction("Index");
}
You can add and implement a Delete action method in your controller. Then in your view, call #Html.ActionLink("Delete", "Delete", new { id = item.empno }). This will return a hyperlink which links to your Delete method in the controller.

Passing entire Model from a View back to the Controller

I got a list of:
public class Items
{
public String Nro_Item { get; set; }
public Sucursal Sucursal { get; set; }
public Areas Area { get; set; }
public Sectores Sector { get; set; }
public bool ID_Estado { get; set; }
}
I'm passing it to this view:
#using ClientDependency.Core.Mvc
#model IEnumerable<TrackingOperaciones.Controllers.Items>
#{
ViewBag.Title = "Ver Items";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<br/>
#using (Html.BeginForm("CargarRecibidos", "Recepcion", FormMethod.Post))
{
<table class="table table-striped table-bordered table-condensed">
<tr>
<th>
Numero
</th>
<th>
Sucursal
</th>
<th>
Area
</th>
<th>
Sector
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Nro_Item)
</td>
<td>
#Html.DisplayFor(modelItem => item.Sucursal.descripcion)
</td>
<td>
#Html.DisplayFor(modelItem => item.Area.descripcion)
</td>
<td>
#Html.DisplayFor(modelItem => item.Sector.Descripcion)
</td>
<td>
#Html.CheckBoxFor(modelItem => item.ID_Estado)
</td>
</tr>
}
</table>
<p>
<input class="btn" name="Guardar" type="submit" value="Guardar"/> |
#Html.ActionLink("Volver al listado de RecepciĆ³n", "Index")
</p>
}
Until there everything is fine: Now the problem is getting back the entire model with the checked values in a controller for processing it like this one:
[HttpPost]
public ActionResult CargarRecibidos(IEnumerable<Items> items)
{
if (ModelState.IsValid)
{
//do something here
}
return RedirectToAction("Index");
}
}
But i'm falling miserably because "items" came back empty in the postback
i'm guess something is wrong with the form
#using (Html.BeginForm("CargarRecibidos", "Recepcion"))
{
<input class="btn" name="Guardar" type="submit" value="Guardar"/>
}
please help me!
Use IEnumerable
Then the controller input parameter will be List
Perhaps also consider using AJAX POST with JSON objects in place of a form submit (more modern/elegant) but submits are fine too.
Part of the problem is it won't post the entire model since only the checkbox is a form value. I think you need to add an additional hidden value in your form to track the item number and then handle the checkbox values specially in the controller. The item number is appended to "checkbox" in the posted values to keep them distinct.
<tr>
<td>
#Html.DisplayFor(modelItem => item.Nro_Item)
#Html.Hidden("Nro_Item", item.Nro_Item)
</td>
<td>
#Html.DisplayFor(modelItem => item.Sucursal.descripcion)
</td>
<td>
#Html.DisplayFor(modelItem => item.Area.descripcion)
</td>
<td>
#Html.DisplayFor(modelItem => item.Sector.Descripcion)
</td>
<td>
#Html.CheckBox("checkbox" + item.Nro_Item, item.ID_Estado)
</td>
</tr>
In the controller only bind to the number item so it can be used to process the checkboxes:
[HttpPost]
public ActionResult CargarRecibidos(List<string> nro_item)
{
foreach (string item in nro_item)
{
var checkbox=Request.Form["checkbox" + item];
if (checkbox != "false") // if not false then true,false is returned
{
// Do the action for true...
}
else
{
// Do the action for false
}
}
return View();
}

Passing value from EditorFor to controller

This is my view where education is the list in the model.
#using chpayroll.Models.CustInformations
#model CustInfoExtract
#Html.HiddenFor(x => x.flag, new { #id = "flag" })
#Html.HiddenFor(x => x.StaffId)
<table style=" width:730px">
<tr>
<th>Country</th>
<th>Board</th>
<th>Level</th>
<th>PassedYear</th>
<th>Division</th>
</tr>
<tr>
#Html.EditorFor(x => x.education)
</tr>
<tr>
<td><input type="submit" value="Add Another" id="addedu"/> </td>
</tr>
</table>
I have editor template as below
#using staffInfoDetails.Models
#model staffInfo.education
#Html.HiddenFor(x=>x.staffId)
<tr>
<td >#Html.DropDownListFor(x => x.country, Model.countryList, "--select--", new { #id="country"})</td>
<td>#Html.TextBoxFor(x => x.board, new { #id="board"})</td>
<td>#Html.TextBoxFor(x => x.level, new { #id="level"})</td>
<td>#Html.TextBoxFor(x => x.passedYr, new { #id="passedYr"})</td>
<td>#Html.DropDownListFor(x => x.passedDiv, Model.passedDivList, "--select--", new { #id="division"})</td>
</tr>
I am trying to pass model from controller to view and back from view to controller. While I was passing model to view, the education list passed, but, when i tried to pass model from view to controller, everything else passed except for the education list. How can I solve this problem ?
Only the selected value from the drop down list will be posted back so you'll need to re-populate your drop down list if validation fails (ie. if the View has to be re-displayed).
Your POST action might look something along the lines of the following:
[HttpPost]
public ActionResult Home(CustInformations viewModel)
{
if (!ModelState.IsValid)
{
// Re-populate drop-down list and redisplay form
viewModel.DropdownListOptions = _repository.getEductionList();
return View(viewModel);
}
// Validation passed
// Save, update, etc and redirect to new page
}

Why is the view not refreshed? (.Net MVC)

I am learning .Net MVC. I have a page where I show productlines. I want to filter the productlines by their suppliers via a dropdownlist.
My controller:
public class ProductlineController : Controller
{
SupplierRepository sr = new SupplierRepository();
ProductlineRepository pr = new ProductlineRepository();
public ActionResult Default()
{
SupplierModel sm = new SupplierModel();
List<Supplier> suppliers = sr.GetAll();
sm.Suppliers = (from s in suppliers select new SelectListItem {
Text = s.Name,
Value = s.Id.ToString()
}).ToList();
sm.Productlines = pr.GetAll();
return View("List", sm);
}
[HttpPost]
public ActionResult SupplierDropUsed(int id)
{
SupplierModel sm = new SupplierModel();
List<Supplier> suppliers = sr.GetAll();
sm.Suppliers = (from s in suppliers
select new SelectListItem
{
Text = s.Name,
Value = s.Id.ToString()
}).ToList();
Supplier supplier = sr.GetById(id);
sm.Productlines = supplier.Productlines.ToList();
return View("List", sm);
}
}
The default action shows all productlines. SupplierDropUsed is called when dropdownlist is changed.
The view:
#model RyfMvcTestApplication1.Models.SupplierModel
#{
Layout = null;
}
List
<script type="text/javascript">
function supplierDropChanged() {
$.post("Productline/SupplierDropUsed", { id: $('#SupplierDrop').val() });
}
</script>
<div><strong>Filter by supplier</strong></div>
<br />
<div>
#Html.DropDownList("SupplierDrop", Model.Suppliers, "Select supplier", new { onChange = "supplierDropChanged()" })
</div>
<br />
<br />
<table>
<tr>
<th style="width:50px; text-align:left">Id</th>
<th style="text-align:left">Name</th>
<th style="text-align:left">Supplier</th>
</tr>
#foreach (var item in Model.Productlines) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Id)
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Supplier.Name)
</td>
</tr>
}
</table>
When I select a supplier, the javascript and controller action are executed (I checked in debug mode). I also get the correct supplier id. But the view is never refreshed. I still see the list with all productlines.
You're doing a post via the jquery post method which submits the request and that is why your debug action is called but that result that is returned from the post call is never used to update your UI.

Resources