Button Event in ASP.NET MVC - asp.net-mvc

I have created view page in MVC like
<%using (Html.BeginForm())
{ %>
<%=LabelHelpers.Label("firstname", "FirstName:")%>
<br/>
<%=Html.TextBox("firstname")%>
<br/><br/>
<%=LabelHelpers.Label("lastname", "Lastname:")%>
<br/>
<%=Html.TextBox("lastname")%>
<br/><br/>
<input type="Button" value="Register"/>
<%} %>
Here I want to write Buttonclick Event ...How and Where should i write?

Your input is of type button - these don't do anything without additional client side code.
If you want to handle the 'event' on the server in a similar way that you would have in ASP.NET, you should convert it to a submit button. Assuming your controller is called 'Account' and your action is called 'Register' your current code would look something like this:
public ViewResult Register()
{
return View();
}
You want to start by passing a model to the view:
public ViewResult Register()
{
var registerModel = new RegisterModel();
return View(registerModel);
}
Your current view is using loosely typed inputs. Since you're passing it a model you can use strongly typed views. Your model should look something like this:
public class RegisterMode
{
public string Firstname { get; set; }
public string Surname { get; set; }
}
To use strongly typed views, change your view to look like this:
<%using (Html.BeginForm())
{ %>
<%=Html.LabelFor(x => x.Firstname)%>
<br/>
<%=Html.TextBoxFor(x => x.Firstname)%>
<br/><br/>
<%=Html.LabelFor(x => x.Surname)%>
<br/>
<%=Html.TextBoxFor(x => x.Surname)%>
<br/><br/>
<input type="submit" value="Register"/>
<%} %>
What we've done is told the view to build labels and text boxes for your RegisterModel type. This will allow the model values to be automatically mapped when you POST the form to the controller.
Do accept the post, we need to add a new Action to the controller, with the same name, but accepting a parameter of type RegisterModel:
public ActionResult Register(RegisterModel model)
{
// do something with the model, such as inserting it into the database.
// model.Firstname will contain the value of the firstname textbox
// model.Surname will contain the value of the surnaem textbox
return RedirectToAction("Success");
}
One last thing to do, to be safe, is to add the [HttpGet] and [HttpPost] attributes to your controller actions to control the methods they accept:
[HttpGet]
public ViewResult Register()
and
[HttpPost]
public ActionResult Register(RegisterModel model)
I suggest you read up on MVC at http://www.asp.net/mvc and read the NerdDinner tutorial chapter in Professional MVC (available for free online in PDF format).

joining to the question, want to make it more concrete
i have a form, the form already has a submit button, but i need to bind an additional action to another button.
yes, i do know that MVC does not support events 'cause HTML forms doesn't support them.
so the solution i've came to is to create to hidden inputs inside the form and bind an 'onclick' event (jquery 'live' method) to every... oh, what the hell? here is the code:
html:
<input type="hidden" id="SenderControlID" name="SenderControlID" value="-1" />
<input type="hidden" id="SenderControlValue" name="SenderControlValue" value="-1" />
js:
if ($('#SenderControlID')[0]) {
$('input[type="submit"], input[type="button"], input[type="checkbox"], input[type="radio"]').live('click', function () {
$('#SenderControlID').val($(this).attr('name'));
$('#SenderControlValue').val($(this).val());
});
}
but maybe there is more elegant solution?

Related

Attaching a hidden text field to a form MVC

This very well may end up being a very silly question in a way but basically I have this "form" in a model that gets attached to my View as the form but I haven't been able to actually pass any data do it from the View. It only has two properties: an Id property and a String property. I've been trying to fill the String property with text from a hidden text box on the page with no luck.
Form code:
public class AllocateListForm
{
public int Id { get; set; }
public virtual string HiddenText { get; set; }
}
Relevant View code:
<% using (Html.BeginForm("SaveExit", "User", new { }, FormMethod.Post, new { id = "selectExitPoints" })) { %>
<fieldset>
<input type="hidden" id="HiddenText" />
</fieldset>
<% } %>
There is JQuery behind the scenes that fills HiddenText with text and I can assure you that it is filling. There is also JQuery behind the scenes that performs an Ajax submission and I can promise you that code works as it is used elsewhere in the application without a problem. When I perform the action that submits the form to the server and I go to my controller code that this points to, I have a breakpoint set so I can go into the console and check if the HiddenText field on the form has any data it is null. Can anybody point me in the right direction?
If you assign the input's name to be "HiddenText" the model binder should pick it up. I'm assuming that your controller action accepts an AllocateListForm as a parameter.
<input type="hidden" name="HiddenText" id="HiddenText" />
You can also use Html Helpers like so:
#Html.HiddenFor(model => model.HiddenText, new { id = "HiddenText" })
EDIT: Add an AllocateListForm as a property of your main model and then change the helper to be #Html.HiddenFor(model => model.MyAllocateListForm.HiddenText)
This should do the trick, if you want to do it the Razor-way.
#Html.HiddenFor(model => model.HiddenText);

Fields marked HiddenFor not binding to Model in MVC4

I have implemented an image upload child action form for an application. I have a strongly typed partial view.
public class ImageViewModel{
public long ImageId{get;set;}
public long OwnerId{get;set;}
public string ImageName{get;set;}
public string ImageDescription{get;set;}
public IEnumerable<HttpPostedFileBase> Files { get; set; }
}
Razor code looks something like this:
<form action="UploadImage" method="post" enctype="multipart/form-data">
#Html.ValidationSummary()
#Html.HiddenFor(m => m.OwnerId)
#Html.HiddenFor(m => m.ImageId)
#HtmlEditorFor(m=>m.ImageName)
<input type="file" name="Files" id="file0" />
<input type="submit" value="Upload" />
</form>
Here is the problem. When form is posted back, the model has uploaded file and ImageName value in it. But values that were bound using HiddenFor are missing.
[HttpPost]
public ActionResult UploadImage(ImageViewModel model)
{ ...}
I have checked HTML source. Hidden fields are rendered corrected with Id and names matching to property named of model. On post back I checked the raw request. Both hidden fields are carried in Form collection. But model binding is not setting the values of these fields in properties.
Is there something that I am missing about these hidden fields?
Thanks

Can't figure out why model is null on postback?

I'm new to ASP.NET MVC and I'm trying to create a very simple blog type site as a means of learning how everything works. But, I'm having a problem when posting from a comment form to a model which is null and I can't tell why.
On a blog post page, I have an "add comment" link which calls some JQuery to render a partial view that is strongly typed to the CommentModel. The link passes in the ID of the blog post as well and the partial is coded like:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Blog.Models.CommentModel>" %>
<% using (Html.BeginForm())
{ %>
<%: Html.HiddenFor(x => x.Post.ID) %>
<%: Html.HiddenFor(x => x.CommentID) %>
<%: Html.TextBoxFor(x => x.Name) %><br />
<%: Html.TextBoxFor(x => x.Email) %><br />
<%: Html.TextBoxFor(x => x.Website) %><br />
<%: Html.TextAreaFor(x => x.Comment) %><br />
<input type="submit" value="submit" />
<% } %>
The CommentsModel is simple and looks like this (I haven't applied any validation or anything yet):
public class CommentModel
{
public BlogPost Post { get; set; }
public int CommentID { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Website { get; set; }
public string Comment { get; set; }
}
This is then supposed to post to a simple controller action which will add the comment to the database and return the user to the page. For the sake of simplicity, I've stripped out most of the code but it looks similar to:
[HttpPost]
public ActionResult CommentForm(CommentModel model)
{
if (ModelState.IsValid)
{
}
else
{
}
}
Everything works as expected, except that when posting the comment form, the comment model is null. I can't figure out why this is null. When I view the source of the rendered partial view, I can see that the "Post.ID" is populated with the correct ID, but this is lost when the form is submitted.
Am I missing something obvious here? I've set up forms similar to this in the past and it's worked fine, I can't understand why its not now. Thanks in advance.
Later Edit:
I had typed the code incorrectly and changed the public ActionResult CommentForm(CommentModel model) from public ActionResult CommentForm(CommentModel comment) which was causing the problem.
Thanks for the help.
Similar kind of question has been answered yesterday. Check out : MVC3 - Insert using ViewModel - Object reference not set to an instance of an object
The problem I can see is , when the form is posted, the Post.ID and CommentID are passed, whereas your action is expecting a full blown object of type "CommentModel". The model binder is unable to map the post data, into the corresponding model object.
Add:
public int PostID {get; set;}
...to your model, and populate that in your controller as a hidden input. The Post object is not going to parse easily.

ASP.NET MVC - Form Returns Null Model Unless Model is Wrapped in a Custom ViewModel

I have a pair of views in my application that both display the same Editor Template for one of my model items; of the two views ("Add" and "Edit"), "Edit" works fine, but "Add" is returning null for the model when my controller action handles the post.
I found that if I give the "Add" view a custom ViewModel and call Html.EditorFor(p => p.PageContent) rather than simply calling the EditorFor() on the whole Model object- Html.EditorFor(p => p), then the form returns the correct, non-null model, but that generates other problems pertaining to my client-side scripting and control IDs (as now all of the fields are prefixed with "PageContent_"). I am using the same Editor Template technique in a few different places throughout my application and none of the others are exhibiting this odd dependency on a ViewModel.
Has anyone else ever experienced similar problems?
Edit View
<%# Page Title="" Language="C#" MasterPageFile="~/Areas/Admin/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<PageContent>" %>
<% using (Html.BeginForm())
{ %>
<%=Html.Hidden("PageID", Model.Page.ID) %>
<%=Html.EditorFor(p => p)%>
<input type="submit" name="btnSave" value="Save" />
<input type="submit" name="btnCancel" value="Cancel" class="cancel" />
<% }
Action (Working)
[HttpPost, ValidateInput(false)]
public ActionResult EditContent(int id, FormCollection formCollection) {}
Add View
<%# Page Title="" Language="C#" MasterPageFile="~/Areas/Admin/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<PageContent>" %>
<% using (Html.BeginForm())
{ %>
<%=Html.Hidden("PageID", ViewData["PageID"]) %>
<%=Html.EditorFor(p => p)%>
<input type="submit" name="btnSave" value="Save" />
<input type="submit" name="btnCancel" value="Cancel" class="cancel" />
<% } %>
Action (Failing)
// content is ALWAYS null
[HttpPost, ValidateInput(false)]
public ActionResult AddContent(PageContent content, FormCollection formCollection) {}
Before you cry "duplicate"
This question does relate to this one, but this question is intended to target the specific problem I am experiencing rather than the more general question asked there.
I tracked down the problem and it's a rather interesting one.
When the DefaultModelBinder attempts to resolve a model item one of the first things it does is check to see if there are any prefixed fields in the data being bound; it does this by checking for any form items that begin with the name of the model object (this seems extremely arbitrary, if you ask me). If any "prefixed" fields are found then it results in different binding logic being invoked.
ASP.NET MVC 2 Preview 2 BindModel() Source
public virtual object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {
if (bindingContext == null) {
throw new ArgumentNullException("bindingContext");
}
bool performedFallback = false;
if (!String.IsNullOrEmpty(bindingContext.ModelName) && !DictionaryHelpers.DoesAnyKeyHavePrefix(bindingContext.ValueProvider, bindingContext.ModelName)) {
// We couldn't find any entry that began with the prefix. If this is the top-level element, fall back
// to the empty prefix.
if (bindingContext.FallbackToEmptyPrefix) {
/* omitted for brevity */
};
performedFallback = true;
}
else {
return null;
}
}
// Simple model = int, string, etc.; determined by calling TypeConverter.CanConvertFrom(typeof(string))
// or by seeing if a value in the request exactly matches the name of the model we're binding.
// Complex type = everything else.
if (!performedFallback) {
/* omitted for brevity */
}
if (!bindingContext.ModelMetadata.IsComplexType) {
return null;
}
return BindComplexModel(controllerContext, bindingContext);
}
The controller action I defined to handle the Add action defines a PageContent item called "content" and in my domain PageContent has a property called "Content" which "matched" with the model name of "content" thus causing the DefaultModelBinder to assume I had a prefixed value when in fact it was simply a member of PageContent. By changing the signature-
from:
[HttpPost, ValidateInput(false)]
public ActionResult AddContent(PageContent content, FormCollection formCollection) {}
to:
[HttpPost, ValidateInput(false)]
public ActionResult AddContent(PageContent pageContent, FormCollection formCollection) {}
The DefaultModelBinder was once again able to correctly bind to my PageContent model item. I'm not sure why the Edit view didn't also display this behavior, but either way I've tracked down the source of the issue.
It seems to me that this issue falls very close to "bug" status. It makes sense that my view worked initially with the ViewModel because "content" was getting prefixed with "PageContent_", but a core framework feature/bug like this ought not be unaddressed IMHO.

ASP.NET MVC and Paging - Search & Result Scenario

I have forms in my page a get and a post and i want add pager on my get form .. so i cant page through the results..
The problem that i am having is when i move to the second page it does not display anything..
I am using this library for paging ..
http://stephenwalther.com/Blog/archive/2008/09/18/asp-net-mvc-tip-44-create-a-pager-html-helper.aspx
this my actions code.
[AcceptVerbs("GET")]
public ActionResult SearchByAttraction()
{
return View();
}
[AcceptVerbs("POST")]
public ActionResult SearchByAttraction(int? id, FormCollection form)
{....
}
and this is what i am using on my get form to page through
<%= Html.Pager(ViewData.Model)%> //but when i do this it goes to
this method
[AcceptVerbs("GET")]
public ActionResult SearchByAttraction()
instead of going to this this
[AcceptVerbs("POST")] public ActionResult SearchByAttraction(int? id, FormCollection form)
which sort of makes sence .. but i cant really think of any other way of doing this
Any help would be very appreciated..
Thanx
I'd recommend against doing paging via HTTP POST. Page and search criteria are 2 perfect examples of what querystrings are meant for. Put those values in the query string & have that load up your action args.
Think about this. You can search google for "pies", navigate to page 14, copy the link and send it to your grandma. You can't do that when your paging/search only works with form posts.
Of course it will hit the GET version of SearchByAttraction because using this control you have a links as output.
So what you need to do:
1. make form on the page:
<form id="myForm" action="your/url" method="post">
<input type="hidden" name="page" />
<input type="hidden" name="your_param1" />
<input type="hidden" name="your_param2" />
<input type="hidden" name="your_paramN" />
</form>
2. make changes to pager - it should produce something like that:
<ul id="pager">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
3. add simple javascript function on the page:
<script language="javascript" type="text/javascript">
function submitMyForm(page) {
var form = document.forms["myForm"];
form.elements["page"].value = page;
form.submit();
return false;
}
</script>
And you will be able to hit the POST version, because clicking the link will submit your form on the server using POST request.
Thanx everyone i finally got it working .. just used one form .. and did something like this
Controller Actions
[AcceptVerbs("GET")]
public ActionResult SearchByAttraction()
{
return View();
}
public ActionResult Search(FormCollection form,int? id)
{
var info = _repository.ListByLocation(city, postal, pageIndex, 2);
return View("SearchByAttraction", info);
}
View
<% using (Html.BeginForm("Search", "Home", FormMethod.Get))
{ %>
so it calls the search method every time it does a post..
Try this:
[AcceptVerbs("GET")]
public ActionResult SearchByAttraction(int? id)
{
return View();
}
id should contain the page number you need to display.
If you lose form values using this approach then you'll need to change the Html.Pager method to render each action link as a form submit link.

Resources