Trouble accessing data passed from another view, using MVC - javascript

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.

Related

How to read multiple choice answers from a dynamic form in razor pages?

As a follow up on my previous question related to this issue, the solution provided there works well enough for basic answers to basic questions in my questionnaire.
Background
I'm allowing the user to create custom questionnaires by specifying question details including a question type which determines the UI elements that will be rendered dynamically when their customer fills out the questionnaire.
The proposed solution of binding in a list per learnrazorpages.com works well for questions for which only one response may be given, however, it seems less apt for handling a multiple choice type of question where the user may provide any number of responses.
The following code does not inject my selections on the multiple choice question into the form submission.
<form method="post">
#for (int i = 0; i <= Model.Questions.Count - 1; i++)
{
var question = Model.Questions[i];
var questionId = Model.Questions[i].Id;
var questionType = Model.Questions[i].Type;
<input type="hidden" id="[#i].QuestionId" name="[#i].QuestionId" value="#questionId" />
#if (questionType == Enums.QuestionType.MultipleChoice)
{
var options = Model.Options.Where(x => x.Question.Id == questionId);
var answers = Model.Answers.WHere(x => x.Question.Id == questionId);
<div class="mb-3">
<p class="mb-0 mt-2">#question.Text</p>
#for (int j = 0; j <= Model.Options.Count() - 1; j++)
{
if (Model.Options[j].Question.Id == questionId)
{
// Determine based on the answer whether or not to check the checkbox.
var option = Model.Options[j];
var isChecked = answers.Any(x => x.Value == option.Id.ToString());
var _checked = isChecked ? "checked" : "";
<div>
<input type="hidden" id="[#j].OptionId" name="[#j].OptionId" value="#option.Id" />
<input class="form-check-input" type="checkbox" id="[#j].Value" name="[#j].Value" value="#option.Id" #_checked />
<label class="form-check-label" for="[#j].Value">#option.Text</label>
</div>
}
}
</div>
}
</form>
I structured it this way thinking it would simply inject the options list into the method parameter value of my OnPost method, since the viewmodel I built for that method accepts the list as a parameter:
public void OnPost(List<AnswerViewmodel> answers)
{
// I haven't got any logic here yet to save the answers so this is just for a breakpoint.
var answered = answers.Where(x => x.Value is not null);
}
public class AnswerViewmodel
{
public int QuestionId { get; set; }
public string Value { get; set; }
public string Comment { get; set; }
public List<OptionViewmodel> Options { get; set; }
}
public class OptionViewmodel
{
public int OptionId { get; set; }
public string Value { get; set; }
}
If the option is selected (checked) then Value will be "true", otherwise "false".
However, the Options list is always null in the value.
How can I get my options to post through to the backend with the rest of the form?
You name attribute of your inputs should be [#i].Options[#j].Value to bind correctly with the List<OptionViewmodel> Options:
<input type="hidden" id="[#j].OptionId" name="[#i].Options[#j].OptionId" value="#option.Id" />
<input class="form-check-input" type="checkbox" id="[#j].Value" name="[#i].Options[#j].Value" value="#option.Id" #_checked />

JQuery submit intervention doesn't add parameter required in Controller method

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>

Values are sent as null when using js prompt

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

Javascript Function in MVC

I am developing an Quiz Application in MVC 5. I have added two tables in database. One for marks and other for Questions and Answers. I have entered data in database for question, answers and have entered bool value as true or false for correct answer and vice versa. I am able to view Question and Answers from database.But I got stuck whenever user checks the checkboxes i want to give him points based on correct or wrong answer. I am not able to write javascript function in order to check whether the checkbox is checked or not.
Javascript:
function scorecheck(id) {
if (document.getElementById(id).checked) {
document.getElementById(id).value = "false";
}
else {
document.getElementById(id).value = "true";
}
}
Razor view:
#using(Html.BeginForm("Score", "Home", FormMethod.Post))
{
foreach (var item in Model) {
#Html.DisplayFor(modelItem => item.Question)
#Html.CheckBox("ans1", new { onchange = "scorecheck()" })
#Html.DisplayFor(modelItem => item.ans1)<br />
#Html.CheckBox("ans2", new { onchange = "scorecheck()" })
#Html.DisplayFor(modelItem => item.ans2)<br />
#Html.CheckBox("ans3", new { onchange = "scorecheck()" })
#Html.DisplayFor(modelItem => item.ans3)<br />
#Html.CheckBox("ans4", new { onchange = "scorecheck()" })
#Html.DisplayFor(modelItem => item.ans4)<br />
}
<input type="Submit" value="Submit" />
}
Also I have written logic for giving points for correct and wrong answer but it is not working.
C#:
int s = 0;
string ans1 = c["ans1"];
if (ans1 == "true")
{
s = s + 20;
}
string ans2 = c["ans2"];
if (ans2 == "false")
{
s = s - 20;
}
string ans3 = c["ans3"];
if (ans3 == "false")
{
s = s - 20;
}
string ans4 = c["ans4"];
if (ans4 == "false")
{
s = s - 20;
}
Here is how you can check the value of checkbox on click:
<input type="checkbox" value="yourvalue" onclick="MyFunc(this)">
and the javascript function:
function MyFunc(control)
{
if(control.checked==true)
//your logic
}
I have used following to get id from checkboxes:
`<input id="#(item.ans1)" type="checkbox" name="ans1" value="#item.ans1" onchange="scorecheck('#(item.ans1)')" /> `
Then I am using Javascript Function to check if its value is true or false like this:
if (document.getElementById(id).checked) {
document.getElementById(id).value = "True";
}
else {
document.getElementById(id).value = "False";
}

date validation mvc3 causing issues

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.

Categories

Resources