TextBoxFor decimal - c#

In my database I stored fields with the data type decimal. I am using exactly the same (decimal) data type in my ASP.NET application.
This is inside my view in order to display the value.
#Html.TextBoxFor(model => model.Stock, new { id = "Stock", #class = "k-textbox" })
This pretty straight forward. The only issue I am facing is that by default in my view the data is displayed with 4 decimal places.
I give you a few examples on how it looks and how it should look:
1,0000 => 1
1,2000 => 1,2
1,4300 => 1,43
1,8920 => 1,892
1,5426 => 1,5426
As you can see I want to cut off all the 0 as decimal places (only when displayed in the view).
Remember: I am using commas instead of decimal points.
Edit:
My model
public class Article
{
public decimal? Stock{ get; set; }
}

The G29 argument of the string.Format method does exactly what you want.
You can use the the following attribute on your models Stock value.
[DisplayFormat(DataFormatString = "{0:G29}", ApplyFormatInEditMode = true)]
Or you can use the overload which #Chris mentioned.
#Html.TextBoxFor(model => model.Stock, "{0:G29}", new { id = "Stock", #class = "k-textbox" })

You can use {0:G29} like this:
#{
string temp = string.Format("{0:G29}", decimal.Parse(Model.Stock.ToString()));
#Html.TextBoxFor(model => temp)
}
Or with string interpolation:
#{
string temp = $"{decimal.Parse(Model.Stock.ToString()):G29}";
#Html.TextBoxFor(model => temp)
}
EDIT:
The reason that you can't get the value in your Controller after you save it is that the model binder can't find a property with name temp. You can use a TextBox instead of TextBoxFor to solve this issue like this:
string temp = $"{decimal.Parse(Model.Stock.ToString()):G29}";
#Html.TextBox("Stock" , temp)
Or if you still want to use TextBoxFor you can just rename the temp variable to Stock:
string Stock = string.Format("{0:G29}", decimal.Parse(Model.Stock.ToString()));
#Html.TextBoxFor(model => Stock)

There is an overload of TextBoxFor that takes a format parameter that it uses to format the text.
This will allow you to format your number in any way you want.

Related

FormCollection MVC5 not passing decimal to controller

i keep getting errors when trying to post an <input type="number"> from my view to my controller using FormCollection. the database type for expenseBackup is a decimal(8,2). I keep getting "Cannot impliticity convert string to decimal?". Then when i try expenseBackup = Int32.Parse(formValues["expenseBackup"]), i get "Input string was not in correct format". i don't want to have to convert anything in the controller i don't understand why it won't just pass as a decimal through the FormCollection.
Controller
[HttpPost]
public ActionResult Create(FormCollection formValues)
{
var data = new usr_ebillingClientDatabase()
{
client = formValues["client"], //is a string from form
expenseBackup = formValues["expenseBackup"] //is a decimal from form
};
dataContext.table1.InsertOnSubmit(data);
try
{
dataContext.SubmitChanges();
return RedirectToAction("Index");
}
catch (Exception e)
{
return RedirectToAction("Index");
}
}
View
<div class="form-group">
<div class="col-md-10">
#Html.EditorFor(model => model.expenseBackup, new { htmlAttributes = new { #class = "form-control" , , #type="number", #step=".01" } })
</div>
</div>
when you're reading the field from formValues["expenseBackup"] it's being read as a string. Convert it to a decimal using Convert.ToDecimal().
expenseBackup = Convert.ToDecimal(formValues["expenseBackup"] ?? 0m);
FormCollection is a key-value pair collection (NameValueCollection) which returns values as string based from provided key, which is also a string. If you're in doubt which number format applied by numeric input during submit, use combination of decimal.TryParse() and if-condition with string.IsNullOrEmpty() to check null/empty string value:
decimal expense;
if (!string.IsNullOrEmpty(formValues["expenseBackup"])
&& decimal.TryParse(formValues["expenseBackup"], out expense))
{
var data = new usr_ebillingClientDatabase()
{
client = formValues["client"],
expenseBackup = expense
};
// insert to database
}
else
{
// unable to parse numeric value, do something else
}
If you're sure that numeric representation passed in FormCollection uses certain decimal separator other than default, use NumberFormatInfo when parsing with decimal.Parse()/decimal.TryParse():
var numberFormat = new System.Globalization.NumberFormatInfo() { NumberDecimalSeparator = "," };
var data = new usr_ebillingClientDatabase()
{
client = formValues["client"],
expenseBackup = decimal.Parse(formValues["expenseBackup"], numberFormat);
};
However, I recommend using strongly-typed viewmodel over FormCollection because you're using EditorFor, and it will pass property values directly to controller when viewmodel name is included as action parameter.

display a message to user if field is blank

Afternoon Folks,
I am new to c# and im trying to create an if statement to check the value of two fields and if both of these fields are blank, to then display a message to the user.
My two fields are DateofBirth with a datatype of DateTime and Age with a datatype of int. Im using studio 2013 and have a c# mvc project.
In my create.cshtml page i am using razor syntax for these two form fields.
#Html.EditorFor(model => model.client.DateOfBirth, new { htmlAttributes = new { #class = "form-control", #placeholder = "dd-mm-yyyy" } })
and
#Html.EditorFor(model => model.client.AgeNotKnown, new { htmlAttributes = new { #class = "form-control", #placeholder = "Age in Years" } })
the user needs to fill in either one or the other field when submitting the form.
In my controller and my HttpPost for the ActionResult Create. I have tried a couple of ways to get this working via an if statement but i get seem to get this to work.
I have tried using the string.IsNullOrEmpty method, but as these are DateTime and int datatypes this will not work. See sample below.
if (string.IsNullOrEmpty(clientViewRecord.client.AgeNotKnown));
{
MessageBox.Show("please an Age if DOB not known");
}
db.ClientRecords.Add(clientViewRecord.client);
db.SaveChanges();
return RedirectToAction("MainMenu", "Home");
I get three errors here:
Argument 1: cannot convert from 'int?' to 'string'
The name 'MessageBox' does not exist in the current context 3) The
best overloaded method match for 'string.IsNullOrEmpty(string)' has
some invalid arguments
The best overloaded method match for 'string.IsNullOrEmpty(string)' has
some invalid arguments
Another way i have tried to get this working is the following...
if (clientViewRecord.client.AgeNotKnown == 0 || clientViewRecord.client.DateOfBirth == 0);
{
MessageBox.Show("please enter an Age or if DOB");
}
db.ClientRecords.Add(clientViewRecord.client);
db.SaveChanges();
return RedirectToAction("MainMenu", "Home");
I get the same issue for the message box and the following for the DateofBirth filed.
Operator '==' cannot be applied to operands of type 'System.DateTime?' and 'int'
Im new to c# but think that im kinda on the right lines, i think just need a little help or any suggestions.
Regards
Betty
? means nullable whose default value will be null if i use int? its default value will be null if i use int its default value will be 0
about validation you can use ModelState for validation in MVC and add a custom validation
#Html.ValidationMessage("validation")
#Html.EditorFor(model => model.DateOfBirth, new { htmlAttributes = new { #class = "form-control", #placeholder = "dd-mm-yyyy" } })
#Html.EditorFor(model => model.AgeNotKnown, new { htmlAttributes = new { #class = "form-control", #placeholder = "Age in Years" } })
i used #Html.ValidationMessage("validation") which will show the validation message if i return any and in your action
if (cls.DateOfBirth == null && cls.AgeNotKnown == null)
{
ModelState.AddModelError("validation","Please select one");
return View();
}
in action it will check condition if both are null then it will return to the same view including the validation message of key validation which is defined in the view.
First of all MessageBox class is belong to windows forms. If you want to wanr the user you should use validations. I prefer jquery validation
To add control like this, just put a breakpoint to your code and look want data coming from your form. This way you can decide how do you want to control your data.
System.DateTime? and int?, this question marks tell you that these variables can be null. So you should consider that while comparing.
First of all create ViewModel for this kind of validation
public class ClientViewModel
{
[Required, DataType(DataType.Date), DisplayFormat(DataFormatString = "{0:dd-MM-yyyy}", ApplyFormatInEditMode = true)]
public DateTime Date { get; set; }
[Required]
public int Age { get; set; }
}
In View
#model Models.ClientViewModel #*reference to your model usally create in Models folder*#
#Html.ValidationSummary() #* add this for validation summary displays here.*#
#Html.EditorFor(model => model.Date, new { htmlAttributes = new { #class = "form-control", #placeholder = "dd-mm-yyyy" } })
#Html.ValidationMessageFor(m => m.Date)
#Html.EditorFor(model => model.Age, new { htmlAttributes = new { #class = "form-control", #placeholder = "Age in Years" } })
#Html.ValidationMessageFor(m => m.Age)
#* Add jqueryval bundles which is created in app_start/BundleConfig *#
#section Scripts{
#Scripts.Render("~/bundles/jqueryval")
}
In Controller
//Change the name of PostMethod
public ActionResult PostMethod(Models.ClientViewModel model )
{
if (ModelState.IsValid)
{
// do your stuff
}
return View();
}

asp mvc format timespan (mm:ss) textboxfor to work with bootstrap timepicker

I've read up on several posts with similar problems but still I can't get it to work properly. My problem is formating two timespan properties to mm:ss, and having them work with this bootstrap datepicker correctly.
The model properties: (Not sure if it's correct)
[DataType(DataType.Time)]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = #"{0:mm\:ss}")]
public TimeSpan AgentHoldoffTime { get; set; }
[DataType(DataType.Time)]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = #"{0:mm\:ss}")]
public TimeSpan AgentAlertTime { get; set; }
public InteractionQueueModel() // ctor
{
AgentAlertTime = new TimeSpan(0, 0, 17);
AgentHoldoffTime = new TimeSpan(0, 2, 00);
}
The view:
#Html.EditorFor(model => model.QueueModel.AgentHoldoffTime, new { htmlAttributes =
new { #class = "form-control timepicker-holdOffTime" } })
#Html.EditorFor(model => model.QueueModel.AgentAlertTime, new { htmlAttributes =
new { #class = "form-control timepicker-alertTime" } })
JS:
var timePickerAlertTime = $(".timepicker-alertTime"),
timePickerHoldOffTime = $(".timepicker-holdOffTime");
timePickerAlertTime.datetimepicker({
format: "mm:ss",
})
.on("dp.change", function () {
...
});
timePickerHoldOffTime.datetimepicker({
format: "mm:ss",
})
.on("dp.change", function () {
...
});
Now, when the view renders, a textbox displays 00:17 for a time(7) column with the value 00:00:17.0000000. Everything seems fine, But when I submit 01:00 it's saved as 01:00:00.0000000 instead of 00:01:00.0000000? I've probably missed something simple, but I can't figure it out.
Thanks in advance.
specifying the format works for me:
#Html.TextBoxFor(m => Model.AgentHoldoffTime,
"{0:hh\\:mm}",
new {
#class = "form-control",
placeholder = "hh:mm",
})
this signature:
//
// Summary:
// Returns a text input element.
//
// Parameters:
// htmlHelper:
// The HTML helper instance that this method extends.
//
// expression:
// An expression that identifies the object that contains the properties to display.
//
// format:
// A string that is used to format the input.
//
// htmlAttributes:
// An object that contains the HTML attributes to set for the element.
//
// Type parameters:
// TModel:
// The type of the model.
//
// TProperty:
// The type of the value.
//
// Returns:
// An input element whose type attribute is set to "text".
public static MvcHtmlString TextBoxFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
string format,
object htmlAttributes);
When you use 'EditorFor' the Framework try to render the best HTML element for the data type, in case of TimeSpan, the best is an <input type="time"/>, as i understand you need handle seconds, but this input by default does not consider seconds, you'll need to "force" with attribute step = 1. Now if you use 'EditorFor' it does not allows you to set attributes, or at least i have not found how to do that, so changes it to 'TextBoxFor':
#Html.TextBoxFor(model => model.AgentHoldoffTime, new
{
#class = "form-control timepicker-holdOffTime",
type = "time",
step = 1
})
I Hope this help

Create an Editor Template for DateTime with three input fields for day, month, year, in MVC

I would like to create an editor template for DateTime? field that has 3 text boxes for day, month, year. Currently my EditorTemplates/Date.cshtml looks like this:
#Html.TextBox(string.Empty, Model.HasValue ? Model.Value.Day.ToString() : "",
new { #class = "day-box", title = "day", min = "1", max = "31", type = "number" })
#Html.TextBox(string.Empty, Model.HasValue ? Model.Value.Month.ToString() : "",
new { #class = "month-box", title = "month", min = "1", max = "12", type = "number" })
#Html.TextBox(string.Empty, Model.HasValue ? Model.Value.Year.ToString() : "",
new { #class = "year-box", title = "year", min = "1900", max = "2020", type = "number" })
The obvious problem is that that (as is) the id and name attributes all get set to the same value. I need to append something to those values, and never make it back into my model.
I was hoping that appending _Day to the id, and .Day to the name of the Day input, and likewise for month and year would solve the problem. But I can't see an easy way of doing this.
I was going to use Hidden input for the actual value, then use javascript to update the value of the hidden field each time a value changes in one of my three (d/m/y) textboxes.
So is there a way to get the name and id that MVC is going to use, when I pass in string.Empty? Using ViewData.TemplateInfo.HtmlPrefix doesn't seem to give full value.
Is there a better way to do what I want? I can't imagine I am the first to tackle this.
I know there are 3rd party date pickers out there. For the sake of this problem I am not interested in them.
Thanks,
~S
Had DateTime's Year Month Day are settable, you can just do this on your DateTime.cshtml EditorTemplates
#model System.DateTime
#Html.TextBoxFor(model => model.Year) / #Html.TextBoxFor(model => model.Month) / #Html.TextBoxFor(model => model.Day)
Above isn't possible. DateTime's Year, Month and Day properties are read-only.
What you can possibly do is to just create a separate data type:
public struct DatePart
{
public int Year { get; set; }
public int Month { get; set; }
public int Day { get; set; }
public DateTime Date { get { return new DateTime(Year, Month, Day); } }
}
Then do this on your date EditorTemplates
#model TestV.Models.DatePart
#Html.TextBoxFor(model => model.Year) / #Html.TextBoxFor(model => model.Month) / #Html.TextBoxFor(model => model.Day)
Then just access DatePart's Date(DateTime type) property
You can form date from three field in your custom template with javascript and write it in hidden field that will bind to your Model.Date

ASP.NET MVC Where to keep the values for SelectLists

I've currently got all of this mess at the top of my ViewModels which I feel violates the purpose of a DTO. For example, this is in the constructor of one of my view models -
Dictionary<int, string> chargeGroups = new Dictionary<int, string>();
chargeGroups.Add(1, "Administration");
chargeGroups.Add(2, "Annual Leave");
chargeGroups.Add(3, "Bereavement");
chargeGroups.Add(4, "Customer Installation, Setup & Training");
chargeGroups.Add(5, "Customer Support");
chargeGroups.Add(6, "Internal Training & Education");
chargeGroups.Add(7, "Sales & Marketing");
chargeGroups.Add(8, "Sick");
chargeGroups.Add(9, "Software Devel / Maint / Test");
chargeGroups.Add(10, "Software Upgrade / Patch");
chargeGroups.Add(11, "Other");
chargeGroups.Add(12, "Other Absence");
chargeGroups.Add(13, "Warranty");
chargeGroups.Add(14, "Public Holiday");
chargeGroups.Add(15, "Other Paid Leave");
ChargeGroups = new SelectList(chargeGroups, "Key", "Value");
My viewmodel:
[DisplayName("Charge group")]
public short? ChargeGroup { get; set; }
public SelectList ChargeGroups;
then in my view:
<div class="editor-label">
#Html.LabelFor(model => model.ChargeGroup)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.ChargeGroup, Model.ChargeGroups)
#Html.ValidationMessageFor(model => model.ChargeGroup)
</div>
Where should I be putting this stuff?
When I have a list of values that wont change I usualy use an Enum and then use a custom Html Helper to render out a select list. You can customzie the display text of the enum values by using meta data description markup.
That way you can just use:
<%: Html.EnumDropDownListFor(model => model.EnuProperty) %>
or
#Html.EnumDropDownListFor(model => model.EnuProperty)
Check out this post by Simon which allows you to use the Meta Description attribute to customzie the output for Enum names:
How do you create a dropdownlist from an enum in ASP.NET MVC?
Here is another example but it lacks the meta description property:
http://blogs.msdn.com/b/stuartleeks/archive/2010/05/21/asp-net-mvc-creating-a-dropdownlist-helper-for-enums.aspx
EDIT
Your enum might look something like this
public enum ChargeGroupEnum
{
[Description("Administration")]
Administration=1,
[Description("Annual Leave")]
AnnualLeave=2,
[Description("Bereavement")]
Bereavement=3,
[Description("Customer Installation, Setup & Training")]
CustomerInstallation=4,
[Description("Customer Support")]
CustomerSupport=5,
[Description("Internal Training & Education")]
InternalTraining=6,
[Description("Sales & Marketing")]
SalesMarketing=7,
[Description("Sick")]
Sick=8,
[Description("Software Devel / Maint / Test")]
Development=9,
[Description("Software Upgrade / Patch")]
Upgrade=10,
[Description("Other")]
Other=11,
[Description("Other Absence")]
OtherAbsence=12,
[Description("Warranty")]
Warranty=13,
[Description("Public Holiday")]
PublicHoliday=14,
[Description(")ther Paid Leave")]
OtherPaidLeave=15
}
And then on your View Model you could use the following to make the field start with no value and REQUIRE a value:
[Required(ErrorMessage=" * required")]
public ChargeGroupEnum? ChargeGroup {get;set;}
And then in your view you would use the Html Helper "ChargeGroupEnum" which you'll need to get from the post I linked to.
#Html.EnumDropDownListFor(model => Model.ChargeGroup)
If your model has an Int, you can easly go from Enum => Int and Int => Enum with casting.
I think that Caching that data after loading it from datasource and rendering the control based on that data through a helper method will be a better solution.
I decided to keep the values for the select list on another class called OtherData which sits beside my main DBContext class in my models file.
Wouldn't it be more ideal to create the SelectList in the view, vs. view model, just so the view models aren't AS tightly coupled to a view object (SelectList)?
I know a view model is for a view so tightly coupling them is more ok, but theoretically if the view is swapped out with something that doesn't use a SelectList, you could reuse more of the view model if it didn't use that SelectList.
public static List<string> PaymentCurrency = new List<string> { "USD", "GBP", "EUR", "AUD", "BRL", "CAD", "CHF", "CLP", "CNY", "CZK", "DKK", "FJD", "HKD", "HNL", "HUF", "IDR", "ILS", "INR", "ISK", "JPY", "KRW", "LVL", "MXN", "MYR", "NOK", "NZD", "PHP", "PKR", "PLN", "RUB", "SEK", "SGD", "THB", "TRY", "TWD", "ZAR" };
List<SelectListItem> PaymentCurrencyOptionItems = new List<SelectListItem>() { new SelectListItem { Text = "", Value = "" } };
PaymentCurrencyOptionItems.AddRange(Lolio.PaymentCurrency.Select(r => new SelectListItem { Text = r+" "+LangResources.Get("Currency_" + r), Value = r }));
IEnumerable<SelectListItem> LinkPaymentType = new SelectList(PaymentTypeOptionItems, "Value", "Text", lnk.Performance.PaymentType);
Html.DropDownListFor(m => m.PaymentType, LinkPaymentType))

Categories