ASP.NET MVC Html.BeginForm Problem - c#

I have a partial view:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<DomainModel.Entities.Product>" %>
<div class="item">
<h3><%= Model.Name %></h3>
<%= Model.Description %>
<% using (Html.BeginForm("AddToCart", "Cart")) { %>
<%= Html.Hidden("ProductID") %>
<%= Html.Hidden("returnUrl", ViewContext.HttpContext.Request.Url.PathAndQuery) %>
<input type="submit" value="+ Add to cart" />
<% } %>
<h4><%= Model.Price.ToString("c")%></h4>
</div>
And here is the html that gets rendered:
<div class="item">
<h3>Kayak</h3>
A boat for one person
<form action="" method="post">
<input id="ProductID" name="ProductID" type="hidden" value="1" />
<input id="returnUrl" name="returnUrl" type="hidden" value="/" />
<input type="submit" value="+ Add to cart" />
</form>
<h4>$275.00</h4>
</div>
Nothing happens when the submit button is clicked and I am pretty sure it's because the form action attribute has no value. Shouldn't BeginForm(action, controller) take care of rendering out the form action? What am I doing wrong?
EDIT
Code from CartController AddToCart action:
public RedirectToRouteResult AddToCart(Cart cart, int productID, string returnUrl)
{
Product product = productsRepository.Products.FirstOrDefault(p => p.ProductID == productID);
cart.AddItem(product, 1);
return RedirectToAction("Index", new { returnUrl });
}
EDIT 2
The view that renders the partial:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<% foreach (var product in Model) { %>
<% Html.RenderPartial("ProductSummary", product); %>
<% } %>
<div class="pager">
Page:
<%=Html.PageLinks((int)ViewData["CurrentPage"],
(int)ViewData["TotalPages"],
x => Url.Action("List", new { page = x, category = ViewData["CurrentCategory"] })) %>
</div>
</asp:Content>
EDIT 3
Routes:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
null, // don't need a name
"", // matches the root URL, i.e. ~/
new { controller = "Products", action = "List", category = (string)null, page = 1 } //Defaults
);
routes.MapRoute(
null, // don't need name
"Page{page}", // URL pattern, e.g. ~/Page683
new { controller = "Products", action = "List", category = (string)null }, // defaults
new { page = #"\d+" } // constraints: page must be numerical
);
routes.MapRoute(null,
"{category}",
new { controller = "Products", action = "List", page = 1 });
routes.MapRoute(null,
"{category}/Page{page}",
new { controller = "Products", action = "List" },
new { page = #"\d+" } // constraints: page must be numerical
);
}

It looks like you don't have a default route set up. BeginForm uses UrlHelper.GenerateUrl to match up the action/controller names to your route collection. So if you don't have a route that maps to AddToCart, then it can't generate a URL for it. Try adding this to the bottom of your routes:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Products", action = "List", id = "" }
);

This is from the main application example used in Steven Sanderson's excellent 'Pro ASP MVC Framework' book.
Funnily enough I made exactly the same mistake and omitted the final .MapRoute call given in the listing on page 130.
routes.MapRoute("Default", "controller}/{action}"
It was Johnny G's answer to this post that helped me to find my mistake as well.
Nice one Johnny!

Related

How do I set a click event in C#?

I am new to C# (my job is making me convert from JavaScript) and for some reason I cannot find a straightforward example of setting up a button that calls a method.
I am using C# ASP.NET MVC 2 with the ASPX view engine. This is not ASP.NET Web Forms.
My Index.aspx looks like:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Blogs
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Blogs</h2>
<button ID="btnBlog" onclick="blogging" runat="server">Blog</button>
</asp:Content>
and I have tried several ways of doing this; this last one being:
public event EventHandler blogging()
{
System.Diagnostics.Debug.Write("clicked");
}
Edit:
Ok so doing the button like:
<asp:Button ID="btnBlog" OnClick="blogging" runat="server" />
and method:
protected void blogging(object sender, EventArgs e)
{
System.Diagnostics.Debug.Write("clicked");
}
Tells me that blogging is undefined... how do I call blogging()?
If you meaning to call an action method from View then you might try to use one of the following examples below. When creating a link to a controller action in ASP.NET MVC, using the generic ActionLink method is preferable, because it allows for strongly typed links that are refactoring friendly.
Default: ActionLink:
#Html.ActionLink("Delete", "Delete", new { id = item.ID })
However, what if we want to have an image that links to an action? You might think that you could combine the `ActionLink` and Image and `Button` helpers like this:
Using Button:
<button onclick="location.href='#Url.Action("Index", "Users")';
return false;">Cancel</button>
(with parameters)
<button onclick="location.href='#Url.Action("Detail", "Admin",
new { Model.ProductID })';return false;">Detail</button>
or
<input type="button" title="Delete" value="Delete"
onclick="location.href='#Url.Action("Delete", "movies", new { id = item.ID })'" />
**Using Image:**
<a href="#Url.Action("Delete", "movies", new { id = item.ID })" title="Edit">
<img src="../../Content/Images/Delete.png" />
</a>

Problems with Html.BeginForm() asp.net MVC 2

I have a SearchController.cs in my controller folder, it has an Action named Index. My search folder has a view named Index
The following code is in my /Controller/SearchController
private TEAM2BooksDBEntities _db = new TEAM2BooksDBEntities();
[HttpPost]
public ActionResult Index(string SearchFor)
{
var query = _db.Books.Where(em => em.title.Contains(SearchFor)).ToList();
return View(query);
}
The following code is in my /Home/Index
<% using(Html.BeginForm("Index","Search")){ %>
<%= Html.TextBox("SearchFor") %>
<input type="submit" value="Submit" />
<% }%>
But no matter what I do when I hit the submit button it just reloads the current page. I want it to send the contents of the "SearchFor" box as a parameter to the Index action in the Search controller. How can I fix this?
I also suggest try to use this.
<% using(Html.BeginForm("Index","Search",FormMethod.Post)){ %>
<%= Html.TextBox("SearchFor") %>
<input type="submit" value="Submit" />
<% }%>
Try this inside your action :
string SearchFor= Request.Form["SearchFor"];

Load DropDownList from ViewData in MVC 2

I have the following View. This is the whole code of my view
<asp:Content ID="Content2" ContentPlaceHolderID="HeadContent" runat="server">
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
</asp:Content>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<div>
<table>
<tr>
<td>
<select id="clientDDL">
</select>
<% Html.DropDownList("clientDDL",
new SelectList((IEnumerable)ViewData["Clients"], "Code", "Name")); %>
</td>
</tr>
</table>
</div>
</asp:Content>
I use the next ViewData from my Model:
public static List<lookup> GetClients()
{
using (ModelDataContext data = new ModelDataContext(System.Configuration.ConfigurationManager.ConnectionStrings["ConnectionString"].ToString()))
{
List<lookup> retVal = new List<lookup>();
List<Client> lClient = data.Clients.Where(a => a.IsActive == true).ToList();
lClient = lClient.OrderBy(o => o.ClientName).ToList();
foreach (Client item in lClient)
{
retVal.Add(new lookup() { Code = item.ClientID.ToString(), Name = item.ClientName, });
}
return retVal;
}
}
This is my Controller:
public ActionResult ProcedureFilter()
{
ViewData["Clients"] = WorkflowModels.GetClients();
return View();
}
What did I miss? My DropDownList is still empty. Maybe i have to put some reference? Any suggestions please.
UPDATE:
The problem was ';' at the end of part <%= %>. The works code:
<%= Html.DropDownList("clientDDL",
new SelectList((IEnumerable)ViewData["Clients"], "Code", "Name")) %>
In the ASP.NET code you provided, 2 HTML select tags (or DropdownLists) are defined with the same id (cliendDDL) :
<select id="clientDDL"> <-- the first one
</select>
<% Html.DropDownList("clientDDL",
new SelectList((IEnumerable)ViewData["Clients"], "Code", "Name")); %> <-- the second one, Html.DropDownList generating a select under the hood.
Would it be possible that only the first one is displayed (the empty one) and the second remains hidden because of a missing character, changing your expected HTML generation routine (Html.DropDownList) into an Embedded Code Block?
Maybe instead of :
<% Html.DropDownList
it should be :
<%= Html.DropDownList or <%: Html.DropDownList
See here for <%:%> ASP.NET 4 syntax
Edited
Also the ";" end of line character is not needed and should be removed.
View Page:
"<%=Html.DropDownList("Description", New SelectList(ViewData("Description")), "--Select--")%>"
Contoller:
Function Purchase() As ActionResult:
Dim dataContext As New tblMVCDataContext
Dim teststr As String
Dim itemVar = From U In dataContext.Items Select U.Description
For Each tbItem In itemVar
teststr += tbItem + ","
Next
ViewData("Description") = teststr.Split(",")
Return View(itemVar)
End Function

View loop value doesn't change after first value

I have an ICollection<String> being passed to my view and I do a foreach to load a partial view. It loops through the correct number of times, however, the value it passes is the same and I know in the model that this is not the case.
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View("Index", new List<String>());
}
[HttpPost]
public ActionResult Index(List<String> txtValue)
{
return View("Index", txtValue);
}
}
View:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<List<String>>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Home
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<script type="text/javascript">
//Deletes the div the Control is in.
$(".delete").live("click", function () {
$(this).parent().remove();
});
//Adds the TextBoxes to divControls
function AddTextBox(Value) {
var elements = "<div><input name=\"txtValue\" type=\"text\" /><input type=\"button\" class=\"delete\" value=\"-\" /><br/></div>";
$("#divControls").append(elements);
}
</script>
<h2>Controls!!!</h2>
<input id="btnAdd" type="button" name="Refresh" value="+" onclick="AddTextBox()" />
<% using (Html.BeginForm())
{ %>
<input id="btnsubmit" type="submit" name="Submit" onclick="Submit" />
<div id="divControls">
<%
foreach (var text in this.Model)
{ %>
<%=Html.TextBox("txtValue", text, new { id = "Value", name = "txtValue" })%>
<% Html.RenderPartial("TextControl", text);
}
%>
</div>
<%
}
%>
</asp:Content>
TextControl.ascx
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<String>" %>
<div>
<%=Html.TextBox("txtValue", this.Model, new { id = "Value", name = "txtValue" }) %>
<input id="btn" type="button" class="delete" value="-" /><br/>
</div>
The values of the model passed from the controller to the view are correct, even when passed to the user control "TextControl" the value is correct, but when the Textbox displays they are all just the first value of the original model passed in.
Ex.
Model as List<String> { "1", "2", "3", "4" }
passed to the view, will iterate through each one correctly, passing the correct string to "TextControl" to create a Html.TextBox("name", this.Model). Everything on the debugging side appears correct, however, when it finishes all the textboxes are "1" (or the first value in the list).
Here's a link to my exact code: http://www.sendspace.com/file/sypl1u
Note:
I came up with a solution of just using <input type="text" name="txtValue" value="<%= this.Model %>" /> instead.
Potential issue: you are using ElementAt which is LINQ method that fave special behavior for IList argument, but you are passing in txtValue as result of some query. In this case ElementAt may case sequence to be enumerated multiple times and may even fail if sequence can't be re-enumerated.
Consider simple foreach on the collection instead:
foreach (var text in Model)
{
Html.RenderPartial("TextControl", text);
}

Where is the erroneous "Id" coming from?

I'm experimenting with the MVC beta 2 and have the following method in a controller:
[HttpPost]
public ActionResult Create(Issue issue) {
if(TryUpdateModel(issue, "Model", new [] {"Title", "Description"})) {
ServiceCaller.PutIssue(issue);
return RedirectToAction("Index");
}
return RedirectToAction("Create");
}
TryUpdateModel always fails and ModelState has an error under a Key called "Id" which says that "A value is required". The View contains no Id input field and I understood that my "include" argument on the TryUpdateModel should have ignored anything other than the explicitly included fields anyway. Changing the method signature to the following fixes the problem but I'd like to understand how the "Id" field is getting included in the first place.
public ActionResult Create([Bind(Exclude = "Id")]Issue issue)
For completeness, here's the View (it's a shared view in the EditorTemplates folder):
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Tracker.Processing.Model.Issue>" %>
<% using (Html.BeginForm(Model.Id > 0 ? "Edit" : "Create", "Issue", FormMethod.Post)) { %>
<p>
<%= Html.LabelFor(i => i.Title) %>
<%= Html.EditorFor(i => i.Title) %>
</p>
<p>
<%= Html.LabelFor(i => i.Description) %>
<%= Html.TextArea("Description", Model.Description, new{ style = "width: 100%;" }) %>
</p>
<p>
<input type="submit" value="Save" />
</p>
<% } %>
Any ideas?
Its attempting to match the Id in the route to the one on your object
as the one in the route is null and the Id on your object is not nullable you get the error
Irritating isn't it

Categories