Foolproof required value based on Dropdown value [duplicate] - c#

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

Related

Client-side validation of US currency

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>

Adding Html required to TextAreaFor not working c#

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.

ASP.NET MVC Passing URL id between views of different controllers

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.

NullReferenceException in the cshtml page [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 7 years ago.
I am starting on ASP.net and I can not resolve the next problem.
System.NullReferenceException: La référence d'objet n'est pas définie à une instance d'un objet.
I forwards a User Id from User controller to this Action, who belongs to Email Controler. Then I want to give this Id to a new parameter.
public ActionResult Create(Guid? id)
{
ViewBag.Key_Destinataire = id;
return View();
}
Le code de ma page HTML :
#model ProjetWeb.Models.Email
////
#Html.LabelFor(model => model.Objet, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Objet, new { htmlAttributes = new { #class = "form-control" } })
///
<div class="form-group">
#Html.LabelFor(model => model.Key_Destinataire, "Key_Destinataire", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Model.Key_Destinataire.Value=ViewBag.Key_Destinataire;
#Html.ValidationMessageFor(model => model.Key_Destinataire, "", new { #class = "text-danger" })
</div>
</div>
English Translation;
Hello,
I start on ASP.net and I can not resolve the error below:
System.NullReferenceException : Object reference not set to an instance of an object.
my code below: I transmits the ID of a user of controller User controller in this action the Email. Then I want to assign the id to a new setting.
Your '#Model' is null. You didn't pass any model in controller to view.
Some reading: check this
You will need to pass the id from the controller action to the view in your return statement. For example:
public ActionResult Create(Guid? id)
{
return View(id);
}
This will now be available to you in your view if you declare #model Guid?. For example:
#model Guid?
<div class="form-group">
#Html.LabelFor(model => model, "Key_Destinataire", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBoxFor(model => model.Value)
#Html.ValidationMessageFor(model => model, "", new {#class = "text-danger"})
</div>
</div>

Viewmodel values not being returned to controller

I found some similar posts to mine, but I couldn't find an answer that suits my needs for this.
Problem is as follows:
I have a viewmodel like this:
public class PrefViewModel
{
public SelectList countries { get; set; }
public SelectList Provincies { get; set; }
public ApplicationUser user { get; set; }
public Preference MyPref{ get; set; }
public int mycountry { get; set; }
public int myprovince { get; set; }
}
my cshtml looks like this:
#using (Html.BeginForm("Index","Preferences", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<div class="form-group">
#Html.LabelFor(model => model.user.UserName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="control-label col-md-10">
<span class="textvak">
#Html.TextBoxFor(model => model.user.UserName, new { disabled = "disabled", #readonly = "readonly" })
</span>
#Html.ValidationMessageFor(model => model.user.UserName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.user.Email, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="control-label col-md-10">
<span class="textvak">
#Html.TextBoxFor(model => model.user.Email, new { disabled = "disabled", #readonly = "readonly" })
</span>
#Html.ValidationMessageFor(model => model.user.Email, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.user.Unhashed, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.user.Unhashed, new { htmlAttributes = new { #class = "form-control", type = "password" } })
#Html.ValidationMessageFor(model => model.user.Unhashed, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.user.Provincie.Land, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="control-label col-md-10">
#Html.DropDownListFor(model => model.mycountry, Model.countries, new { Name = "ddlLand", id = "ddlLanden", #class = "textvak" })
#Html.ValidationMessageFor(model => model.user.Provincie.Land, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.user.Provincie, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="control-label col-md-10">
#Html.DropDownListFor(model => model.myprovince, Model.Provincies, new { #class = "textvak" })
#Html.ValidationMessageFor(model => model.user.Provincie, "", new { #class = "text-danger" })
</div>
</div>
<br />
<table>
<tr>
<td>
<input type="submit" value=#Resources.Wijzig class="btn btn-default" />
</td>
</tr>
</table>
}
and in my controller I try to get the posted PrefViewModel back as follows:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(PrefViewModel TestMymodel)
{
if (ModelState.IsValid)
{
int myCountry = TestMymodel.mycountry;
int myprovince = TestMymodel.myprovince;
}
return View();
}
My problem is that the PrefViewModel TestMymodel never is filled with the values I thought i'm posting back. Even more strange to me is the fact that I do get the Unhashed password back, but all other values are 0 or null.
I can put values inside the PrefViewModel to load the page and that works, but on Posting it's almost entirely empty.
Any ideas?
edit: Would it make any difference that I did change the default model to one that I made up myself? Cause when I Call the Create action for example, I do get the values back in my post (from create offcourse). I'm getting a bit desperate
edit2: this is what was posted:
__RequestVerificationToken:-JYcw0CH2zZ7WrGUiYJM6-R6VxfL41ykTD5EHUjgtyyFcN01AaUU61BYuaRNr4oPdEvDq09aYsOFdb8fObJTXMnTKulADVkGY8CrBG3U71QXw0g7Th86WKl1up4059Zy7mW0SlrWGJpehed586v_5g2
user.Unhashed:Jonas1234-
user.Unhashed:Jonas1234-
ddlLand:1
ddlProvincie:3
(can't add picture with my reputation, so here a link to the full post: http://postimg.org/image/id95wjcxp/ )
Ok, when I change the name of the dropdownlists to the PrefViewModel property name those values get returned correct.
It appears that you have overriden the names of the drop down lists to some values which are different than the property names in your view model. That's why the values are not successfully bound back. Make sure that your input fields respect the same names as the properties on your view model if you want the default model binder to be able to bind them back to the view model.
Also your username textbox has the disabled flag:
#Html.TextBoxFor(model => model.user.UserName, new { disabled = "disabled", #readonly = "readonly" })
so it will not be submitted back to the server. You might need to add an additional hidden field if you want those values to travel back. Or simply use readonly without disabled attribute. Both attributes prevent the user from modifying the value in the corresponding input field but in addition to that the disabled attribute strips it from the POST payload when the form is submitted.
So you may use:
#Html.TextBoxFor(model => model.user.UserName, new { #readonly = "readonly" })

Categories