I have 4 submit buttons on my View and in order for them to call the right method in the controller I added a JQuery POST function.
Dependant on what buttons I click in the View I want the Controller to calculate whatever operation was selected. The JQuery correctly links my View with the Controller (the debugger first stops in the JQuery, then in the controller), however it doesn't seem to pass the parameter operation (needed in CalculationValidation(Model, String) ). So it ends up reloading the View with a new Model (operation == null). What it should do is calculate the result dependant on the clicked operation and then reload the PartialView.
The JQuery does serialize the model correctly as the Model's properties Number1 and Number2 are filled from the View, but without the operation type. WIthout that I'm unable to calculate the result in the controller and load the PartialView with the updated model.
Question / Goal
How would I be able to load the PartialView with the Model.Result without reloading the full page after clicking the submit buttons?
Prehaps important: The result of filling in the input fields and then clicking a submit button returns the error alert from the JQuery script.
CalculationValidation.cshtml
#using MVCPluginTest.Models
#model MVCPluginTest.Models.CalculatorModel
#{
Layout = "~/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Validation master Page";
}
<div id="containter">
<h2>Validation</h2>
#*#using (Html.BeginForm("CalculationValidation", "Home", FormMethod.Post))*#
#*#using (Html.BeginForm("CalculationValidation", "Home", FormMethod.Get, new { id = "ValidationForm" , name = "ValidationForm"} ))*#
#using (Ajax.BeginForm("CalculationValidation", "Home", new AjaxOptions { HttpMethod = "POST" }, new { id = "ValidationForm", name = "ValidationForm" }))
{
<!--
if (#ViewData.ModelState.IsValid)
{
<b>
Number 1 : #ViewBag.Number1<br />
Number 2 : #ViewBag.Number2<br />
Result: #ViewBag.Result
</b>
} -->
#Html.ValidationSummary(true)
<fieldset>
<p>#Html.LabelFor(model => model.Number1)</p>
<p>#Html.EditorFor(model => model.Number1) #Html.ValidationMessageFor(model => model.Number1)</p>
<p>#Html.LabelFor(model => model.Number2)</p>
<p>#Html.EditorFor(model => model.Number2) #Html.ValidationMessageFor(model => model.Number2)</p>
</fieldset>
<p><input type="submit" value="+" name="operation" id="btn-plus" /></p>
<p><input type="submit" value="-" name="operation" id="btn-minus" /></p>
<p><input type="submit" value="*" name="operation" id="btn-multiply" /></p>
<p><input type="submit" value="/" name="operation" id="btn-divide" /></p>
#Html.ValidationMessageFor(model => model.OperationType)
#Html.ValidationMessageFor(model => model.Result)
}
</div>
<div id="dvCalculationResult">
#{ Html.RenderPartial("CalculationPartial", #Model); }
</div>
LoadPartialCalc.js
$(document).ready(function () {
$("#ValidationForm").submit(function (event) {
event.preventDefault();
$.ajax({
//url: '#Url.Action("CalculationValidation", "Home")',
url: "/Home/CalculationValidation",
dataType: 'json',
data: $("#ValidationForm").serialize(),
type: 'POST',
success: function (result) {
$("#dvCalculationResult").html(result);
},
error: function (xhr) {
alert("err");
}
});
});
});
HomeController
public ActionResult CalculationValidation()
{
return View(new CalculatorModel());
}
[HttpPost]
public ActionResult CalculationValidation(CalculatorModel valModel, string operation)
{
var num1 = valModel.Number1;
var num2 = valModel.Number2;
if (operation == null)
{
ModelState.AddModelError("OperationType", "No operation type selected");
return View(new CalculatorModel());
}
else
{
if (ModelState.IsValid)
{
switch (operation)
{
case "+":
valModel.Result = num1 + num2;
break;
case "-":
if (ValidateNumbers(num1, num2, "-"))
{
valModel.Result = num1 - num2;
}
else
{
valModel.Result = 0;
ModelState.AddModelError("Result", "Minus can't be lower than 0");
}
break;
case "*":
valModel.Result = num1 * num2;
break;
case "/":
if (ValidateNumbers(num1, num2, "/"))
{
valModel.Result = num1 / num2;
}
else
{
valModel.Result = 0;
ModelState.AddModelError("Result", "Division not whole.");
}
break;
default:
valModel.Result = 0;
break;
}
}
}
valModel.Result = num1 + num2;
return PartialView("CalculationPartial", valModel);
}
CalculatorModel
public class CalculatorModel
{
[Required(ErrorMessage = "Please enter a number.")]
[Display(Name = "Number 1")]
[RegularExpression(#"^[0-9]*$", ErrorMessage = "You can only enter numbers above 0.")]
public double Number1
{
get;
set;
}
[Required(ErrorMessage = "Please enter a number.")]
[Display(Name = "Number 2")]
[RegularExpression(#"^[0-9]*$", ErrorMessage = "You can only enter numbers above 0.")]
public double Number2
{
get;
set;
}
public string OperationType
{
get;
set;
}
public double Result
{
get;
set;
}
}
CalculationPartial
#using MVCPluginTest.Models
#model MVCPluginTest.Models.CalculatorModel
<h2>Result</h2>
<p id="result">#Model.Result</p>
Related
I have a simple form with 2 dropdown fields and a submit button in my MVC application. I have enabled client side validation and it works fine. I have now added a javascript to disable the submit button to prevent the form being submitted twice. For some unknown reason the client validation message does not display when I add this script.
This is my form:
#using (Html.BeginForm("Recycle", "GetList", FormMethod.Post, new { id = "myForm" }))
{
<!-- Server list -->
<div>
<span>Site type: </span>
#Html.DropDownListFor(m => m.uInputS, new List<SelectListItem>
{
new SelectListItem {Text = "text", Value = "value" },
new SelectListItem {Text = "text", Value = "value" }
}, "Select site type")
#Html.ValidationMessageFor(m => m.uInputS, "", new { #class = "error" })
</div>
<!-- Application list -->
<br />
<div>
<span>Application: </span>
#Html.DropDownListFor(m => m.uInputA, new SelectList(string.Empty, "Value"))
#Html.ValidationMessageFor(m => m.uInputA, "", new { #class = "error" })
</div>
<br />
<!-- Submit-->
<div>
<input id="Submit1" type="submit" value="Submit" onclick="return FreezeSubmit();" />
</div>
}
Below is the jquery I used to disable the submit button.
<script>
function FreezeSubmit() {
var s = $("#uInputS").val();
var a = $("#uInputA").val();
if ((s && a)) {
$('#myForm').submit();
$('#Submit1').prop('disabled', true);
return true;
}
else {
$('#Submit1').prop('disabled', false);
return false;
}
}
</script>
This is my Model:
public class GetList
{
[Required(ErrorMessage = "Please select site type")]
public string uInputS { get; set; }
[Required(ErrorMessage = "Please select application name")]
public string uInputA { get; set; }
}
I am very new to programming and I am not able to figure out why the client validation message fails to display because I added some javascript. Any help is appreciated. Thanks!
Remove onclick in
<input id="Submit1" type="submit" value="Submit" onclick="return FreezeSubmit();" />
change to
<input id="Submit1" type="submit" value="Submit" />
and you need change your script to
<script>
$(document).ready(function(){
checkEmpty()
})
$('input').change(function() {
checkEmpty();
});
function checkEmpty(){
var s = $("#uInputS").val();
var a = $("#uInputA").val();
if ((s && a)) {
$('#Submit1').prop('disabled', true);
}
else {
$('#Submit1').prop('disabled', false);
}
}
</script>
disable the button when submit handler is called, see jquery api here
$( "#your_form_id" ).submit(function(event) { // Handler for .submit() called.
$('#Submit1').prop('disabled', true);
});
I want to save the entered value of the database. However, values are sent as null.
I'm glad if I encode additional help.
HomeConteller.cs
[HttpPost]
public void GaleriOlustur(string Adi)
{
GaleriTanim As = new GaleriTanim() { Adi = Adi };
db.GaleriTanims.Add(As);
db.SaveChanges();
islemler islem = new islemler { islemler1 = "Galeri Oluşturuldu", kayitTarihi = DateTime.Now };
db.islemlers.Add(islem);
db.SaveChanges();
RedirectToAction("GaleriYonet", "Home");
}
GaleriYonet.cshtml
#using (Html.BeginForm("GaleriOlustur", "Home",FormMethod.Post,new {Adi="Adi"}))
{
<input type="submit" onclick="GaleriOlustur()" name="Adi" value="Galeri Oluştur"/>
}
GaleriYonet.cshtml "Javascript"
<script type="text/javascript">
function GaleriOlustur() {
var Adi = prompt("Galeri İsmi Giriniz");
if (Adi != null) {
return Adi;
} else {
alert("Bir İsim Girmelisiniz.");
return false;
}
};
Your client side function should either return true or false. Not the value user entered to the prompt.
I also suggest you keep an input variable value (hidden type) in your form with name matching to your action method parameter name. In your javascript method, when user enter a vliad value, you can update this form control value to that.
Also, you need to do return GaleriOlustur() on the onclick event
#using (Html.BeginForm("GaleriOlustur", "Home", FormMethod.Post, new { Adi = "Adi" }))
{
<input type="hidden" name="Adi" />
<input type="submit" onclick="return GaleriOlustur()" value="Galeri Oluştur" />
}
and in js method, set the input field value to the value user entered.
function GaleriOlustur() {
var adi = prompt("Galeri İsmi Giriniz");
if (adi !=="") {
$("input[name='Adi']").val(adi);
return true;
} else {
alert("Bir İsim Girmelisiniz.");
return false;
}
};
<script type="text/javascript">
jQuery.validator.addMethod("mustbetrue", function (value, element, param) {
return element.checked;
});
jQuery.validator.unobtrusive.adapters.addBool("mustbetrue", "required");
that was my script and c# code is ...
public class mustbetrueAttribute : ValidationAttribute, IClientValidatable // IClientValidatable for client side Validation
{
public bool chkbox { get; set; }
public override bool IsValid(object value)
{
if (value is bool)
return (bool)value;
else
return false;
}
// Implement IClientValidatable for client side Validation
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var modelClientValidationRule = new ModelClientValidationRule
{
ValidationType = "mustbetrue",
ErrorMessage = FormatErrorMessage(metadata.DisplayName)
};
modelClientValidationRule.ValidationParameters.Add("mustbetrue", chkbox);
yield return modelClientValidationRule;
//return new ModelClientValidationRule[] { new ModelClientValidationRule { ValidationType = "checkbox", ErrorMessage = this.ErrorMessage } };
//yield return new ModelClientValidationRule
//{
// ErrorMessage = "You must accept Terms and Condition",
// //Given Validation Type will be Used for Client side Validation in Unobtrusive Jquery
// ValidationType = "mustbetrue"
//};
}
}
rendered html:
<li>
<label for="TermsAccepted">Terms and Conditions.</label>
<input data-val="true" data-val-mustbetrue="Please Accept the Terms & Conditions" data-val-mustbetrue-mustbetrue="False" data-val-required="The Terms and Conditions. field is required." id="TermsAccepted" name="TermsAccepted" type="checkbox" value="true" />
<input name="TermsAccepted" type="hidden" value="false" />
</li>
You forget to add:
$.validator.addClassRules("mustbetrue", {
mustbetrue: true
});
Here is a jsfiddle with example
I am attempting to pass data from one view to the other using MVC. I am trying to do a simple guessing game, where on the first view, we enter a range of numbers, then on the second view we try to guess the number. I am able to store the values in my model, but I'm having trouble accessing them/using them in a js script on another view. Sorry if this is too much code, MVC's are hard to ask for help on without showing a full range of code. When I go to the second view to guess the number, it doesn't recognize #ViewBag.(model => model.Low) and it says Load is not defined
Model
pubblic class Range
{
public int High
{
get
{
if (HttpContext.Current.Session["High"] == null)
{
HttpContext.Current.Session["High"] = 3;
}
return (int)HttpContext.Current.Session["High"];
}
set
{
HttpContext.Current.Session["High"] = value;
}
}
public int Low
{
get
{
if (HttpContext.Current.Session["Low"] == null)
{
HttpContext.Current.Session["Low"] = 1;
}
return (int)HttpContext.Current.Session["Low"];
}
set
{
HttpContext.Current.Session["Low"] = value;
}
}
}
Controller
public class GuessingGameController : Controller
{
public ActionResult EnterRange()
{
return View();
}
[HttpPost]
public ActionResult EnterRange(Range range)
{
int high = range.High;
int low = range.Low;
return View(range);
}
public ActionResult GuessNumber()
{
return View();
}
}
View 1: Enter Range
#model GameMVC.Models.Range
#using (Html.BeginForm("EnterRange", "GuessingGame"))
{
<center>
<h2>Lets play a game.</h2>
Enter A Range of Numbers:
<br />
Low: #Html.TextBoxFor(m => m.Low)
<br />
High: #Html.TextBoxFor(m => m.High)
<br />
<input type="submit" value="Enter"/>
<p>
#Html.ActionLink("Now, To the Game", "GuessNumber", "GuessingGame")
</p>
</center>
}
View 2: Guess Number
#model GameMVC.Models.Range
<script language="JavaScript">
var myNum, count;
function Load() {
document.game.status.value = "Please set range of numbers and press the Start button.";
document.game.number.focus();
}
function Round(scale) {
var dd = new Date();
return((Math.round(Math.abs(Math.sin(dd.getTime())) * 8.71 * scale) % scale));
}
function myRange() {
var to = 1 + 1 * #ViewBag.(model => model.Low);
count = 0;
myNum = Round(to);
while (myNum < #ViewBag.(model => model.High);)
myNum = Round(to);
document.game.status.value = "Please guess a number, enter it, and press Guess.";
}
function Guess() {
var numberGuess = document.game.number.value;
count++;
if (numberGuess < myNum) alert("My number is greater than " + numberGuess + ".");
else if (numberGuess > myNum) alert("My number is less than " + numberGuess + ".");
else alert("It takes you " + count + " attempts to guess this number");
}
</script>
<body onload=" Load() ">
<div style="text-align: center;">
<form name=game>
Guess: <input type="text" name="number" size=10>
<p>
<br/>
<input type="button" value="Guess" onclick=" Guess() ">
</p>
#Html.Label("status")
</form>
</div>
</body>
Instead of #ViewBag.(model => model.Low), you could try just using #Model.Low
Model instance is not provided for "GuessAction" view. You need to pass an instance of "Range" to "GuessNumber" view. Since you are accessing values from session, you can simply pass a new instance.
public ActionResult GuessNumber()
{
return View(new Range());
}
Then in javascript you can simply access the data as #Model.High and #Model.Low
You can also use TempData to store the high and low values if you need it only for one request.
I want to be able to validate that a birthdate entered is 18 or older. I have searched and found numerous posts about this. However, I don't understand
1) Why MS didn't build this into MVC3 like the other validations such as string, email, password, etc.
2) why when I get the javascript in place to make the dates correctly validate, the other unobtrustive js doesn't work any more.
I want to have client side validation before submit yet, dates doesn't seem to work well with this. All the rest does.
Am I missing something ?
some code I've tried in my model
#1) [Display(Name = "Date of Birth (must be at least 18) ")]
public DateTime Birthdate
{
get
{
if ((SelectedBMonth != "0") && (SelectedBday != "0") && (SelectedBYear != "0"))
return DateTime.Parse(SelectedBMonth + "/" + SelectedBday + "/" + SelectedBYear);
else
return DateTime.MinValue;
}
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (Birthdate.Date > DateTime.Today.AddYears(-18))
yield return new ValidationResult("You must be at least 18 years old to register", new[] { "Birthdate" });
}
#2)
[Required]
[CustomValidation(typeof(RegisterModel), "ValidateDOBDate")]
[DataType(DataType.Date)]
[Display(Name = "Date of Birth")]
public DateTime DateOfBirth { get; set; }
public static ValidationResult ValidateDOBDate(DateTime DateOfBirthtovalidate) { if (DateOfBirthtovalidate.Date > DateTime.Now.AddYears(-18)) { return new ValidationResult("User should be atleast 18 years old."); } if (DateOfBirthtovalidate.Date < DateTime.Now.AddYears(-150)) { return new ValidationResult("Please put a valid date"); } return ValidationResult.Success; }
#3)
public class DateofBirthAttribute : ValidationAttribute, IClientValidatable
{
public override bool IsValid(object value)
{
if (value == null || (DateTime)value < DateTime.Today.AddYears(-18))
return false;
return true;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
yield return new ModelClientValidationRule
{
ErrorMessage = this.ErrorMessage,
ValidationType = "dateofbirth"
};
}
}
[Required]
[Display(Name = "Date of Birth")]
[DateofBirth(ErrorMessage = "User must be at least 18")]
public DateTime Birthdate { get; set; }
View :
<div class="editor-label">
#Html.LabelFor(m => m.Birthdate)
</div>
<div class="editor-field">
#Html.TextBoxFor(x => x.Birthdate)
#Html.ValidationMessageFor(x => x.Birthdate)
</div>
Top of view before beginform:
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"> </script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/MyScripts.js")" type="text/javascript"></script>
<script type="text/javascript">
// we add a custom jquery validation method
jQuery.validator.addMethod('greaterThan', function (value, element, params) {
if (!/Invalid|NaN/.test(new Date(value))) {
return new Date(value) > new Date($(params).val());
}
return isNaN(value) && isNaN($(params).val()) || (parseFloat(value) > parseFloat($(params).val()));
}, '');
// and an unobtrusive adapter
jQuery.validator.unobtrusive.adapters.add('dateofbirth', {}, function (options) {
options.rules['greaterThan'] = true;
options.messages['greaterThan'] = options.message;
});
</script>
That's a dynamic validation which is dependant on current date, and it's not available in default validation options.
You can easily implement it but there is no client side validation generated.
You must implement the client side javascript validation also.
Fore more information about adding a new Validation to ASP.NET MVC check out this ASP .Net MVC 3 unobtrusive custom client validation.