Second model in same view not posting to controller - asp.net-mvc

With the help of several SO questions, I've figured out how to use two models on the same view, using the tuple form. At the top of my file is this:
#using Project.Models;
#{
ViewBag.Title = "Details";
Layout = "~/Views/Shared/_Layout.cshtml";
#model Tuple<Foo, Bar>
}
For the Foo stuff, it uses jQuery like this:
#Html.DisplayFor(tuple => tuple.Item1.ID)
and works fine. However, for my second model, it isn't displaying info, but is a submission form. Currently, this is what I have:
#using (Html.BeginForm(null, null, FormMethod.Post, new { id = "createFoo", #action = "/api/Foo" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div class="editor-field">
#Html.TextAreaFor(tuple => tuple.Item2.Text)
#Html.ValidationMessageFor(tuple => tuple.Item2.Text)<br />
</div>
<input type="submit" value="Post Response" />
}
Mind you, this is mostly copy paste from other views since I'm new to MVC and it worked fine with other forms. For my FooController, I have this:
public void Post([FromBody] Foo foo)
{
Foo existingFoo = this.fooRepository.GetFoo(foo.ID);
if (existingFoo != null)
{
// throw error
}
else
{
System.Diagnostics.Debug.WriteLine("MESSAGE POSTING: " + foo.Text);
}
}
When submitting from the view, the received foo isn't null (checked in other tests), but the foo.text is empty. I've tried lots of different inputs and such, but I'm just so unfamiliar with the #Html.* functions and ASP.net-MVC in general that I'm not sure where I could be going wrong.
If you need to see my repository code let me know, but I doubt it'd have an effect on this. Thanks in advance for any help.

There are 2 issues I can see with your code above:
The way the Html helper will output your fields and how that feeds into your api post
Not having your ID in the controller.
1: Outputting a field like this (#Html.TextAreaFor(tuple => tuple.Item2.Text)) will give the field the name "Item2.Text". This is an issue as that is what gets passed on the post. You will get form data with Item2.Text:dfsdsgdfg. This won't match when your API controller tries to bind. So, try outputting the text field with a set name:
#Html.TextArea("Text", #Model.Item2.Text)
2: Your Id field is not in the form... thus it won't be sent. Try using a hidden field:
#Html.Hidden("ID", #Model.Item1.ID)
Also, just a clarification, this (#Html.DisplayFor(tuple => tuple.Item1.ID)) is not jQuery.

Related

returning model back to view causes page to break with encType

I am inheriting a project which is somewhat built in Umbraco 6 and I am not familiar with Umbraco but learning thus far.
A partial view is using an existing template which effectively has this in its template:
#inherits Umbraco.Web.Mvc.UmbracoTemplatePage
#{
Layout = "MvcBanner.cshtml";
}
#section ContentPlaceHolderParent {
#Umbraco.RenderMacro("Breadcrumb")
#Umbraco.Field("pageName")
#Umbraco.Field("pageInstructions", insertBefore: "", insertAfter: "", convertLineBreaks: true)
#Html.Action(#Umbraco.Field("MVCActionName").ToString(), #Umbraco.Field("MVControllerName").ToString())
}
This template is being used by a page "UploadJobs.cshtml"
Now, on the UploadJobs.cshtml I have a few fields bound to a model and then a file upload:
#model Models.JobsModel
#using(Html.BeginUmbracoForm("UploadJobs", "Jobs"))
{
#Html.TextBoxFor(m => m.Name);
#Html.TextBoxFor(m => m.Files, new { type = "file", name = "Files" })
<input type="submit" value="Upload" id="cmdSubmitJobs" />
}
My action method looks like this:
[HttpPost]
[ValidateAntiForgeryToken]
public PartialViewResult UploadJobs(UploadJobs model)
{ ... }
When submitting, everything seems fine but when returning the model back to the view (i.e validation fails), it seems to break the page completely when rendering (i.e all styles and all formatting is gone) and any javascript//jquery functions I have returns errors when the document is being rendered
thoughts? I want to be able to obviously return the model if it is invalid
Ahmed,
your problem is probably because of you are redirecting to the partialview not the view itself. Double check your flow, the partial page is most likely called from another view (parent one). This parent view contains all required styling stuff within it.

ASP.NET MVC: Html Helper Form Seems to be Incorrect

all, I could use your help again. I'm currently attempting to use an HTML helper to create a from that will pass my model into the Operations controller's method, TaskEdit, seen below:
[HttpPost]
public ActionResult TaskEdit(TaskViewModel viewModel, bool? embedded)
{
// code
}
In the view, I am using the following Razor code to attempt to produce the form:
#using (Html.BeginForm("TaskEdit", "Operations", new { embedded = true, viewModel = Model }, FormMethod.Post, new { #class = "form-horizontal" }))
{
// form code
}
This didn't actually give me my instance of the model - it only passed the class back as if it were a static class. So I tried the following instead:
#using (Html.BeginForm("TaskEdit", "Operations", new { embedded = true, id = Model.TaskId }, FormMethod.Post, new { #class = "form-horizontal" }))
{
// form code
}
And the following form was produced (which confused me):
<form action="/<sitename>/Operations/TaskEdit/0?embedded=True" class="form-horizontal" method="post"> <!-- Form code --> </form>
Not only was I assuming that the form action would be more along the lines of "/<sitename>/Operations/TaskEdit?id=0&embedded=True", but when I try to submit the form, I get a server error about "No parameterless constructor defined for this object." Help?
A transcription from the comments:
The reason the URL results in /TaskEdit/0 is because of the way your routing is setup. You'll notice the route also defines an id which causes it to format it different than expected.
The best solution here is to use a strongly typed view:
1) Put your model on top of the view (#model TaskViewModel)
2) Remove the model parameter from your form
3) Use the built-in extensions to create form fields (Html.EditorFor(x => x.SomeField)) or use the field names if you're doing it manually: <input type="text" name="SomeField />
4) The model parameter in your controller's actionresult will now contain the form data

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);

Passing parms to Controller from View with Html.BeginForm

I have two simple questions that I am hoping someone could answer... It's been asked several times on the web, but I cannot find a post that clearly state what I need below...
question 1:
How do you get the values from the View to pass to the Controller where the values already exist on the View? In other words, I need the #loanID value. This value is a textbox on the form and is not part of the model.
<label for="txtLoanID">Loan ID :</label>
#(Html.Kendo().IntegerTextBox()
.Name("txtLoanID")
.Placeholder("Enter LoanID")
)
#using (Html.BeginForm("GeneratePDF", "Home", new { #loanID = loanID }, FormMethod.Post))
question 2:
How can I pass multiple values using the above line to the Controller, specifically, a dropdownlist text value which is also not part of the model.
The textbox should be in the form so it gets posted back by it.
#using (Html.BeginForm("GeneratePDF", "Home", FormMethod.Post)) {
<label for="txtLoanID">Loan ID :</label>
#Html.Kendo().IntegerTextBox().Name("txtLoanID").Placeholder("Enter LoanID")
}
then your controller should be able to get it through model binding
public ActionResult GeneratePDF(int txtLoadID)
{
}

Losing ViewModel Data after POST

I don't see this problem too often but I've got a .cshtml that uses a layout. In the layout I've got:
#using (Html.BeginForm(null, null, FormMethod.Post, new { #class = "someCssClass", #id = "UserForm" }))
{
...rest of the code
}
My main .cshtml using this layout has the model defined at the top as we always do:
#model CarViewModel
#{
Layout = "~/Views/Shared/_CarLayout.cshtml";
}
When It gets back to my action method, I get nulls for all values of the model:
public ActionResult Cars(CarViewModel model)
{
carBL.RemoveCars(model.CarIds, model.DealerId);
...
}
Not sure what I need to do here and why this is happening. Usually I just get it back successfully via autobind. It seems to me when the model is used via RAzor in the markup- that gets posted back fine with the returned ViewModel but if I'm not using those fields, it doesn't...so I assume that's how that works and if I don't use them in mark-up I need to send them back as hidden values then to force the persistence since I am not using x fields from the ViewModel (Which would have automatically persisted those fields if I had used them in the form)?
If the values are not bound to a form field, they will come back null.
in the form use the below for things like ID fields.
#Html.HiddenFor(x => x...)
A quick test, to see if the form is being posted correctly would be to modify the signature of your action:
public ActionResult Cars(FormCollection form)
{
...
}
If form is not populated then you have an issue with the form post. As a side, note you could accomplish this when reviewing the post data of the form with a tool like FireBug, Chrome Dev tools or Fiddler if you prefer.
If the form is posting correctly, then I you should check to make sure the name's of the input fields on the form align with the names of the CarViewModel you are expecting.
Not sure if this has been resolved yet, but this is how I do it (partial code):
#model MyProject.ViewModels.MyViewModel
#using (Html.BeginForm())
{
<table>
<tr>
<td>First Name:</td>
<td>#Html.TextBoxFor(x => x.FirstName, new { maxlength = "50" })
#Html.ValidationMessageFor(x => x.FirstName)
</td>
</tr>
</table>
<button id="btnSave" type="submit">Save</button>
<button id="btnCancel" type="button">Cancel</button>
}
Then my action method to handle the HTTP post request:
[HttpPost]
public ActionResult Create(MyViewModel viewModel)
{
// Check for null on viewModel
// Do what needs to be done
}
Doing it this way should not let you loose your values filled in on the form/view.

Resources