d ei
d ei

Reputation: 555

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.

Upvotes: 0

Views: 777

Answers (2)

pool pro
pool pro

Reputation: 2104

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>

Upvotes: 1

d ei
d ei

Reputation: 555

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>

Upvotes: 0

Related Questions