.net MVC RenderPartial renders information that is not in the model - asp.net-mvc

I have a usercontrol that is rendering a list of items. Each row contains a unique id in a hidden field, a text and a delete button. When clicking on the delete button I use jquery ajax to call the controller method DeleteCA (seen below). DeleteCA returns a new list of items that replaces the old list.
[HttpPost]
public PartialViewResult DeleteCA(CAsViewModel CAs, Guid CAIdToDelete)
{
int indexToRemove = CAs.CAList.IndexOf(CAs.CAList.Single(m => m.Id == CAIdToDelete));
CAs.CAList.RemoveAt(indexToRemove);
return PartialView("EditorTemplates/CAs", CAs);
}
I have checked that DeleteCA is really removing the correct item. The modified list of CAs passed to PartialView no longer contains the deleted item.
Something weird happens when the partial view is rendered. The number of items in the list is reduced but it is always the last element that is removed from the list. The rendered items does not correspond to the items in the list/model sent to PartialView.
In the usercontrol file (ascx) I'm using both Model.CAList and lambda expression m => m.CAList.
How is it possible for the usercontrol to render stuff that is not in the model sent to PartialView?
Thanx
Andreas

It sounds like the ModelState is the trouble here, as you bind to CAs the ModelState save this values in the background as Attempted Values, so its true the object is no longer present at the Model, but the ModelSate still have the values of the deleted object. You can try a:
ModelState.Clear();
To remove all those old values.

Check in firebug what the response realy is. This way you can see if you have a serverside problem or it is a jquery issue.

Related

MVC nested model collection is empty (not null)

I have a model that has a property which is a collection. I can successfully bind from the edit actions, for example:
[HttpGet]
public ActionResult Edit(string id)
{
// code here
return this.View(complexModel);
}
[HttpPost]
public ActionResult Edit(ComplexModel complexModel)
{
// code here
return RedirectToAction("AnotherAction")
}
In the post method I can successfully receive all the object properties, including the collection one. However I have another view that can invoke the Edit action. When this happens I can see that the html rendered is the same (i.e. the nested property info is there). When I save the changes in the post Edit I receive all the correct properties with one exception - the collection propery has zero items.
Where do I have to search for the problem?
Update:
I am properly iterating through the collection and displaying all items with EditorFor; however when coming from a differnt view (the different view is in another controller and the Edit link is placed in a Display Template - if that makes any difference) with the same exact model I can see that the html is the same since all the properties of the collection are there.
Ok, false alarm. I figured it out - I am invoking the action method using #Html.ActionLink; I was passing the whole model instead of just the id. I do not know for what silly reason things got messed up, but they are ok now.
What does your Edit view look like? You need to iterate over all the items in the collection as form elements.

asp.net mvc reading html table/cell values in the controller

My application needs to do an HTTP post of a table with checkboxes like in the image above. On the controller side I will need to traverse the table and perform certain operations for each row that was checked.
The things that I need to do are:
Identify whether a row is checked
Get the cell values of a checked row
I have a good understanding on how this will be done in Razor in as far as posting the form is concerned. But I am clueless once I am in my controller's action method.
Please help. Thanks.
From what you've show, it appears that all you really need in your action method is a collection of ids to identify which "rows" to modify. I'd use a series of checkboxes with values set to the id of the row they represent. Presumably you have some sort of persistence mechanism in which these rows can be looked up or have them cached server side.
[HttpPost]
public ActionResult Update( List<int> rowIDs ) // where your checkboxes are named rowIDs
{
var messages = DB.Messages.Where( m => rowIDs.Contains( m.ID ) );
foreach (var message in messages)
{
// process the update
}
DB.SaveChanges();
return RedirectToAction( "index" ); // display the updated list
}
Note that it's more likely that you have a model with the collection of ids as well as some other data representing what "update" to perform. Posting collections can be tricky; you might need to play with the name of the input and/or with hidden indexes if you're not getting all the data posted back as expected.

ASP.NET MVC Dropdownlist retain the selected value in the browser after post

I build a drop down list in my aspx page as following
<%= Html.DropDownList("SelectedRole", new SelectList((IEnumerable)Model.roles, "RoleId", "RoleName", Model.SelectedRole), "")%>
it works fine for first Get and the first default value is selected; then I select item from the drop down list and submit the form.
the controller bind the values correctly,
public ActionResult About([Bind] Roles r)
{
//r.SelectedRole = the selected value in the page.
//Roles r = new Roles();
r.roles = new List<Role>();
r.roles.Add(new Role(1, "one"));
r.roles.Add(new Role(2, "two"));
r.roles.Add(new Role(3, "three"));
r.roles.Add(new Role(4, "four"));
r.SelectedRole = null;
return View(r)
}
Then I nullify the selected item and return my view, but still the previous selected Item is selected (although I did nullify it)
Any Idea if I am doing something wrong or it is a bug in MVC?
I am using ASP.NET MVC 1
Thanks
This is the normal behavior of all html helpers: they will look at the POSTed values to perform the binding. This means that you cannot change the value in your controller action and expect it to reflect on the view if you use the standard helpers. If there's a value SelectedRole in the POST it will always be this value used and the last parameter of the drop down completely ignored.
You could write your own helper to achieve this or redirect after the POST.

asp.net mvc: What is the correct way to return html from controller to refresh select list?

I am new to ASP.NET MVC, particularly ajax operations. I have a form with a jquery dialog for adding items to a drop-down list. This posts to the controller action.
If nothing (ie void method) is returned from the Controller Action the page returns having updated the database, but obviously there no chnage to the form. What would be the best practice in updating the drop down list with the added id/value and selecting the item.
I think my options are:
1) Construct and return the html manually that makes up the new <select> tag
[this would be easy enough and work, but seems like I am missing something]
2) Use some kind of "helper" to construct the new html
[This seems to make sense]
3) Only return the id/value and add this to the list and select the item
[This seems like an overkill considering the item needs to be placed in the correct order etc]
4) Use some kind of Partial View
[Does this mean creating additional forms within ascx controls? not sure how this would effect submitting the main form its on? Also unless this is reusable by passing in parameters(not sure how thats done) maybe 2 is the option?]
UPDATE:
Having looked around a bit, it seems that generating html withing the controller is not a good idea. I have seen other posts that render partialviews to strings which I guess is what I need and separates concerns (since the html bits are in the ascx). Any comments on whether that is good practice.
look at the ContentResult you can specify the mime type of what you return (text/html)
You could alternatively make a control that take a IEnumerable of whatever you put in the selectlist, and build it using the view engine. That way you keep the formatting of the html (in this case a list of options) into a view, and not in your code.
<%# Control Language="C#"Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Article>>"%>
<%foreach (var article in Model){%>
<option><%:article.Title %></option>
<%} %>
I think I would go for that second one
From what I understood, the jQuery dialog contains a form that, when submitted, will post to an action which updates the database with some information. You want to get the newly added database information and update the same form that was used to trigger the database update.
If that is the case, then I think the best clean and logical option is to return JSON serialization of the items to be put in the drop down right after you update the database. Then, using jQuery, you would clear the drop down and append option tags into it.
You can also write a new, seperate action that returns the JSON serialization of the database objects you need. You would have jQuery call another post to this action as a callback to your first ajax post (the one used to update the database).
Here is a quick snippet
public ActionResult UpdateDatabase(string something)
{
/// update the database
IEnumerable<Items> items = getItemsFromDatabase(); // or w/e
var vals = items.Select(x=> new { value = x.ID, text = x.Name }); // something similar
return Json(vals);
}
Personally, I would write a separate function that returns JSON. This ensure separation of concerns, and gives me a function I can use in many different places.
Returning a JsonResult with all the items is the most versatile and least-bandwidth intensive solution as long as you are happy to iterate through the list in jQuery and update your drop-down list.
Using a partial view is nice for HTML that you can .load(...) directly into your select, but less versatile.
I would go with the JsonResult.
In your Controller:
public JsonResult UpdateItem(string sItem)
{
// 1. Insert new item into database if not exist...
// {update code here}
// 2. retrieve items from database:
IEnumerable<Item> Items = GetItems();
// 3. return enumerable list in JSON format:
return new JsonResult{ Data = new {Items = Items, Result = "OK" }};
}
On client-side:
Iterate through Items array and add the items to your list.

ASP.NET MVC - How to get checkbox values on post

Hey all, this is a newbie ASP.NET MVC question.
I have a view that has a list of checkboxes and a submit button. On submit it posts to a controller method but I can't figure out how to get the values of the checkboxes. Also, I can't figure out how to get model data that I passed into the view when I'm in the post method, I tried using Html.Hidden but that didn't seem to work.
Here's the code:
http://pastebin.com/m2efe8a94 (View)
http://pastebin.com/m39ebc6b9 (Controller)
Thanks for any input received,
Justin
First thing I noticed is that your hidden fields need to be inside your form. Currently in your view, they are above the BeginForm, so they won't be included in the form submission.
To get the values of the selected check boxes, add an IsOffered parameter to your OfferTrade Action method.
public ActionResult OfferTrade(FormCollection result, List<string> IsOffered)
That parameter will contain a list of the ItemId's for all the checked IsOffered boxes.
The HtmlHelper's CheckBox works differently and I don't like the way it works, so I don't use it.
Making the IsOffered parameter type List<int> should also work if your ItemId field is an integer.
First of all your ItemId and UserId is outside your form:
<%= Html.Hidden("ItemId", Model.ItemIWant.ItemId) %>
<%= Html.Hidden("UserId", Model.ItemIWant.UserId) %>
//...
<% using (Html.BeginForm()) {%>
Secondly you could try to make your Controller action method use "model binding" (if this is also called model binding)
public ActionResult OfferTrade(int ItemId, int UserId, IList<string> IsOfferred)
Edit Just noticed you are not using the HtmlHelper CheckBox so your list will contain only selected items, but a point still:
You might want to look into Phil Haacks post on Model Binding To A List, but there is a small change to this in the RTM version of MVC:
You dont need the ".Index" hidden fields, but then the indexes in the Name fields must be zero-indexed and increasing (by 1).

Resources