Whenever I add Html.Hidden form in my Form Post it kills all the data in the Model.
Model -
public class ViewRemoveStep
{
[HiddenInput]
public PModel p { get; set; }
[HiddenInput]
public RemoveStep remvoveStep { get; set; }
}
Both fields in the model are models with several properties.
View -
#using (Html.BeginForm("RemovePStep", "PFilter", FormMethod.Post, new { #class = "form-horozontal" }))
{
#Html.HiddenFor(m => m.p.LOB)
<div class="form-group">
#Html.TextBoxFor(m => m.remvoveStep.p, new { #id = "p", #name = "p", #type = "text", #placeholder = "P", #class = "form-control" })
</div>
<div class="form-group">
#Html.TextBoxFor(m => m.remvoveStep.RemovedStep, new { #id = "RemovedStep", #name = "RemovedStep", #type = "text", #placeholder = "Remove multiple eg.(1,2,3)", #class = "form-control" })
</div>
<button class="btn btn-danger col-md-offset-4 center-block">Remove</button>
}
The ViewRemoveStep is coming into this view with the P already populated trying to get the RemoveStep populated from the form. No matter what if I add HiddenFor to the form, it posts a completely null model to the controller. Even the fields from the two typeable fields in the form are null. Take the hidden part away and the removestep fields return correctly, but the peril is null as you would expect.
Even if I use a HiddenFor on a string on the model its still returns all null. It's like using HiddenFor in anyway kills the entire model.
I can't figure out why.
EDIT
I've seen the same type of response twice now, and it doesn't seem to help. I changed my stuff to this
#using (Html.BeginForm("RemovePerilStep", "PerilFilter", FormMethod.Post, new { #class = "form-horozontal" }))
{
<div class="form-group">
#Html.TextBoxFor(m => m.removeStep.peril, new { #id = "removeStep.peril", #name = "removeStep.peril", #type = "text", #placeholder = "Peril", #class = "form-control" })
</div>
<div class="form-group">
#Html.TextBoxFor(m => m.removeStep.RemovedStep, new { #id = "removeStep.RemovedStep", #name = "removedStep.RemovedStep", #type = "text", #placeholder = "Remove multiple eg.(1,2,3)", #class = "form-control" })
</div>
#Html.HiddenFor(m => m.peril, new { #id = "peril", #name = "peril" })
<button class="btn btn-danger col-md-offset-4 center-block">Remove</button>
}
The matching names aren't making any difference.
You have to make the name of your DOM field match to the property of the model your controler is waiting for.
Actually, your input field has #name = "RemovedStep" and it doesn't match with the model.
In your Model you have public RemoveStep remvoveStep { get; set; } your name as to be something like #name = "remvoveStep.fieldName"
If you don't specify a name, it is generated with the good matching name.
#Html.TextBoxFor(m => m.remvoveStep.p, new { #id = "p", #name = "p", #type = "text", #placeholder = "P", #class = "form-control" })
you are setting the id and name = p, but in reality it should be removeStep.p
When the form post back ASP.NET sees a parameter called 'p' with text = something. So it tries to look for property p in your model and it sees that p is actually a PModel, but the text is just a string instead of a valid json so it just skips that property. Thus the model is null.
just do #Html.TextBoxFor(m => m.remvoveStep.p) and it should fix the problem
Related
I have an ASP.Net MVC 5 web application and I need to accept user input of US currency. Some valid inputs might be:
100
$100.21
$ 1,234
$1,234.56
Invalid inputs might be:
10,12
1o0.21
My (simplified) model looks like:
public class Claim {
[DisplayName("$ Amount)]
[DataType(DataType.Currency)]
[Required]
[Range(0.0, 200000.0)]
public decimal? DollarAmount { get; set; }
}
My cshtml markup looks like:
#Html.LabelFor(model => model.DollarAmount, htmlAttributes: new { #class = "control-label col-md-3" })
<div class="col-md-9">
#Html.EditorFor(model => model.DollarAmount, new { htmlAttributes = new { #class = "form-control margin-bottom" } })
#Html.ValidationMessageFor(model => model.DollarAmount, "", new { #class = "text-danger" })
</div>
I used this advice this advice to build a binder that converts user input to a decimal, but client-side validation won't let the user enter a dollar-sign or commas. What do I need to do to allow the user to enter valid currency values, but warns her if she enters an invalid value? I'd prefer to do as much validation on the client-side as possible.
You Might want to look at https://github.com/globalizejs/globalize#currency-module. Helps allot with this kind of stuff. As for your Question to be able to use the Dollar Symbol you would not be able to store this Value as a decimal format in the database, only as a string.
There are a few things you can do, Use bootstrap to place a Dollar symbol in front of your TextBox using input-group-addon. Not sure if it will work properly as i see you have set Margin-bottom on your Textbox, telling me you might not be using bootstrap form tags above.
You may want to look into AutoNumeric jQuery plugin, It's well-maintained and they've basically "thought of everything" I could want for currency.
// View
#Html.LabelFor(model => model.DollarAmount, htmlAttributes: new { #class = "control-label col-md-3" })
<div class="col-md-9 input-group">
<span class="input-group-addon">$</span>
#Html.EditorFor(model => model.DollarAmount, new { htmlAttributes = new { #class = "form-control margin-bottom" } })
#Html.ValidationMessageFor(model => model.DollarAmount, "", new { #class = "text-danger" })
</div>
// Class
public class Claim {
[DisplayName("$ Amount")]
[DataType(DataType.Currency)]
// {0:C} Will show as currency {0:N} to show Numbers
[DisplayFormat(DataFormatString = "{0:C}", ApplyFormatInEditMode = true))]
[Required]
[Range(0.0, 200000.0)]
public decimal? DollarAmount { get; set; }
}
Another option is to have a hidden field with javascript that will duplicate the field from a string to decimal and that can be the one you submit like below.
// MODEL
public class Claim {
[DisplayName("$ Amount")]
[DataType(DataType.Currency)]
[Required]
[Range(0.0, 200000.0)]
public decimal? DollarAmount { get; set; }
}
// View
#Html.HiddenFor(model => model.DollarAmount, new { #id = "DollarAmount" })
#Html.LabelFor(model => model.DollarAmount, htmlAttributes: new { #class = "control-label col-md-3" })
<div class="col-md-9 input-group">
<span class="input-group-addon">$</span>
<input id="DollarSave" type="text" name="DollarSave" pattern="^\$?([0-9]{1,3},([0-9]{3},)*[0-9]{3}|[0-9]+)(.[0-9][0-9])?$" title="You must enter in proper currency">
#Html.ValidationMessageFor(model => model.DollarAmount, "", new { #class = "text-danger" })
</div>
<script type="text/javascript">
jQuery(document).ready(function($){
$('#DollarSave').change(function(){
var sourceField = $("#DollarSave").val(); //source field key
$("#DollarAmount").val(sourceField); //destination field key
$("#DollarAmount").change(); //destination field key
});
});
</script>
Pool pro's answer was a great help in solving my problem but I couldn't get his input tag pattern to display a message. It worked in JSFiddles, but not in my Asp.Net view template. So, I did the pattern validation and message update in javascript. I also used a different regex. For completeness, I'm posting my solution here:
#Html.HiddenFor(model => model.DollarAmount, new { #id = "DollarAmount" })
#Html.LabelFor(model => model.DollarAmount, htmlAttributes: new { #class = "control-label col-md-3" })
<div class="col-md-9">
<input id="DollarSave" type="text" name="DollarSave" class="form-control text-box single-line">
<p id="BadDollarSave" class="text-danger"></p>
</div>
<script type="text/javascript">
jQuery(document).ready(function($){
$('#DollarSave').on('blur', function () {
validateDollarSave();
});
function validateMoney(inputId) {
var errorMsg = '';
var currency = $('#DollarSave').val();
var good = currency.match(/^(\$|\$ )?[0-9]{1,3}(?:(,[0-9]{3})*|([0-9]{3})*)(?:(\.|\.[0-9]{2}))?$/);
if (!good) {
errorMsg = "$ Amount must be US currency";
} else {
var num = currency.replace(/[, $]/g, "");
$('#DollarAmount').val(num);
}
document.getElementById('BadDollarSave').innerHTML = errorMsg;
};
});
</script>
I'm using C#/.NET in Visual Studio and the MVC framework.
I have a form that I'm working with, and I was able to get it to output the correct error message at the appropriate time. My issue is that the input field of the form is supposed to highlight red with a has-error class when the field is either not filled in or filled in incorrectly. I could do this if I was using regular form tags, but because this is connected to an Umbraco project, I have to use Html.EditorFor and Html.ValidationMessageFor.
Is there a way (either using jQuery or modifying the existing code) to add a class to the Html.EditorFor field upon Html.ValidationMessageFor deciding it should display the message?
Here is a portion of my View:
<div class="name-field">
<label>Name</label>
#Html.EditorFor(m => m.Name, new { htmlAttributes = new { #class = "form-control", #id = "contact_name", #name = "contact_name", #placeholder = "Name" } })
#if (#Html.ValidationMessageFor(model => model.Name) != null)
{
#Html.ValidationMessageFor(model => model.Name, null, new { #class = "contact-form-error-msg text-danger small-sized", #id = "contact-form-name-error-1", #style = "display:block;" })
}
</div>
and here is the attribute in my Model:
[Required(ErrorMessage = "Please enter a contact name.")]
public string Name { get; set; }
Like I said, the error message shown in the model is showing up correctly. My issue is just applying the has-error class to the Html.EditorFor field which I have a feeling is going to require jQuery; however, I'm not sure how to access the existing code in a jQuery block.
Thank you.
Edit: I was notified that my question could be a possible duplicate of the question here (How can I check if my model is valid from inside the razor view?). With some modification I was able to find the solution to my problem.
#if (!ViewData.ModelState.IsValidField("Name")) {
<div class="name-field has-error">
#Html.EditorFor(m => m.Name, new { htmlAttributes = new { #class = "form-control", #id = "contact_name", #name = "contact_name", #placeholder = "Name" } })
#if (#Html.ValidationMessageFor(model => model.Name) != null)
{
#Html.ValidationMessageFor(model => model.Name, null, new { #class = "contact-form-error-msg text-danger small-sized", #id = "contact-form-name-error-1", #style = "display:block;" })
}
</div>
} else {
<div class="name-field">
#Html.EditorFor(m => m.Name, new { htmlAttributes = new { #class = "form-control", #id = "contact_name", #name = "contact_name", #placeholder = "Name" } })
</div>
}
I'm trying to add a required to my TextAreaFor, but it won't give the error message when i post it. I'm trying to do it on the followinng line:
#Html.TextAreaFor(model => model.Content, new { htmlAttributes = new { #class = "form-control", required = "" } })
And this is my full code:
#using (Html.BeginForm("_Create", "Comments", FormMethod.Post))
{
#Html.HiddenFor(m => m.ThreadId)
<div class="form-group">
<div class="col-md-10">
#Html.TextAreaFor(model => model.Content, new { htmlAttributes = new { #class = "form-control", required = "" } })
#Html.ValidationMessageFor(model => model.Content, "", new { #class = "text-danger"})
</div>
</div>
<div class="form-group">
<div>
<input type="submit" value="Post" class="btn btn-default" />
</div>
</div>
}
If anyone wanst to do it with html attribute,
#Html.TextAreaFor(model => model.Content, new { required = "required", htmlAttributes = new { #class = "form-control"} })
You don't need required as a html attribute. It should be a data annotation on the model.
[Required]
public string Content { get; set; }
#Html.TextAreaFor(model => model.Content, new { htmlAttributes = new { #class = "form-control", required = "" } })
Should be:
#Html.TextAreaFor(model => model.Content, new { #class = "form-control", required = "required" })
Or if you want to explicitly name the parameter your anonymous object is for:
#Html.TextAreaFor(model => model.Content, htmlAttributes: new { #class = "form-control", required = "" } })
But, if you do not use data-annotation, it could be even easier this way:
<textarea id="Content" name="Content" required class="form-control">#Model.Content</textarea>
(id attribute may be optional, depending on your usages.)
Side note: I tend to minimize uses of html helpers methods. For me, MVC is also about letting you control very precisely the browser client code, which is imo better done by writing it yourself. WebForm is, on this subject, about hiding most of browser client code handling.
Using extensively html helpers, built-in validation logic, and so on, may cause you to lose the precise control of how your page should work.
This question already has answers here:
The ViewData item that has the key 'XXX' is of type 'System.Int32' but must be of type 'IEnumerable<SelectListItem>'
(6 answers)
Closed 7 years ago.
I have discovered the Foolproof library that seems very nice but I am having problems to put it working.
I want to create a required field only if the dropdown has the selected value = 7.
Simple Model:
[RequiredIf("LeadSource_Id","7", ErrorMessage = "Campo obrigatório")]
public string SourceDescription { get; set; }
[Display(Name = "Origem")]
public virtual int LeadSource_Id { get; set; }
The way I create the Dropdown in the Controller:
ViewBag.LeadSource_Id = new SelectList(db.LeadSources.ToList(), "Id", "Name");
The View:
<div class="form-group">
#Html.LabelFor(model => model.LeadSource_Id, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("LeadSource_Id", null, htmlAttributes: new { #class = "form-control ld-lead-source" })
#Html.ValidationMessageFor(model => model.LeadSource_Id, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group collapse">
#Html.LabelFor(model => model.SourceDescription, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.SourceDescription, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.SourceDescription, "", new { #class = "text-danger" })
</div>
</div>
When I try to see if the validation is working when I select the value 7, I get the error:
The ViewData item that has the key 'LeadSource_Id' is of type 'System.Int32' but must be of type 'IEnumerable<SelectListItem>'.
EDIT:
The libraries I include are:
<script src="~/Scripts/jquery/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery/jquery.validate.unobtrusive.min.js"></script>
<script src="~/Scripts/jquery/jquery.validate.globalize.min.js"></script>
<script src="~/Scripts/mvcfoolproof.unobtrusive.min.js"></script>
The error occurs because the value ofViewBag.LeadSource_Id is null. Since you have set its value in the GET method, then presumably this error is occurring when you return the view in your POST method (which you have omitted) but have not reassigned the value. In addition you cannot give the ViewBag property the same name as your model property.
Change your controller code to (say)
ViewBag.LeadSourceList = new SelectList(db.LeadSources.ToList(), "Id", "Name");
and ensure this code appears in both the GET method and POST method is you return the view, and modify the view to
#Html.DropDownList("LeadSource_Id", IEnumerable<SelectListItem>ViewBag.LeadSourceList , { #class = "form-control" })
However the recommended approach is to use a view model containing a property public IEnumerable<SelectListItem> LeadSourceList { get; set;}
So I decided to make an auction house web application as my first asp.net mvc project and I cannot figure out how to pass a parameter between two views that belong to different controllers. In the first view, Details of AuctionHouseController, I have:
<a class="btn btn-default" href="#Url.Action("Create", "Auctions", new { id = Model.ItemId })">Start Auction »</a>
and a URL: http://localhost:2142/AuctionHouse/Details/123
And here is the Details method:
public ActionResult Details(int id)
{
var item = _auctionhDbc.Items.Find(id);
return View(item);
}
I want to pass the id part of the URL - the "123" to the view where the button leads - Create of AuctionsController, where I have:
<div class="form-group">
#Html.LabelFor(model => model.Item.ItemId, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Item.ItemId, new { htmlAttributes = new { #class = "form-control", #Value = " " } })
#Html.ValidationMessageFor(model => model.Item.ItemId, "", new { #class = "text-danger" })
</div>
</div>
I want to place the "123" as the default value (#Value) of the Html Editor field. How can I do that?
Assuming you are using strongly typed views, your model for the Create view will already have the value of 123 in ItemID. The problem is, your model is of type Items, yet you are trying to use EditorFor for model.Item.ItemID.
Thus, instead of your line
#Html.EditorFor(model => model.Item.ItemId,
new { htmlAttributes = new { #class = "form-control", #Value = " " } })
if you use
#Html.EditorFor(model => model.ItemId,
new { htmlAttributes = new { #class = "form-control" } })
you will already have passed the value there. Make sure you use strongly typed views by putting:
#model YourNameSpace.Items
in the beginning of your view.