Using MVC3 and Ajax.BeginForm I surprisingly discovered that mvc ajax forms submits elements with the attribute disabled="disabled".
I have tested both select and text inputs.
I was suprised because they should not be submited and they will not when using Html.BeginForm.
Is there some hidden option or a workaround for this?
[EDIT example]
#using (Ajax.BeginForm("Action", "Control", new AjaxOptions() { HttpMethod = "POST" }))
{
<input type="text" name="_enabled" value="_enabled" />
<input type="text" name="_disabled" value="_disabled" disabled="disabled" />
<input type="submit" value="POST" />
}
Html.BeginForm will not post the _disabled value.
you can set disabled element value in other hidden element:
<input type="text" name="Id" id="Id" value="5" />
<input type="hidden" name="Id" id="Id" value="5" />
and or :
#Html.TextBoxFor(m => m.Id)
#Html.HiddenFor(m => m.Id)
Related
I'm writing an MVC website in C# with razor syntax.
I have some code here:
#using (Html.BeginForm("DoSignUp", "SignUpController", FormMethod.Post))
{
<input type="text" width="3000" value="" name="Name" />
<input type="submit" value="Register" /
}
So this form should post to the SignUpController on the DoSignUp method. Instead of doing that it just posts back to the page I'm currently on which is called SignUp. I suspected there might be something wrong with my routing but when I look at the html that is being generated through the browser developer tools i see this:
<form action="" method="post">
<input type="text" width="3000" value="" name="selectedURL">
<input type="submit" value="Register">
</form>
Edit: Well I wrote this out and then looked at my code again. The problem which I keep bloody doing is that SignUpController should just be SignUp.
Remove the 'Controller' from your controller name (SignUp, not SignUpController). It's assumed to be a controller by convention
#using (Html.BeginForm("DoSignUp", "SignUp", FormMethod.Post))
{
<input type="text" width="3000" value="" name="Name" />
<input type="submit" value="Register" /
}
I am doing my first ASP.NET mvc project, on the home page, Index.cshtml, I have a small form:
<form action="ChoixFormulaire" method="get">
<fieldset>
<label>NAS</label>
<input id="nas" type="text" placeholder="###"/>
<br />
<label>Date of birth</label>
<input id="date" type="text" placeholder="AAAA-MM-JJ"/>
<br />
<label>Employee number</label>
<input id="numEmployee" type="text" placeholder="######"/>
<br />
</fieldset>
<input type="submit" value="Soumettre" onclick="return VerifierFormulaire()" />
</form>
When the button is clicked, there is some verification made in the 'VerifierFormulaire()' method, which is defined in the same Index.cshtml file. Then the ChoixFormulaire.cshtml is displayed (called from the ChoixFormulaire() method in my HomeController, which returns View()).
I was expecting the form inputs to be in the URL as parameters. For example, If I enter '123' for NAS, '1989-01-01' for date of birth and '123456' for employee number, I am redirected to http://localhost:15778/Home/ChoixFormulaire? but I would expect to be redirected to http://localhost:15778/Home/ChoixFormulaire?nas=123&dateBirth=1989-01-01&numEmployee=123456
Try adding the name attribute:
<input id="nas" name="nas" />
I am using Steve Sanderson's BeginCollectionItem helper and ran into a problem. I have a form that has an option to add unlimited reward fields. I am using his helper since it solved this problem with how to keep generating the fields and not have to worry about how to bind it when the form gets submitted.
I have in this same form some checkboxes that there is an unknown amount. The difference with this one versus the rewards is the unknown amount will become known after a database call and will be known by the time the code gets to the view.
So my code looks like this
public class FrmVm
{
public Guid Id { get; set; }
public string Name { get; set; }
public bool Active { get; set; }
public IList<WarrantyFeaturesVm> WarrantyFeaturesVm { get; set; } // this is the checkbox ones.
public IList<RewardVms> RewardVms { get; set; } // this is the dyanmic one that I needed the helper for
public CbCreditCardFrmVm()
{
Active = true;
WarrantyFeaturesVm = new List<WarrantyFeaturesVm>();
RewardVms = new List<RewardVms>();
}
}
// view
#foreach (var tier in Model.RewardVms)
{
#Html.Partial("GenerateReward", tier) // in this partial view in the BeginCollectionItem
}
#foreach (var warranties in Model.WarrantyFeaturesVm)
{
using (Html.BeginCollectionItem("WarrantyFeaturesVm"))
{
<span>#warranties.Name:</span>
#Html.TextBoxFor(x => warranties.FeatureId)
#Html.CheckBoxFor(x => warranties.HasFeature)
}
}
I am using jquery to submit the data by using serializeArray(). When it goes to the server it bind all the dynamic ones correctly and even binds the Warranty to the Collection(the collection count is 1). Yet it never binds anything insides the WarrantyFeaturesVm, everything is left as default.
if I remove using (Html.BeginCollectionItem("WarrantyFeaturesVm")) then it won't even bind the collection.
Anyone know why it is not binding anything in the collection?
Edit
// for loop (works)
<form method="post" id="" action="" class="ui-formwizard ui-helper-reset ui-widget ui-widget-content ui-corner-all" novalidate="novalidate">
<span id="" class="step ui-formwizard-content ui-helper-reset ui-corner-all" style="display: none;">
<input type="hidden" value="6aa20677-d367-4e2a-84f0-9fbe00deb191" name="WarrantyFeaturesVm[0].FeatureId" id="WarrantyFeaturesVm_0__FeatureId" data-val-required="The FeatureId field is required." data-val="true" class="ui-wizard-content ui-helper-reset ui-state-default"> <span>Purchase</span>
<input type="checkbox" value="true" name="WarrantyFeaturesVm[0].HasFeature" id="WarrantyFeaturesVm_0__HasFeature" data-val-required="The HasFeature field is required." data-val="true" class="ui-wizard-content ui-helper-reset ui-state-default"><input type="hidden" value="false" name="WarrantyFeaturesVm[0].HasFeature" class="ui-wizard-content ui-helper-reset ui-state-default">
</form>
//foreach loop beginItemCollection(does not work)
<form method="post" id="" action="" class="ui-formwizard ui-helper-reset ui-widget ui-widget-content ui-corner-all" novalidate="novalidate">
<span id="" class="step ui-formwizard-content ui-helper-reset ui-corner-all" style="display: inline;">
<input type="hidden" value="68ba9241-c409-4f4b-96da-cce13b127c1e" autocomplete="off" name="WarrantyFeaturesVm.index" class="ui-wizard-content ui-helper-reset ui-state-default">
<input type="hidden" value="6aa20677-d367-4e2a-84f0-9fbe00deb191" name="WarrantyFeaturesVm[68ba9241-c409-4f4b-96da-cce13b127c1e].war.FeatureId" id="WarrantyFeaturesVm_68ba9241-c409-4f4b-96da-cce13b127c1e__war_FeatureId" data-val-required="The FeatureId field is required." data-val="true" class="ui-wizard-content ui-helper-reset ui-state-default"> <span>Purchase</span>
<input type="checkbox" value="true" name="WarrantyFeaturesVm[68ba9241-c409-4f4b-96da-cce13b127c1e].war.HasFeature" id="WarrantyFeaturesVm_68ba9241-c409-4f4b-96da-cce13b127c1e__war_HasFeature" data-val-required="The HasFeature field is required." data-val="true" class="ui-wizard-content ui-helper-reset ui-state-default"><input type="hidden" value="false" name="WarrantyFeaturesVm[68ba9241-c409-4f4b-96da-cce13b127c1e].war.HasFeature" class="ui-wizard-content ui-helper-reset ui-state-default">
</span>
</form>
//for loop beginItemCollection (does not work)
<form method="post" id="" action="" class="ui-formwizard ui-helper-reset ui-widget ui-widget-content ui-corner-all" novalidate="novalidate">
<span id="" class="step ui-formwizard-content ui-helper-reset ui-corner-all" style="display: none;">
<input type="hidden" value="fe3fbc82-a2df-476d-a15a-dacd841df97e" autocomplete="off" name="WarrantyFeaturesVm.index" class="ui-wizard-content ui-helper-reset ui-state-default">
<input type="hidden" value="6aa20677-d367-4e2a-84f0-9fbe00deb191" name="WarrantyFeaturesVm[fe3fbc82-a2df-476d-a15a-dacd841df97e].WarrantyFeaturesVm[0].FeatureId" id="WarrantyFeaturesVm_fe3fbc82-a2df-476d-a15a-dacd841df97e__WarrantyFeaturesVm_0__FeatureId" data-val-required="The FeatureId field is required." data-val="true" class="ui-wizard-content ui-helper-reset ui-state-default"> <span>Purchase</span>
<input type="checkbox" value="true" name="WarrantyFeaturesVm[fe3fbc82-a2df-476d-a15a-dacd841df97e].WarrantyFeaturesVm[0].HasFeature" id="WarrantyFeaturesVm_fe3fbc82-a2df-476d-a15a-dacd841df97e__WarrantyFeaturesVm_0__HasFeature" data-val-required="The HasFeature field is required." data-val="true" class="ui-wizard-content ui-helper-reset ui-state-default"><input type="hidden" value="false" name="WarrantyFeaturesVm[fe3fbc82-a2df-476d-a15a-dacd841df97e].WarrantyFeaturesVm[0].HasFeature" class="ui-wizard-content ui-helper-reset ui-state-default">
</span>
<span id="adminSettings" class="step ui-formwizard-content ui-helper-reset ui-corner-all" style="display: inline;">
</form>
Ok I think I see what is going on here.
In the second sample, where you did the foreach, it looks like your cshtml was something like this (# symbols may be incorrect):
foreach (var war in Model.WarrantyFeaturesVm) {
using (Html.BeginCollectionItem("WarrantyFeaturesVm")) {
Html.HiddenFor(m => war.FeatureId)
<span>#Html.DisplayFor(m => war.Name)</span>
Html.HiddenFor(m => war.HasFeature)
}
}
Because BeginCollectionItem uses its context to derive the HTML names and id's, this is why you end up with "war" in the id's and names. The model binder is looking for a collection property named "WarrantyFeaturesVm", which it finds. However it is then looking for a property named "war" on the WarrantyFeaturesVm viewmodel, which it cannot find, and thus does not bind.
<input type="hidden" value="6aa20677-d367-4e2a-84f0-9fbe00deb191"
name="WarrantyFeaturesVm[68ba9241-c409-4f4b-96da-cce13b127c1e].war.FeatureId"
id="WarrantyFeaturesVm_68ba9241-c409-4f4b-96da-cce13b127c1e__war_FeatureId" .../>
In the 3rd scenario, it is similar. It is looking for the WarranyFeaturesVm collection property, which it finds. It however looks for another collection item.
<input type="hidden" value="6aa20677-d367-4e2a-84f0-9fbe00deb191"
name="WarrantyFeaturesVm[fe3fbc82-a2df-476d-a15a-dacd841df97e].WarrantyFeaturesVm[0].FeatureId"
id="WarrantyFeaturesVm_fe3fbc82-a2df-476d-a15a-dacd841df97e__WarrantyFeaturesVm_0__FeatureId" .../>
In order to bind correctly, your HTML has to look similar to your first HTML example:
<input type="hidden" value="68ba9241-c409-4f4b-96da-cce13b127c1e"
name="WarrantyFeaturesVm.index" .../>
<input type="hidden" value="6aa20677-d367-4e2a-84f0-9fbe00deb191"
name="WarrantyFeaturesVm[68ba9241-c409-4f4b-96da-cce13b127c1e].FeatureId"
id="WarrantyFeaturesVm_68ba9241-c409-4f4b-96da-cce13b127c1e__FeatureId" .../>
Like I hinted in my comment, you can achieve this by putting the BeginCollectionItem and everything it wraps into a partial view. The partial view will then receive its own context, since your helpers will use the view's #Model property with the stongly-typed helpers like so: #Html.WidgetFor(m => m.PropertyName).
On the other hand, if you really need the collection to be rendered in the outer view, I don't see any problem using normal indexing (integer-based) with a for loop and without BeginCollectionItem.
Update
I dug up this old post from Phil Haack. An excerpt:
...by introducing an extra hidden input, you can allow for arbitrary
indices. In the example below, we provide a hidden input with the
.Index suffix for each item we need to bind to the list. The name of
each of these hidden inputs are the same, so as described earlier,
this will give the model binder a nice collection of indices to look
for when binding to the list.
<form method="post" action="/Home/Create">
<input type="hidden" name="products.Index" value="cold" />
<input type="text" name="products[cold].Name" value="Beer" />
<input type="text" name="products[cold].Price" value="7.32" />
<input type="hidden" name="products.Index" value="123" />
<input type="text" name="products[123].Name" value="Chips" />
<input type="text" name="products[123].Price" value="2.23" />
<input type="hidden" name="products.Index" value="caliente" />
<input type="text" name="products[caliente].Name" value="Salsa" />
<input type="text" name="products[caliente].Price" value="1.23" />
<input type="submit" />
</form>
BeginCollectionItem uses this indexing method to make sure the model binding happens. The only difference is it uses Guids instead of ints as the indexer. But you could manually set any indexer like in Phil's example above.
I have the following razor code:
<form id="logon" action="/security/dev" method="get">
#Html.AntiForgeryToken()
#Html.EditorFor(x => x.UserName)
#Html.EditorFor(x => x.Password)
<input type="submit" value="Login" name="Login" />
<input type="submit" value="Cancel" name="Cancel" />
</form>
when getting the precompiled version to output the generated html I get the following:
<form id="logon" action="/security/dev" method="get">
<input name="__RequestVerificationToken" type="hidden" value="vTyswnqonYMzGeewLrLSJ9XySz1A0PR0nvyVu58458J/nftXtxBPIVoQEdfr3MzEYPDLBPcGvXtMkOTujsou/x3eJVfdt2YSJgxUfu6AxMLj23kTwUNQo7X8ec7twsbt8U2BdogpHy0fSGq1nMljlukM9fGZ/770JLijcpJXx4o=" />
/* EditorTemplates/String */
/* EditorTemplates/Password */
<input type="submit" value="Login" name="Login" />
<input type="submit" value="Cancel" name="Cancel" />
</form>
Anyone have any idea why it would do that? Here is a failing example: skydrive file
Cheers
w://
Apparently this is not part of the expected output.
I had similar problem with EditFor. Using TextBoxFor instead helped me.
Can any one help me in passing the parameters to the worldpay site using mvc http post , below is the example which i found on google , the example is working on view , but I want to pass the parameters through http[post] action controller :
<form method="post" action="https://secure.wp3.rbsworldpay.com/wcc/purchase" id="frmWorldPay">
<input type="hidden" name="instId" value="1" />
<input type="hidden" name="cartId" value="<%: Model.CardID %>" />
<input type="hidden" name="currency" value="GBP" />
<input type="hidden" name="amount" value="<%= Model.Cost%> " />
<input type="hidden" name="desc" value="<%: ViewBag.Name %> track day" />
<input type="hidden" name="email" value="<%: Model.aspnet_Users.aspnet_Membership.Email %>" />
<input type="hidden" name="name" value="<%: Model.FullName %>" />
<input type="hidden" name="address" value="<%: Model.Address %>" />
<input type="hidden" name="testMode" value="100" />
Have a look at System.Net.WebClient.
Also this question on SO may help you further.
edit
You should follow the links I posted. There you find i.e. this example code
using System;
using System.Text;
using System.Net;
using System.Collections.Specialized;
//...
string url = "http://www.amazon.co.uk/exec/obidos/search-handle-form";
NameValueCollection formData = new NameValueCollection();
formData["field-keywords"] = "Harry Potter";
// add more form field / values here
WebClient webClient = new WebClient();
byte[] responseBytes = webClient.UploadValues(url, "POST", formData);
string response = Encoding.UTF8.GetString(responseBytes);
Console.WriteLine(response);