Razor pages jQuery function validation issue - c#

I have a form in Razor Pages .NET Core and inside this form I have a dropdown. This dropdown takes it's values (strings) from a jQuery function like this:
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script>
$(function () {
$("#StartDate").on("change", function () {
var time = $(this).val();
$("#select").empty();
$("#select").append("<option value=''>select </option>");
$.getJSON(`?handler=Time&time=${time}`, (data) => {
$.each(data, function (i, item) {
*$("#select").append("<option value='" + "'>" + item.hours + "</option>");*/
$("#select").append($("<option>").val(item.hours).text(item.hours));
});
});
});
});
</script>
<form method="post" id="myForm">
<div class="form-group">
<h6><label class="col-form-label">Time</label></h6>
<select id="select" asp-for="Time" class="form-control"></select>
<span class="text-danger" asp-validation-for="Time"></span>
</div>
</form>
Backend:
[Required(ErrorMessage = "Field cannot be empty!")]
[BindProperty]
public string Time { get;set; }
public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
return Page();
}
}
My issue is that after I submit my form, the ModelState.IsValid check always fails.
After some research, I found out that the reason is in my jQuery function because the added values are not validated.
I tried adding this line to my function, but it did not help:
$.validator.unobtrusive.parse("#myForm");
Right now, what it happens is that if I select a value from the dropdown, the ModelState won't be valid and returns the page

In my code:
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="StartDate" class="control-label"></label>
<input asp-for="StartDate" class="form-control" min="#DateTime.Now.ToString("yyyy-MM-ddThh:mm")" max="2050-06-01T00:00" />
<span asp-validation-for="StartDate" class="text-danger"></span>
</div>
<select id="select" asp-for="Time" class="form-control"></select>
<span class="text-danger" asp-validation-for="Time"></span>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
<script>
$(function () {
$("#StartDate").on("change", function () {
var time = $(this).val();
$("#select").empty();
$("#select").append("<option value=''>select </option>");
$.getJSON(`?handler=Time&time=${time}`, (data) => {
$.each(data, function (i, item) {
*$("#select").append("<option value='" + "'>" + item.hours + "</option>");*/
$("#select").append($("<option>").val(item.hours).text(item.hours));
});
});
});
});
When I select a value from the dropdown,it will pass the validate,You can make an endpoint in your OnPost action.Below is my test,you can see which column failed the verification.

Related

Submitting a post form with success message from Layout in Asp.Net core

I need to create a newsletter form in my footer, so I had to include it in my layout.
I have successfully created the form using:
<footer>
<form method="post" asp-controller="NewsletterSubscriptions" asp-action="Create" data-ajax="true" data-ajax-method="post" data-ajax-success="success" data-ajax-completed="completed">
<div class="newsletter" id="newsletter">
<div class="form-group">
<input type="text" id="FullName" name="FullName" data-provide="FullName" class="form-control" placeholder="name" autocomplete="off">
</div>
<div class="form-group">
<input type="email" id="Email" name="Email" data-provide="Email" class="form-control" placeholder="email" autocomplete="off">
</div>
</div>
<div class="newsletter-btn">
<input type="submit" value="ok" />
</div>
</form>
</footer>
And in Head:
<head>
<script src="#Url.Content("/lib/jquery-validation/dist/jquery.validate.js")"></script>
<script src="#Url.Content("/lib/jquery-validation/dist/additional-methods.js")"></script>
<script src="#Url.Content("/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js")"></script>
<script>
success = function () {
alert("Hi !");
};
</script>
<script>
completed = function (xhr) {
alert("Hi ${xhr.responseText}!");
};
</script>
</head>
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("FullName,Email")] NewsletterSubscription newsletterSubscription)
{
if (ModelState.IsValid)
{
_context.Add(newsletterSubscription);
await _context.SaveChangesAsync();
return Redirect(Request.Headers["Referer"]+ "#newsletter");
}
else
return View(newsletterSubscription);
}
When I submit, page is refreshed, form is submitted successfully, user is redirected to same page footer area.
But success, or completed functions are not triggered. what am I doing wrong?
Write your form tag as follows:
<div id="success-message-container" class="alert alert-success text-center d-none">
<strong>Success!</strong> You have been subscribed successfully!
</div>
<div id="failure-message-container" class="alert alert-danger text-center d-none">
<strong>Failure!</strong> There is some problem with the service.Please try again.If the problem persists
please contract with system administrator!
</div>
<form id="newsLetterForm" method="post" asp-controller="NewsletterSubscriptions" asp-action="Create">
// Your form contents
</form>
Then in the JavaScript :
$(document).on("submit", "#newsLetterForm", function (event) {
event.preventDefault();
event.stopImmediatePropagation();
var formData = new FormData(this);
var url = this[0].action; // if this does not work then use '#Url.Action("Create","NewsletterSubscriptions")'
$.ajax({
url: url,
type: 'POST',
data: formData,
success: function (response) {
if (response) {
document.getElementById("newsLetterForm").reset();
$("#newsLetterForm input,textarea").removeClass('valid');
$("#success-message-container").removeClass("d-none");
setTimeout(function () {
$("#success-message-container").addClass("d-none");
}, 5000);
}
},
error: function () {
$("#failure-message-container").removeClass("d-none");
setTimeout(function () {
$("#failure-message-container").addClass("d-none");
}, 5000);
},
cache: false,
contentType: false,
processData: false
});
return false;
});
Note: css classes I have used is from Bootstrap 4

PartialViewResult Form will not clear values on ajax result - ASP.NET Core Razor c#

I have a simple contact message form written in razor asp.net and c#. Whenever the form is submitted, I am able to render the server response with no issues but for some reason, all of the input fields are maintaining the same values.
Here is the partial view:
#using PublicWebsite.Models.Contact;
#model ContactFormViewModel
<form role="form" id="contactForm" data-toggle="validator" method="post" asp-controller="Contact" asp-action="SubmitMessage">
#if (!string.IsNullOrWhiteSpace(Model.ServerResponse))
{
<div class="form-group">
<div class="row">
<div class="col-md-12">
<div class="alert #(Model.ServerResponseSuccess ? "alert-success" : "alert-danger")" role="alert">
#Model.ServerResponse
</div>
</div>
</div>
</div>
}
<div class="form-group">
<div class="row">
<div class="col-md-12">
<div class="form-group">
<div class="prepend-icon">
<input type="text" asp-for="#Model.Name" name="Name" class="form-control input-lg" placeholder="Your Full Name" maxlength="50" required>
<i class="nc-icon-outline users_single-03"></i>
</div>
<div class="help-block with-errors"></div>
</div>
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<div class="prepend-icon">
<input type="email" asp-for="#Model.Email" name="Email" class="form-control input-lg" placeholder="Email" maxlength="200" required />
<i class="nc-icon-outline ui-1_email-85"></i>
</div>
<div class="help-block with-errors"></div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<div class="prepend-icon">
<input type="tel" asp-for="#Model.Phone" name="Phone" class="form-control input-lg" placeholder="Phone Number" maxlength="25" required>
<i class="nc-icon-outline ui-2_phone"></i>
</div>
<div class="help-block with-errors"></div>
</div>
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-md-6">
<select class="form-control" asp-for="#Model.ContactReason" name="ContactReason" data-container-class="input-lg" required style="height:46px !important">
<option value="">Choose a Reason</option>
<option value="Home Remediation">Home Remediation</option>
<option value="Commercial Remediation">Commercial Remediation</option>
<option value="Employment Opportunities">Inquire about employment oppotunities</option>
<option value="Other">Other</option>
</select>
</div>
<div class="col-md-6">
</div>
</div>
</div>
<div class="form-group">
<textarea asp-for="#Model.Message" class="form-control" rows="10" name="Message" placeholder="Message" required></textarea>
<div class="help-block with-errors"></div>
</div>
<div class="form-group">
<div class="g-recaptcha" data-sitekey="mysitekeyishere"></div>
<input type="hidden" name="RecaptchaResponse" value="" />
</div>
<button type="submit" id="form-submit" class="btn btn-primary btn-lg icon-left-effect"><i class="nc-icon-outline ui-1_email-85"></i><span>Send message</span></button>
<div id="msgSubmit" class="hidden"></div>
</form>
Here is a look at the viewmodel:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace PublicWebsite.Models.Contact
{
public class ContactFormViewModel
{
[StringLength(50)]
public string Name { get; set; } = "";
[StringLength(200)]
public string Email { get; set; } = "";
[StringLength(25)]
public string Phone { get; set; } = "";
[StringLength(50)]
public string ContactReason { get; set; } = "";
public string Message { get; set; } = "";
[StringLength(250)]
public string ServerResponse { get; set; } = "";
public bool ServerResponseSuccess { get; set; } = false;
}
}
Inside of the Contact Index CSHTML page for Contact, I render the partial view without any issues.
#section Scripts {
<script src="#validatorPath"></script>
<script type="text/javascript">
$(function () {
$(document).on('submit', '#contactForm', function (e) {
$form = $(this);
$url = $form.attr('action');
$.ajax({
type: "POST",
url: $url,
data: $form.serialize(), // serializes the form's elements.
success: function (data) {
loadFormData(data); //This works
resetCaptcha();
},
error: function (data) {
alert(data);
}
});
e.preventDefault(); // avoid to execute the actual submit of the form.
});
function loadFormData(data) {
$formContainer = $('.contact-form-container');
$formContainer.empty();
$formContainer.html(data);
console.log(data); //This reports back the same results
}
function resetCaptcha() {
//reset captcha
$('.g-recaptcha').empty();
$.getScript('#recaptchaUrl');
}
});
</script>
}
<div class="col-md-7 contact-form-container">
#{ await Html.RenderPartialAsync("_ContactForm", new ContactFormViewModel()); }
</div>
Everything renders properly. As seen in the screenshot below.
Once the items are filled out, the following sendmessage function is called as seen in the scripts section above.
[HttpPost]
public async Task<IActionResult> SubmitMessage(ContactFormViewModel contactForm)
{
var captchaResponse = Request.Form["g-recaptcha-response"].ToString();
if (string.IsNullOrWhiteSpace(captchaResponse))
{
contactForm.ServerResponse = _errorCaptchaMessageBlank;
}
else
{
if (await ValidCaptcha(captchaResponse))
{
try
{
await SendCustomerMessage(contactForm);
var customerName = contactForm.Name;
//This works
contactForm = new ContactFormViewModel
{
ServerResponse = String.Format(_successfulSendMessage, customerName.Split(' ')[0]),
ServerResponseSuccess = true
};
}
catch
{
contactForm.ServerResponse = _errorCaptchaMessageInvalid;
}
}
else
{
contactForm.ServerResponse = _errorCaptchaMessageInvalid;
}
}
//This works and I get the response back on the front end
return PartialView("_ContactForm", contactForm);
}
You can even see the message errors on a successful attempt to the server (i.e. the server response as shown in the HTML) and it keeps the user's info as it should so they don't have to re-enter the data as shown in the image below.
Now on success, notice in the code above I create a new Contact Form with cleared values and a success message. However, the same information stays filled in like below. I want the contact form to be cleared out.
I have attempted even just returning back a completely new view model but still have the same problem where all of the data is almost cached. In my console.log response from the server, I get a partial view result with the values pre-filled so I know it's not a browser issue. Even when I debug the CSHTML page, I only see the server response and the success = true, all other fields are blank.
Any help to figure out why the server is still returning a partial view result with the filled in data would be much appreciated.
You can add this to your success callback function:
$('#contactForm').find('input[type=text], textarea, select').val('');
It basically finds all input fields within the form and clears out their values.
Try to change your success callback function like below:
success: function () {
document.getElementById("contactForm").reset();
},
Clearing model state helped to resolve a similar problem when Partial method returned messed-up data:
public PartialViewResult OnPostData()
{
...
ViewData.ModelState.Clear();
return Partial("_ViewName", model);
}

Jquery .ajaxForm() submit gives 404 error but URL is correct ASP.Net MVC

HTML Form
<form id="form_CreateAccount" method="post" action="#Url.Action("CreateAccount","Account")" autocomplete="off">
<div class="col-md-3 form-group">
<label>Account Name*</label>
<input type="text" name="AccountName" class="form-control" required/>
</div>
<div class="col-md-3 form-group">
<label>Account Type</label>
#Html.DropDownList("AccountTypeId",new SelectList(ViewBag.AccountTypes,"Id","Type"), new {#class="form-control"})
</div>
<div class="col-md-3 form-group">
<button type="submit" class="btn btn-success adjust-btn">Create</button>
</div></form>
JQuery .ajaxForm() method:
$("#form_CreateAccount").validate();
$("#form_CreateAccount").ajaxForm({
beforeSubmit: function () {
return $("#form_CreateAccount").valid();
},
dataType: "json",
success: function (res) {
if (res.success === true) {
else {
}
}
})
This is my Controller
public class AccountController : Controller
{
IAccountService _accountSrvc;
[HttpPost]
public JsonResult CreateAccount(Account account)
{
var res = _accountSrvc.CreateAccount(account);
return Json(new { success = res });
}
}
Without .ajaxForm() method, this form submits successfully but when I submit the form using .ajaxForm() it gives me error 404
beforeSubmit: function () {
return $("#form_CreateAccount").valid();
}
Semicolon after .valid() is causing the problem.

View component not rendering properly through AJAX

I've built a site where users can alter various types of data through multiple view components. When I call these view components on initial page load everything works fine. However when I try refreshing a view component through an ajax call, any lists in those view components repeat a single element multiple times, and my jquery functions stop working.
Here is my main view:
#model ContractModel
#using Portal.ViewComponents
#{
ViewData["Title"] = "Contract View";
}
...
<div id="ResultModel_Scope_Facplan">
#await Component.InvokeAsync("ContractPart", new { contractPartName = "Model_Scope_Facplan", projectName = Model.ProjectName })
</div>
My ajax:
#section Scripts {
<script>
$.ajaxSetup({ cache: false });
$(".PartialButton").click(function (event) {
event.preventDefault();
var ElementID = event.target.id.split("-");
var contractPart = ElementID[0];
var contractAction = ElementID[1];
var actionValue = ElementID[2];
console.log($("#Form" + contractPart + actionValue).serialize() + "&ProjectName=#(Model.ProjectName)&contractAction=" + contractAction);
console.log(ElementID);
$.ajax({
url: "#(Url.Action(""))/" + contractPart,
type: "POST",
data: $("#Form" + contractPart + actionValue).serialize()+"&ProjectName=#(Model.ProjectName)&contractAction=" + contractAction,
success: function (data) {
//Fill div with results
alert(data);
//debugger;
$("#Result" + contractPart).html(data);
},
error: failedSearch(contractPart)
});
});
function failedSearch(ElementID) {
// alert(ElementID + " failed!");
// $("#Result"+ElementID).html = "There was a problem in the search. Please try again later.";
}
</script>
}
My actual view component invoke is pretty simple (just sends the right data to the right view).
public IViewComponentResult Invoke(string contractPartName, string projectName)
{
return View(contractPartName, FindContractPart(contractPartName, projectName));
}
And the view component template:
#model IEnumerable<Model_Scope_Facplan>
#if (#Model != null)
{
<div class="row">
Care Provider Payer
</div>
#for (int i = 0; i < Model.Count(); i++)
{
<form id="FormModel_Scope_Facplan#(i)" action="">
<div class="form-horizontal">
<div class="col-md-3">
<input asp-for=#Model.ElementAt(i).CareProviderID class="form-control" />
</div>
<div class="col-md-3">
<input asp-for=#Model.ElementAt(i).PayerID class="form-control" />
</div>
<span class="glyphicon glyphicon-minus DeleteItem PartialButton" style="color:blue;" id="Model_Scope_Facplan-Delete-#(i)"></span>
</div>
</form>
<br/>
}
<form id="FormModel_Scope_Facplan#(Model.Count())" action="">
<div class="form-horizontal">
<div class="col-md-3">
<input name=CareProviderID class="form-control" />
</div>
<div class="col-md-3">
<input name=PayerID class="form-control" />
</div>
<span class="glyphicon glyphicon-plus AddItem PartialButton" style="color:blue;" id="Model_Scope_Facplan-Create-#(Model.Count())"></span>
</div>
</form>
}
The viewcomponent is returning the correct view template, and in debugging I can see that the ViewComponentResult.ViewData.Model includes the appropriate entries in the list. However the page updated after the ajax call includes only a single element over and over. What am I doing wrong?
Seems like my for loop in the view was breaking - I'm guessing the ElementAt(i) function didn't work after the ajax call for some reason. I ended up switching to a foreach loop and now everything works.

Embed Html `alert()` inside C# method call to display alert window MVC

I am trying to add Html code inside a #functions {} codeblock where if it matches some condition it will alert the user.
this is what I have so far, and I am getting the error CS0103: The name 'alert' does not exist in the current context
this is the code piece that is throwing the error.
#functions{
void doSomething(){
if(ViewBag.token != null){
#alert("#ViewBag.token");
}
}
}
Is there a way to embed alert() inside a C# code-block within .cshtml
this is the entire code which this function is in
#using System.Web.Mvc
#using System.Web.Mvc.Html
#using System
#using System.Web.UI
#model Dependency_Injection_MEF_MVC.Models.Payment
#section Scripts{
<script type="text/javascript" src="https://js.stripe.com/v2/"></script>
<script type="text/javascript">
Stripe.setPublishableKey('pk_test_6pRNASCoBOKtIshFeQd4XMUh');
</script>
<script type="text/javascript">
$(function () {
var $form = $('#payment-form');
$form.submit(function (event) {
// Disable the submit button to prevent repeated clicks:
$form.find('.submit').prop('disabled', true);
// Request a token from Stripe:
Stripe.card.createToken($form, stripeResponseHandler);
// Prevent the form from being submitted:
return false;
});
});
function stripeResponseHandler(status, response) {
// Grab the form:
var $form = $('#payment-form');
if (response.error) { // Problem!
// Show the errors on the form:
$form.find('.payment-errors').text(response.error.message);
$form.find('.submit').prop('disabled', false); // Re-enable submission
} else { // Token was created!
// Get the token ID:
var token = response.id;
ViewBag.token = token;
// Insert the token ID into the form so it gets submitted to the server:
$form.append($('<input type="hidden" name="Token">').val(token));
// Submit the form:
$form.get(0).submit();
}
};
</script>
}
<div class="row">
<div class="col-md-12 form-column">
<div class="form-container">
<form asp-controller="home" asp-action="processpayment" method="POST" id="payment-form">
<span class="payment-errors"></span>
<div class="form-group">
<h3>Membership Amount: USD XX</h3>
</div>
<div class="form-group">
<label for="cardNumber">Card Number</label>
<input class="form-control form-input" id="cardNumber" type="text" size="20" data-stripe="number" style= "width:250px;height:25px;font-size:120%">
</div>
<div class="form-group">
<label>Expiration (MM/YY)</label>
<div>
<input class="form-control form-input date-input" type="text" size="2" data-stripe="exp_month" style= "width:250px;height:25px;font-size:120%">
<input class="form-control form-input date-input" type="text" size="2" data-stripe="exp_year" style= "width:250px;height:25px;font-size:120%">
</div>
</div>
<div class="form-group">
<label for="cvc">CVC</label>
<input class="form-control form-input" id="cvc" type="text" size="4" data-stripe="cvc" style= "width:250px;height:25px;font-size:120%">
</div>
<input class="btn btn-default" onclick="doSomething()" id="submit" value="Submit Payment">
</form>
</div>
</div>
</div>
#functions{
void doSomething(){
if(ViewBag.token != null){
alert("#ViewBag.token");
}
}
}
Functions are intended to be completely server-side. But that script can be easily embeddable; if you move that to the page where you want it called, just do:
#if(ViewBag.token != null){
<script>
alert("#ViewBag.token");
</script>
}
And this will get rendered if the token exists. Functions aren't needed for this; this could be inside of a #helper though.

Categories

Resources