ASP.Net MVC - Helper lambdaexpression post action - asp.net-mvc

I created this helper method using a lambdaexpression to used strongly type helper in a view
Helper
public static string DateFor<TModel, TDate>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TDate>> expression)
{
ModelMetadata data = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
StringBuilder sb = new StringBuilder();
...
//code that creates three dropdownlist (day, month and year)
...
}
view
<%= Html.LabelFor(model => model.DataNascita) %>
Controller
[HttpPost]
public ActionResult Edit(int id, Account MyAccount)
{
...
return View(...);
}
my problem is that the MyAccount.DataNascita is not set with the value i choose in the Edit form (date's value minimun.. ex. 1900/01/01).
how to bind it in a Edit post action?

I think what you are after is a custom ModelBinder that will parse the incoming posted data and convert it into a DateTime for your model.

In your view, you say that you are outputting a Label for something, but your question concerns why the value isn't kept on posting.
I think you need to, at least, say Html.EditorFor(...), but you probably want to use the helper method you wrote:
<%: Html.DateFor(model => model.DataNascita) %>
However, it is impossible to say exactly what is going on here without knowing the data type of the DataNascita property on the model.

I suggest you use Jquery Datepicker.
You can customize it with Jquery Themeroller.

Related

Pass an entire model on form submission

I understand that I can use #Html.HiddenFor(m => m.parameter) and when the form is submitted, that parameter will be passed to the controller. My model has many properties.
Is there a shorter way of passing the entire model at once to the controller or must I do it one by one each time?
The model will be passed to the controller in its entirety, but the values of properties that are not bound by input or hidden fields will be lost.
You have to either bind the properties in the form on the client-side, or re-fetch the entity on the server-side.
You seem to be asking for something like #Html.HiddenFor(m => m.Model), and that is not possible. Sorry
One thing to keep in mind, if you have tons of hidden fields, you may be sending more data to the view than you really need. Consider employing view models
For anyone else who looks at this you can do a #Html.EditorForModel() in a hidden div. You'd also have to use #Html.EditorFor(model => model.ObjectProperty) for each object property of the model.
<div hidden="hidden">
#Html.EditorForModel()
#Html.EditorFor(model => model.ObjectProperty)
#Html.EditorFor(model => model.ListOfObjectsProperty)
</div>
The entire model will be posted if you are using a FORM element. Your elements using the Model obviously need to be inside the form element
You can also POST the form yourself say by using JQuery
See this other stack issue for that : jQuery AJAX submit form
Have a close look at the anwser by "Alfrekjv"
This is already built in. Consider this model:
public class MyModel
{
public string PropertyA { get; set; }
public string parameter { get; set; }
}
and now consider this action:
[HttpPost]
public ActionResult PostSomeData(MyModel model)
{
}
MVC will leverage the FormCollection and fill in the MyModel class where it can. If you don't have the PropertyA in the form then it will be null. But since you have an input for the parameter property it will be filled in.
You can check only the properties you want:
if (this.ModelState.IsValidField("Name"))
{
// .....
}
instead of:
if (this.ModelState.IsValid)
{
// .....
}
#using (Ajax.BeginForm("my_function", "my_controller", new AjaxOptions { InsertionMode = InsertionMode.Replace }, mymodel))

Hiddenfor not getting correct value from view model

I have a multi-step file import process. I have a hidden form input in my view that I am trying to populate with the "CurrentStep" from the view model.
<% = Html.HiddenFor(model => model.CurrentStep) %>
CurrentStep is an Enum and I always get the default value rather than the one I provided to the view model. on the other hand this gets me the correct value:
<p><% = Model.CurrentStep %></p>
I realise I could just hand code the hidden input but I want to know: what am I doing wrong? Is there a better way to keep track of the current step between POSTs?
What you are doing wrong is that you are trying to modify the value of a POSTed variable in your controller action. So I suppose you are trying to do this:
[HttpPost]
public ActionResult Foo(SomeModel model)
{
model.CurrentStep = Steps.SomeNewValue;
return View(model);
}
and html helpers such as HiddenFor will always first use the POSTed value and after that the value in the model.
So you have a couple of possibilities:
Remove the value from the modelstate:
[HttpPost]
public ActionResult Foo(SomeModel model)
{
ModelState.Remove("CurrentStep");
model.CurrentStep = Steps.SomeNewValue;
return View(model);
}
Manually generate the hidden field
<input type="hidden" name="NextStep" value="<%= Model.CurrentStep %>" />
Write a custom helper which will use the value of your model and not the one that's being POSTed
My solution was to use Darin's second option, because option 1 (clearing from the model state) means hard coding a string (and the naming convention can be tricky with complex models), and wanted to avoid option 3 because I already have so many custom helpers.
<input type="hidden" name="#Html.NameFor(x => Model.SomeId)" value="#Model.SomeId" />
Just a reminder that you can use Html.NameFor to keep things clean.
Make sure you model property has a "set" operator.
This won't get updated on post-back:
#Html.HiddenFor( m => m.NoSeq)
public Class MyModel
{
int _NoSeq;
public NoSeq
{
get { return _NoSeq };
}
}

Binding, Prefixes and generated HTML

MVC newbie question re binders. Supposing I have two strongly typed partial actions that happen to have a model attributes with the same name, and are rendered in the same containing page i.e.:
Class Friend {string Name {get; set ;} DateTime DOB {get; set ;}}
Class Foe {string Name {get; set ;} string ReasonForDislike {get; set ;}}
Both partials will have a line:
<%= Html.TextBoxFor(model => model.Name) %>
And associated controller actions:
public ActionResult SaveFriend(Friend friend)
public ActionResult SaveFoe(Foe foe)
My problem is that both will render on my containing page with the same id (of course, bad for lots of reasons). I’m aware of the [Bind] attribute that allows me add a prefix, resulting in code:
public ActionResult SaveFriend([Bind(Prefix = “friend”)] Friend friend)
<%= Html.TextBox("friend.Name", Model. Name) %> //Boo, no TextBoxFor :(
But this still doesn’t cut it. I can just about tolerate the loss of the strongly typed TextBoxFor helpers but I’ve yet to get clientside validation to work with prefixes:
I’ve tried:
<%= Html.ValidationMessage("friend.Name") %>
...and every other variant I can think of.
I seem to need the model to be aware of the prefix in both directions but bind only applies when mapping the inbound request. It seems (to me) a common scenario but I’m struggling to find examples out there. What am I missing!
Thanks in advance.
The prefix is there so you can wrap your objects in an "outer" ViewModel.
Suppose we have:
public class MyViewModel
{
public Friend friend;
public Foe foe;
}
If you use this class as your ViewModel and as the base of your strongly-typed Views, then your strongly-typed Textboxes will be named thusly:
friend.Name
foe.Name
You can then use the Prefix attribute you refer to in your question to disambiguate between your Friend and Foe classes.

Edit and Create view using EditCreate.ascx partial in ASP.NET MVC

If you look at the NerdDinner example of creating and editing dinners then you see they use a partial (ViewUserControl or ASCX) DinnerForm to put the functionality of creating and editing dinners into one file because it is essential the same and they use it using RenderPartial("DinnerForm").
This approach seems fine for me but I've run into a problem where you have to add additonal route values or html properties to the Form tag.
This picks up the current action and controller automatically:
<% using (Html.BeginForm()) { %>
However, if I use another BeginForm() overload which allows to pass in enctype or any other attribute I have to do it like this:
<% using ("Create", "Section", new { modal = true }, FormMethod.Post, new { enctype = "multipart/form-data" }))
and as you can see we lose the ability to automatically detect in which View we are calling RenderPartial("OurCreateEditFormPartial"). We can't have hardcoded values in there because in Edit View this postback will fail or won't postback to the right controller action.
What should I do in this case?
What about adding the following HTML helpers:
public static MvcHtmlString CurrentAction(this HtmlHelper htmlHelper)
{
return htmlHelper.ViewContext.RouteData.Values["action"];
}
public static MvcHtmlString CurrentController(this HtmlHelper htmlHelper)
{
return htmlHelper.ViewContext.RouteData.Values["controller"];
}
Then you could go something like this:
<% using (Html.CurrentAction, Html.CurrentController, new { modal = true }, FormMethod.Post, new { enctype = "multipart/form-data" }))
Its not 100% perfect but you could also add an additional HTML helper which would streamline it a little more:
public static MvcForm BeginForm(this HtmlHelper htmlHelper, object routeValues, FormMethod method, object htmlAttributes)
{
return htmlHelper.BeginForm(Html.CurrentAction, Html.CurrentController, routeValues, method, htmlAttributes);
}
Let me know if this helps.
Cheers
I'm answering in an old thread because it came up number two on a Google search whilst I was looking for the same thing :) Found on this SO post:
Html.BeginForm and adding properties
With MVC3 (not sure about MVC2) you can pass null in for the action and controller and get the default routes that BeginForm() would use.
#Html.BeginForm(null, null, FormMethod.Post, new { enctype="multipart/form-data"})
Cheers!

MVC form action

I have a edit View - Product/Edit/1
1 being the Id of the Product.How can I set the action of the edit post in the View to the POST edit action
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int Id, FormCollection collection)
The form tag is prepopulated as
but I want to set it to /Product/Edit/1
I am using this
<%using (Html.BeginForm()){ %>
but know its not right.Can someone help me how to set the form action using the htmlhelper class extension method to the Url in the browser
If you look at the intellisense for creating a Form with the HtmlHelper you will see there are parameters for specifying routeValues (of type object). Here you can specify the ID.
Your Edit View will be strongly typed with your Product object so you can specify Model.ID.
<% using (Html.BeginForm("Edit", "Product", new { Id = Model.ID } %>
...

Resources