Request.Forms.Keys.Count = 0 on Postback - asp.net-mvc-3

I have the following HTML on my displayed form
<fieldset>
<legend>Edit User Roles</legend>
<ul>
<% foreach (string role in (string[]) ViewData["roles"]){ %>
<li>
<div id="Div4" class="grid_6">
<div id="Div5" class="grid_2 alpha" style="font-weight: bold;">
<%= Html.CheckBox("role." + role, Roles.IsUserInRole(Model.UserName, role))%>
</div>
<div id="Div6" class="grid_3 omega" style="font-family: Verdana; font-size: 10pt;">
<label for="role.<%: role %>">
<%: role %></label><br />
</div>
</div>
</li>
<% } %>
</ul>
</fieldset>
I have the following code in my Controller
[HttpPost]
public ActionResult EditUser( string id, bool approved )
{
int i = Request.Form.Keys.Count
foreach (string key in Request.Form.Keys)
{
if (key.StartsWith( "role." ))
{
// Do something
}
}
MembershipUser membershipUser = Membership.GetUser( id );
return View( membershipUser );
}
If I break the code and explore, I find that the Request.Form.Keys.Count = 0, although there should be at least 4 keys created with "role." as a prefix from four checkboxes displayed on the form.
What am I not understanding here?

Request.Form.Keys.Count = 0 could have two possible explanations:
No value was sent in the POST body
You used some special content type such as for example application/json instead of application/x-www-form-urlencoded (could happen if you play with AJAX)
I would recommend you using FireBug to see exactly what's contained in the POST request and if there are any values. You haven't shown the form definition neither how you are submitting it. If you are POSTing with AJAX maybe there's where the problem lies.
Here's an example of how a valid request might look like in FireBug:

Related

Using hidden fields during HTTP post for the reload of same page postback

I have a View where the User can leave a feedback comment in regards to the content video that is playing on the page. Using the following code I am able to manually enter the UserID and ContentID and it saves to the database without problem.
#using (Html.BeginForm("Screencast", "Media", FormMethod.Post, new { id = "form", enctype = "multipart/form-data" }))
{
<div class="row">
<div class="six columns">
<div class="row">
<div class="six columns">
#Html.LabelFor(c => c.FeedbackComment.UserID)
#Html.TextBoxFor(c => c.FeedbackComment.UserID)
</div>
<div class="six columns">
#Html.LabelFor(c => c.FeedbackComment.ContentID)
#Html.TextBoxFor(c => c.FeedbackComment.ContentID)
</div>
<div class="row">
<div class="twelve columns">
#Html.LabelFor(c => c.FeedbackComment.FeedbackString)
#Html.TextAreaFor(c => c.FeedbackComment.FeedbackString)
</div>
</div>
</div>
</div>
</div>
<input type="submit" value="Submit button" class="medium button bottom20"/>
}
However, when the user is on the page before the HTTP post I actually have the related variables in my Model called:
Model.User.UserID
Model.SelectedItem.ContentID
I want to pass these in as hidden fields but when I try to do either:
#HtmlHiddenFor(c => c.FeedbackComment.UserID, #Model.User.UserID)
#HtmlHiddenFor(c => c.FeedbackComment.ContentID, #Model.SelectedItem.ContentID)
or
#HtmlHidden("UserID",#Model.User.UserID)
#HtmlHidden("ContentID",#Model.User.UserID)
Then these values are returned null despite the values being populated before the post. I read about a workaround of putting the input tags in manually but when I did this the #Using.HtmlBeginForm was returning an error of not being set to an instance of an object
Can someone please help me to understand how I can pass these values to the same page using the values I have in the model prior to the post.
Given the following view model (partial):
public class YourViewModel
{
public User User { get; set; }
public SelectedItem SelectedItem { get; set; }
}
You can bind the these properties to a hidden form element. When you post back these properties will still contain their values.
#Html.HiddenFor(x => x.User.UserID)
#Html.HiddenFor(x => x.SelectedItem.ContentID)
Your action method:
public ActionResult YourActionMethod(YourViewModel viewModel)
{
// When you debug here you will see that the values are retained
}
I hope this helps.

ASP.NET MVC4 PartialView Not Being Rendered Inside Parent View

I'm trying to filter a list of entities and update the partial view on the page with the filtered data. The partial view is returning the correct model with the filtered data, but is not being rendered inside the parent page. Instead it is being rendered in "body" element of an empty HTML page. I've found many topics on this but even though I appear to be following their directions, I'm still having no luck. A fresh set of eyes from the community here may be a huge help.
#model PennLighting.ViewModels.LinecardViewModel
#{
ViewBag.Title = "Linecard";
}
<div class="linecard-head">
#using (Ajax.BeginForm("Index",
new AjaxOptions
{
UpdateTargetId = "linecard"
}))
{
#Html.EditorFor(model => model.Categories)
<div class="buttons">
<input type="submit" name="btnFilter" value="Filter" />
<input type="submit" name="btnShowAll" value="Show All" />
</div>
}
</div>
<div id="linecard">
#Html.Partial("Linecard")
</div>
#section Scripts
{
#Scripts.Render("~/bundles/jqueryval")
}
public ActionResult Index()
{
var viewModel = new LinecardViewModel();
viewModel.Categories = db.Categories
.OrderBy(c => c.Name).ToList();
viewModel.Manufacturers = db.Manufacturers
.OrderBy(m => m.Name).ToList();
return View(viewModel);
}
public ActionResult Index(string btnFilter, string[] selectedCategories)
{
var viewModel = new LinecardViewModel();
var selectedMfrs = new List<Manufacturer>();
if (btnFilter != null && selectedCategories != null)
{
var categoryIds = selectedCategories.Select(c => int.Parse(c)).ToArray();
if (categoryIds != null)
{
selectedMfrs = db.Manufacturers
.Where(m => m.Categories.Any(c => categoryIds.Contains(c.ID)))
.OrderBy(m => m.Name).ToList();
}
}
else
selectedMfrs = db.Manufacturers.OrderBy(m => m.Name).ToList();
viewModel.Manufacturers = selectedMfrs;
return PartialView("Linecard", viewModel);
}
<!DOCTYPE html>
<html>
<head>
<title>#ViewBag.Title</title>
#Styles.Render("~/Content/themes/base/css", "~/Content/css")
</head>
<body>
<div id="container" class="round-bottom">
<div id="header">
<div id="header-left">
<div id="logo">
<a href="#Url.Content("~/")">
<img src="#Url.Content("~/Content/Images/logo.png")" alt="Penn Lighting Associates" /></a>
</div>
</div>
<div id="header-right">
<ul class="nav">
<li>#Html.ActionLink("Home", "Index", "Home")</li>
<li>#Html.ActionLink("About", "Index", "About")</li>
<li>#Html.ActionLink("Linecard", "Index", "Linecard")</li>
<li>#Html.ActionLink("Events", "Index", "Events")</li>
<li>#Html.ActionLink("Gallery", "Index", "Gallery")</li>
<li>#Html.ActionLink("Contact", "Index", "Contact")</li>
<li><a href="http://oasis.pennlighting.com:81/OASIS/desk/index.jsp" target="_blank">
Customer Login</a></li>
</ul>
</div>
</div>
<div id="main">
#RenderBody()
</div>
</div>
<div id="footer">
<p>
Copyright © 2008 Penn Lighting Associates</p>
</div>
#Scripts.Render("~/bundles/jquery")
#RenderSection("scripts",false)
</body>
</html>
So what am I missing? Thanks!
You cannot have 2 actions on the same controller with the same name accessible on the same HTTP verb. You might want to decorate your Index contorller action that is invoked with an AJAX call and returns a partial with the [HttpPost] attribute:
[HttpPost]
public ActionResult Index(string btnFilter, string[] selectedCategories)
{
...
}
Without seeing more of your solution, it's a bit fuzzy, but I believe you want to still return the Index and pass the model data into the Partial in your view. The way you are doing it would return only the partial view, which is why you're getting those results.
So in the filtered index:
return View(viewModel)
And in the index view, pass the data to the partial, which I assume without seeing has the right model association to display.
UPDATE
If you're looking to dynamically pull a subset of data and leave the rest untouched, then do an AJAX POST with the filter information to the action specified for the partial view. Take the data results and place them in the Linecard div.
There are many ways to send the data (bundle by JSON, serialize form, individual data points). Here are some examples:
http://brandonatkinson.blogspot.com/2011/01/using-jquery-and-aspnet-mvc-to-submit.html
MVC ajax json post to controller action method
The problem was that my jqueryval bundle was missing the jquery.unobtrusive-ajax.js file. My code works as is once that was included.

Is't possible to get access to <ul> and <li> during submiting form

I have view with controller. I would like to know if it is possible to get access to ul and li? I don't want to do ajax call and pass these elements as parameters. Li elements are added on client side dynamically. this.Request.Form show me only 'name' variable without 'list'. Any advices?
<form action="#Url.Action("Filter")" method="POST">
<ul data-role="listview" data-inset="true" data-filter="false" name="list">
#foreach (var item in #Model.Items)
{
<li value="#item">#item</li>
}
</ul>
<input type="text" name="name"/>
<inpu type="submit" value="Filter"/>
</form>
and controller:
[HttpPost]
public ActionResult Filter(string name, List<string> list)
{
// working with list
return RedirectToAction("Index");
}
thanks
No,
It is not possible to access <ul> and <li> on post back.
BTW, the following code is generates <li> on server not on client
#foreach (var item in #Model.Items)
{
<li value="#item">#item</li>
}
If you wish to access Items (#item) on server, there are other ways to get those that do not require access to <ul> or <li>
For instance, you can emit a hidden (#Html.HiddenFor) element in each <li> in your loop.
You can try the following.
I'm not sure what your view model looks like, but it seems like a list of string values? So then it will look like this in your view model:
public class YourViewModel
{
public List<string> Items { get; set; }
}
In your view try the following:
<ul>
#for (int i = 0; i < Model.Items.Count(); i++)
{
<li>
#Html.DisplayFor(x => x.Items[i])
#Html.HiddenFor(x => x.Items[i])
</li>
}
</ul>
When you post then these items should still be in the list.
It might not be a perfect solution but it can guide you on the right track.
I hope this helps.

ASP.NET MVC validation problem - data is not posted

I have the following class:
public class NewCommentClass
{
public string ActionName { get; set; }
public object RouteValues { get; set; }
[Required(ErrorMessage = "Comment Required")]
public string Comment { get; set; }
public int? CommentParentID { get; set; }
}
following code in view:
NewCommentClass newCommentClass = new NewCommentClass() { ActionName = "PostComment", RouteValues = new { id = ideaItem.Ideas.IdeaID } };
Html.RenderPartial("~/Views/Shared/NewComment.ascx", newCommentClass);
and NewComment.ascx:
<% # Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<NEOGOV_Ideas.Models.NewCommentClass>" %>
....
<div class="comment-new-container">
<div class="grid_1 alpha item-sidebar">
<p style="padding-top: 0.5em">
<a href="#">
<img src="<% = userAvatar %>" class="profile-photo" alt="Your Profile Picture" width="48"
height="48" /></a>
</p>
</div>
<div class="grid_8 omega">
<div class="comment-body">
<% using (Html.BeginForm(Model.ActionName, "Home", Model.RouteValues, FormMethod.Post, new { id = "FormAddComment", name = "FormAddComment" }))
{ %>
<fieldset>
<% = Html.TextAreaFor(model => model.Comment, htmlAttributes)%>
<% = Html.ValidationMessageFor(model=>model.Comment) %>
<input type="submit" value="<% = postButtonTitle %>" class="small blue awesome noborder" />
</fieldset>
<%} %>
</div>
</div>
<div class="clear">
</div>
</div>
and following post method in controller:
public ActionResult PostComment(int id, string Comment, int? CommentParentID, string referrerUrl)
{
...
}
but this validation does not work correctly.
If I enter data to textarea and click on "Submit" - all ok
But If I just click on "Submit" without data inside - got error message (it's correct), but when I enter data to textarea after this action - error message is hidden, but form is not submited!. If I add Html.ValidationSummary(true) - I one label is hidden, but second is shown.
Why so strange behaviour?
In your Html.BeginForm() command, you create an HtmlAttribute object, and you use it to set the name and id of your textarea to FormAddComment. Because this is the only field in the form, you would need to change your method signature as follows:
[HttpPost]
public ActionResult PostComment(string FormAddComment)
Your current signature doesn't receive anything from the posted form. If you use Fiddler or a similar tool to inspect what is being posted, you will see FormAddComment=[whatever was typed into the textarea] as the body of the POST sent from your browser.

MVC - Using Ajax to render partial view

I have this markup in an MVC app.
<div id="ingredientlistdiv">
<% Recipe recipe = (Recipe)Model; %>
<% Html.RenderPartial("IngredientsListControl", recipe.Ingredients); %>
</div>
<div id="ingrediententrydiv" align="left">
<% using (Ajax.BeginForm("Add Ingredient", "Recipes/UpdateStep2", new AjaxOptions { UpdateTargetId = "ingredientlistdiv" }))
{ %>
<p>
<label for="Units">Units:</label><br />
<%= Html.TextBox("Units", 0)%>
<%= Html.ValidationMessage("Units", "*")%>
</p>
<p>
<label for="Measure">Measure:</label><br />
<%= Html.TextBox("Measure")%>
<%= Html.ValidationMessage("Measure", "*")%>
</p>
<p>
<label for="IngredientName">Ingredient Name:</label><br />
<%= Html.TextBox("IngredientName")%>
<%= Html.ValidationMessage("IngredientName", "*")%>
</p>
<p>Save Ingredient</p>
<%= Html.Hidden("RecipeID", recipe.RecipeID.ToString())%>
<% } %>
</div>
When this runs the IngredientsListControl.ascx displayas a new page
in the browser and does not update the ingredientlistdiv.
This is my controller action
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult UpdateStep2(FormCollection form)
{
var factory = SessionFactoryCreator.Create();
using (var session = factory.OpenSession())
{
Recipe recipe = GetRecipe(session, Convert.ToInt32(form["RecipeID"]));
Ingredient ingredient = new Ingredient();
ingredient.UpdateFromForm(form);
ingredient.Validate(ViewData);
if (ViewData.ModelState.Count == 0)
{
recipe.Ingredients.Add(ingredient);
session.Save(recipe);
return PartialView("IngredientsListControl", recipe.Ingredients);
}
return Content("Error");
}
}
Am I doing the right thing on this line?
return PartialView("IngredientsListControl", recipe.Ingredients);
Is that how I render the control into the div so it does
not load new page.???
Malcolm
When you use this:
<a href="javascript:document.forms[0].submit()">
...you should be aware that it's not the same as
<input type="submit" />
It doesn't raise the onsubmit event, and MVC's AJAX eventhandler is not called.
To confirm this is the issue, add
<input type="submit" />
inside the form and try it out.
Finally, just call onsubmit() from your link
<a href="#" onclick="document.forms[0].onsubmit()">
Might be worth ensuring that you have correctly referenced the ajaxmvc and jquery scripts in your page (master page). If these are incorrect a new page will be displayed instead of the correct output in the target div.
RenderPartial takes an action name, not the name of the user control, so replace "IngredientsListControl" with "UpdateStep2", your action name.

Resources