ajax post of form and validation - asp.net

Does ajax post supports the usual validation upon submit of a form?
Is
#using(Html.BeginForm()){
#Hml.ValidationSummary()
<input type="submit" value ="Save">
}
same as
#using(Html.BeginForm(new {id=FormTest})){
#Hml.ValidationSummary()
<input type="button" value= Save>
}
<script type="javascript">
$("#Save").click(function(){
$("#FormTest").submit();
});
</script>

There are so many wrong things going on here that I really don't know where to start.
Your Html.BeginForm definition is wrong: you are confusing routeValues with htmlAttributes. See below for solution
Your button doesn't have an id so your javascript selector will most probably fail
All those efforts are not necessary because a simple <input type="submit"> button does it out of the box.
Now lets suppose that somehow you are a fan of javascript and you want to write it (I don't know why would you want to write code but anyway). So start by fixing your form definition:
#using(Html.BeginForm("someAction", "someController", FormMethod.Post, new { id = "FormTest" }))
{
#Html.ValidationSummary()
#Html.TextBoxFor(x => x.Foo)
<input type="button" value="Save" id="Save" />
}
and then you could do this:
$('#Save').click(function() {
var form = $('#FormTest');
if (form.valid()) {
form.submit();
}
});
obviously you must ensure that the client scripts are properly included on your page:
<script src="#Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
and of course the real solution I would recommend you is to use a submit button for submitting forms:
#using(Html.BeginForm("someAction", "someController", FormMethod.Post, new { id = "FormTest" }))
{
#Html.ValidationSummary()
#Html.TextBoxFor(x => x.Foo)
<input type="submit" value="Save" id="Save" />
}
Now you don't need any javascript (obviously you still need the two script inclusions for the unobtrusive validation).

Related

Form action called before ajax request

I'm trying to validate some data using javascript, so after created this form:
<form asp-controller="User" asp-action="UpdateUser" asp-antiforgery="true" id="userInformations">
<div class="form-group">
<label class="col-lg-6 control-label">#Localizer["OldPassword"] (*)</label>
<div class="col-lg-12">
<input class="form-control" required id="oldPassword"
asp-for="#Model.ExistingPassword" type="password" />
</div>
<div class="form-group">
<label class="col-lg-6 control-label">#Localizer["NewPassword"] (*)</label>
<div class="col-lg-12">
<input class="form-control" required id="newPassword"
asp-for="#Model.Password" type="password" />
</div>
</div>
<button type="submit" class="btn btn-primary">Store</button>
</form>
I binded a javascript function that intercept the submit:
$('#userInformations').on('submit', function (event) {
event.preventDefault();
//validate some fields
//execute ajax request
$.ajax({
url: $(this).attr('action'),
type: "POST",
data: $(this).serialize(),
success: function (result) {
alert(true);
console.log(result)
},
error: function (data) {
console.log(data);
}
});
});
Now when I press the submit button, the method UpdateUser in the UserController is called first of the javascript function, and I don't understand why happen this because I used preventDefault.
How can I prevent to call the asp net action binded to the form?
The effect you want is to use javascript to validate some data , and implement the action call through ajax when you press the submit button?
I use the code you provided and it works.
Try the following two ways:
1.Add the following piece of code above your javascript
<script src="~/lib/jquery/dist/jquery.js"></script>
2.Or directly write your javascript in #section Scripts { }
If you want JavaScript first than you have to remove asp-Controller and action from form, than you can validate form by JavaScript and send data through Ajax call to Controller/action.

How to dynamically set 'was-validated' class on form to show validation feedback messages with angular 5 after submit

I am using a template based form in angular. I also use bootstrap (v4) and I wish to show some validation messages when the form was submitted.
This is my form:
<form [ngClass]="{'was-validated': wasValidated}">
<div class="form-group">
<label for="name">Name</label>
<input type="text" id="name" name="name" class="form-control" [(ngModel)]="category.name" #name="ngModel" required maxlength="100"/>
<div *ngIf="name.invalid" class="invalid-feedback">
<div *ngIf="name.errors.required">
Name is required.
</div>
</div>
</div>
<button type="submit" class="btn btn-success" (click)="save()">Save</button>
</form>
My component looks as follows:
category: Category;
wasValidated: boolean = false;
ngOnInit() {
this.reset();
}
save() {
this.wasValidated = true;
this.categoriesService.createCategory(this.category).subscribe(
() => {
this.notificationService.add(notifications.category_saved, {name: this.category.name});
this.reset();
},
() => this.notificationService.add(notifications.save_category_failed)
);
}
reset() {
this.wasValidated = false;
this.category = {} as Category;
}
This works, but I have a feeling it's overly complex and more like a workaround rather than the right way. What is the best way to accomplish this?
Note: the class was-validated must be present on the form element in order to show the div with class invalid-feedback. I'm using this: https://getbootstrap.com/docs/4.0/components/forms/#validation
Note 2: I have currently no mechanism yet to prevent form submission on error. I'd like to know a good solution for that as well!
With the answer from #Chellappan V I was able to construct the solution I wanted.
I have applied to following changes:
First added #form="ngForm" to the form tag in the template. Secondly I changed the ngClass expression to reference the submitted state of the form, rather than referring to a boolean which was set to true manually when form was submitted. Last but not least I pass the form in the submit method on the save button.
<form novalidate #form="ngForm" [ngClass]="{'was-validated': form.submitted}">
<!-- form controls -->
<button type="submit" class="btn btn-success" (click)="submit(form)">Save</button>
</form>
In the component I injected the template variable in the component with #ViewChild.
#ViewChild("form")
private form: NgForm;
The submit method now takes a form parameter of type NgForm which is used to check if the form was valid before sending a request to the backend:
submit(form: NgForm) {
if (form.valid) {
this.categoriesService.createCategory(this.category).subscribe(
() => {
this.notificationService.add(notifications.category_saved, {name: this.category.name});
this.reset();
},
() => this.notificationService.add(notifications.save_category_failed)
);
} else {
this.notificationService.add(notifications.validation_errors);
}
}
Finally the reset method resets the form and the model so it can be re-entered to submit a next instance:
reset() {
this.form.resetForm();
this.category = {} as NewCategoryDto;
}

Calling a controller action using AJAX with an anchor vs a button

I have a IActionResult on my controller that returns a Partial View via AJAX:
[HttpGet]
[Route("/propertycoverages/loss")]
public IActionResult GetNewLoss()
{
return PartialView("_Loss");
}
If I put an <a> tag in my Razor view with the following:
<a asp-controller="PropertyCoverages" asp-action="GetNewLoss" id="loss-btn" data-ajax="true" data-ajax-update="losses" data-ajax-success="addLoss" data-ajax-method="GET">Add</a>
the following HTML attribute gets generated in the <a> tag: href="/propertycoverages/loss"
it works as expected and the partial view is returned within the page. However, if I try to use a button:
<button asp-controller="PropertyCoverages" asp-action="GetNewLoss" id="loss-btn" type="submit" data-ajax="true" data-ajax-update="losses" data-ajax-success="addLoss" data-ajax-method="GET">Add</button>
the following HTML attribute gets generated in the <button> tag: formaction="/propertycoverages/loss"
and I get redirected to /propertycoverages/loss which is not what I want. Is there a way I can make the button behave like the <a> tag?
Note: These elements are inside a <form>. I also tried switching the <button> from type="submit" to type="button" but the controller action doesn't get called.
You will want to attach a JavaScript method to your button click action.
<button onclick="myFunction()">Click me</button>
In the JS method you can call back to the action get the HTML and lay in on the page in the AJAX call success method.
function onClick() {
var url = [setURL];
$.ajax({
type: "GET",
url: url,
data: { },
success: function (response) {
$('#[setElementToReplace]').html(response);
}
});
}
Hi there are mainly three ways for calling the controller action from the submit button.
Way1: Using simple Form
#using (Html.BeginForm("ActionName", "ControllerName"))
{
<input type="submit" name="add" value="Add" />
}
Note: By default it is a get request, If required you can change formmethod = post
Way 2: Using html Attributes
#using (Html.BeginForm())
{
<input type="submit" name="add" value="Add" formaction="/anycontrollername/anyactionname" formmethod="get"
/>
}
Way 3 : using jquery
#using (Html.BeginForm())
{
<input type="submit" name="add" value="Add" id=”save”
/>
}
$(document).ready(function () {
$("#save").click(function () {
$("form").attr("action", "/anycontroller /anyaction");
});
});
It seems that 2nd way will be suitable for your requirement,
Hope the above answer was useful.

ASP.NET MVC - prevent submit of invalid form using jQuery unobtrusive validation

I have an ASP.NET project that automatically wires up client side validation using jQuery.Validate and the unobtrusive wrapper built by ASP.NET.
a) I definitely have the appropriate libraries: jquery.js, jquery.validate.js, & jquery.validate.unobtrusive.js
b) And the MVC rendering engine is definitely turned on (ClientValidationEnabled & UnobtrusiveJavaScriptEnabled in the appSettings section of the web.config)
Here's a trivial example where things are broken:
Model:
public class Person
{
[Required]
public string Name { get; set; }
}
Controller:
public ActionResult Edit()
{
Person p = new Person();
return View(p);
}
View:
#model validation.Models.Person
#using (Html.BeginForm()) {
#Html.ValidationSummary(false)
#Html.LabelFor(model => model.Name)
#Html.EditorFor(model => model.Name)
}
This generates the following client side markup:
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.15.1/jquery.validate.js"></script>
<script type="text/javascript" src="https://ajax.aspnetcdn.com/ajax/mvc/3.0/jquery.validate.unobtrusive.js"></script>
<form action="/Person" method="post">
<div class="validation-summary-valid" data-valmsg-summary="true">
<ul><li style="display:none"></li></ul>
</div>
<label for="Name">Name</label>
<input data-val="true" data-val-required="The Name field is required." id="Name" name="Name" type="text" value="" />
<input type="submit" value="Save" />
</form>
When run it will perform the client side validation, noting that some form elements are invalid, but then also post back to the server.
Why is it not preventing postback on a form with an invalid state?
The Problem
It turns out this happens when you don't include a #Html.ValidationMessageFor placeholder for a given form element.
Here's a deeper dive into where the problem occurs:
When a form submits, jquery.validate.js will call the following methods:
validate: function( options ) {
form: function() {
showErrors: function(errors) {
defaultShowErrors: function() {
showLabel: function(element, message) {
this.settings.errorPlacement(label, $(element) )
Where errorPlacement will call this method in jquery.validate.unobtrusive.js:
function onError(error, inputElement) {
var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
replace = $.parseJSON(container.attr("data-valmsg-replace")) !== false;
When we don't add a placeholder for the validation message, $(this).find(...) won't find anything.
Meaning container.attr("data-valmsg-replace") will return undefined
This poses a problem is when we try to call $.parseJSON on an undefined value. If an error is thrown (and not caught), JavaScript will stop dead in its tracks and never reach the final line of code in the original method (return false) which prevents the form from submitting.
The Solution
Upgrade jQuery Validate Unobtrusive
Newer versions of jQuery Validate handle this better and check for nulls before passing them to $.parseJSON
function onError(error, inputElement) { // 'this' is the form element
var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
replaceAttrValue = container.attr("data-valmsg-replace"),
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;
Add ValidationMessageFor
To address the core problem, for every input on your form, make sure to include:
#Html.ValidationMessageFor(model => model.Name)
Which will render the following client side markup
<span class="field-validation-valid" data-valmsg-for="Name" data-valmsg-replace="true"></span>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.15.1/jquery.validate.js"></script>
<script type="text/javascript" src="https://ajax.aspnetcdn.com/ajax/mvc/3.0/jquery.validate.unobtrusive.js"></script>
<form action="/Person" method="post">
<div class="validation-summary-valid" data-valmsg-summary="true">
<ul><li style="display:none"></li></ul>
</div>
<label for="Name">Name</label>
<input data-val="true" data-val-required="The Name field is required." id="Name" name="Name" type="text" value="" />
<span class="field-validation-valid" data-valmsg-for="Name" data-valmsg-replace="true"></span>
<input type="submit" value="Save" />
</form>

How to get the right submit from a form in a list of forms in meteor?

I have a list of forms in a page of my meteor app, the list is generated dynamically and all the forms have the same class.
So i made the event submit on the events area of my template, but when i submit the form, only the first form works, if i submit the second form for example, meteor event understand that the event came from the first, and i don'k know how to pass the form id to meteor events, so i can't get the data from the right form. Someone can help me?
This is my event:
'submit .form-equation': function (e, t) {
e.preventDefault();
var name = t.find('#name').value,
equation = t.find('#equation').value,
order = Number(t.find('#order').value),
isChart = t.find('#isChart').checked;
var equationData = {
name: name,
equation: equation,
order: order,
isChart: isChart
};
var station = Stations.findOne(Session.get('stationNewID'));
var sensorId = t.find('#sensorId').value;
Meteor.call('insertEquation', station, sensorId, equationData, function (error, result) {
if (error)
console.log(error);
});
}
I think there is something else wrong with your application. The behavior you described (having multiple forms of the same class with different IDs) works correctly on a clean example.
Check out the demo I made that demonstrates this: http://meteorpad.com/pad/8CPL2xvS7taeL6jZS/MultipleFormSubmitExample
Basically, the forms look like this:
<template name="example">
<form id="1" class="yolo">
<input type="submit" value="Submit">
</form>
<form id="2" class="yolo">
<input type="submit" value="Submit">
</form>
<form id="3" class="yolo">
<input type="submit" value="Submit">
</form>
</template>
And there is only one event listener:
Template.leaderboard.events({
'submit .yolo': function (e, t) {
e.preventDefault();
alert($(e.target).attr('id'));
}
});

Resources