Post Html table created by a model in MVC view to controller - asp.net-mvc

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

Related

Post item form IEnumerable<T>

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);
}

Data not loading on partial view, MVC

I am doing work on form where user can enter a customer record....View is scaffold with Create controller.
On 'Create' View, user can enter 'engineNo' to check its details which passes to another action "CheckRecord",,it can be seen from view...
<form>
<input type="text" id="enginNo" />
<input type="button" value="search" id="btnSearch" />
</form>
#using (Html.BeginForm("Index","Home",FormMethod.Get))
{
#Html.AntiForgeryToken()
<div id="info">
#{Html.RenderAction("CheckRecord","Sales");}
</div>
some create fields
}
The Create and "CheckRecord" actions are,,
public ActionResult Create()
{
ViewBag.CustomerId = new SelectList(db.CustomersDMs, "CustomerId", "Name");
ViewBag.SMClientBranchId = new SelectList(db.SMClientBranchesDMs, "SMClientId", "Name");
ViewBag.EngineNumber = new SelectList(db.StockDMs, "EngineNumber", "ChasisNumber");
return View();
}
public ActionResult CheckRecord(string enginNo)
{
var results = db.StockDMs.Where(c=>c.EngineNumber ==enginNo);
return PartialView("_part",results);
}
And my partialview,,,
#model IEnumerable<SM.CRM.AutosLoan.Models.Core.DomainModels.StockDM>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.AutoCompanyBrand.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.SMClientBranch.Name)
</td>
}
My problem is, the partial view is rendered correctly but the Model of partial view doesn't have value,,,Why is that, i am doing something wrong...Please help,,,Thanks for your time
(Posting this as answer since I mentioned it in comments and that's not the correct place)
Your action CheckRecord(string enginNo) takes an argument of enginNo, but you're calling it without any argument. That in turn means your db lookup will most likely not return any results, unless you get results on..
var results = db.StockDMs.Where(c => c.EngineNumber == null);
Make sure the action gets a valid argument, for example:
#{ Html.RenderAction("CheckRecord", "Sales", new { enginNo = "abc123" }); }

View passing wrong viewmodel

I've created a website using ASP.Net MVC5 (VS 2013) but I guess the same problem would present itself in MVC3 or MVC4
I have the following view:
#model IEnumerable<WilhanWebsite.Models.TestimonialViewModel>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Testimonial.Description)
</td>
<td>
#Html.DisplayFor(modelItem => item.Testimonial.Author)
</td>
<td>
#Html.DisplayFor(modelItem => item.Testimonial.Timestamp)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.Testimonial.TestimonialId }) |
#Html.ActionLink("Details", "Details", new { id=item.Testimonial.TestimonialId }) |
#Html.ActionLink("Delete", "Delete", new { id=item.Testimonial.TestimonialId })
</td>
</tr>
}
</table>
The Index action of my Testimonial controller sends back a List and the view displays existing testimonials correctly in the html table. My problem is that when I click the Edit hyperlink I get the following error:
The model item passed into the dictionary is of type
'WilhanWebsite.DomainClasses.Testimonial', but this dictionary
requires a model item of type
'WilhanWebsite.Models.TestimonialViewModel'
I was previously using DomainClasses.Testimonial as the model passed between controller an view but today I refactored to create the new dedicated view model. It seems strange that the view is happy to process the new viewmodel when displaying the data so why is it passing the old DomainClasses.Testimonial when I click the Edit link?
Any help greatly appreciated!
The View expects #model IEnumerable<WilhanWebsite.Models.TestimonialViewModel> so you have to return it from the Controller's Index action method. Without seeing your controller I would guess that your returning a List of type Testimonial rather than a List of Type TestimonialViewModel
// GET: /Testimonial/
public ActionResult Index()
{
List<TestimonialViewModel> testimonialViewModel = new List<TestimonialViewModel>();
// Add some testimonials to your list.
return View(testimonialViewModel);
//NOT THIS - IT WILL THROW THE ERROR YOUR GETTING
return View(db.Testimonial.ToList());
}
//Testimonial/Index
#model IEnumerable<WilhanWebsite.Models.TestimonialViewModel>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
Alternativly if you are returning a System.Collection and TestimonialViewModel is specified. Make sure that its implements IEnumerable. The following types do.
ICollection
IDictionary
IDictionaryEnumerator
IEnumerable
IEnumerator
IHashCodeProvider
IList
I was able to fix by updating the Edit action to the following:
public ActionResult Edit(int id)
{
var query = from t in _context.Testimonials
where t.TestimonialId == id
select t;
TestimonialViewModel tvm = new TestimonialViewModel();
tvm.Testimonial = query.First();
return View(tvm);
}

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
}

refreshing / reloading the PartialView inside the current view

I have a PartialView that is an image upload, and basically I am displaying some images and then the normal Upload buttons :-
#model MvcCommons.ViewModels.ImageModel
<table>
#if (Model != null)
{
foreach (var item in Model)
{
<tr>
<td>
<img src= "#Url.Content("/Uploads/" + item.FileName)" />
</td>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
</tr>
}
}
</table>
#using (Html.BeginForm("Save", "File", FormMethod.Post, new { enctype = "multipart/form-data" })) {
<input type="file" name="file" />
<input type="submit" value="submit" /> <br />
<input type="text" name="description" />
}
Now my idea is to have this in different pages. I tried it in 1 page already and is working fine, however when I Upload an image,
public ActionResult ImageUpload()
{
ImageModel model = new ImageModel();
model.Populate();
return View(model);
}
I want to go back to the "previous" View, ie the View that is hosting this partial view? When I do return View(model) as above, I get into the ImageUpload partial view which I do not want to.
Thanks for your help and time.
***UPDATE*********
I went for the simple route for the time being, and hard coded the actual View name
public ActionResult ImageUpload()
{
ImageModel model = new ImageModel();
model.Populate();
return View("~/Views/Project/Create.cshtml", model);
}
however I got an error :-
The model item passed into the dictionary is of type MvcCommons.ViewModels.ImageModel, but this dictionary requires a model item of type MvcCommons.Models.Project.
Use the overload that takes a string of the name of the view you want.
http://msdn.microsoft.com/en-us/library/dd460310
protected internal ViewResult View(
string viewName,
Object model
)
i.e.
return View("ViewName", model);
if you have this in different pages then you can inject context via the action paramaters;
public ActionResult ImageUpload(string parentViewName)
{
ImageModel model = new ImageModel();
model.Populate();
return View(parentViewName, model);
}
NOTE: You should only need to pass the views name not the path:
return View("Create", model);

Resources