Form action called before ajax request - asp.net

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.

Related

Multiple submit button fail to find the handler method in asp.net core 3.1 razor page application

I have a single form which has two button one to upload image using ajax call & other is main submit button which saves all the data.
I am still very new to asp.net core and trying different thing to learn asp.net core with razor page.
I read lot of article about multiple form submit but most of then where using two form with submit button for each.
My issue is when i hit the submit button it fails to find the handler method, after full days troubleshoot nothing worked and last few article point to error/failure to antiforgery, i not sure how to implement it in below code as i tried few but they gave error may be article where old referencing core 2.2 etc example1 example2
I am not sure about the what exactly is causing the issue any help would be appreciate.
I am trying to upload Image using Ajax method in asp.net core Razor pages, I am main form in will all input fields are kept and with the form for Fileupload i am also added addition button which is for file upload using Ajax, When i hit the
<input type="submit" value="Upload Image" asp-page-handler="OnPostUploadImage" id="btnUploadImage" />
i want it to call OnPostUploadImage method in pageModel file but it alway goes to default OnPost method. when i rename the OnPost to OnPost2 nothing happend..
How can i call OnPostUploadImage() on button btnUploadImage click event.
When i hit click btnUploadImage it generates following error on browser console
Error in FF
XML Parsing Error: no root element found Location:
https://localhost:44364/Admin/News/NewsCreate?handler=OnPostUploadImage
Line Number 1, Column 1:
Error in Chrome
jquery.min.js:2 POST
https://localhost:44364/Admin/News/NewsCreateMultipleSubmit?handler=OnPostUpLoadImage
400 (Bad Request)
event though path looks fine but it cant find it as per error message
#page
#model BookListRazor.Pages.Admin.News.NewsCreateModel
#{
ViewData["Title"] = "News Create";
Layout = "~/Pages/Shared/_LayoutAdmin.cshtml";
}
<div class="border container" style="padding:30px;">
<form method="post" enctype="multipart/form-data">
<div class="text-danger" asp-validation-summary="ModelOnly"></div>
<input hidden asp-for="News.NewsImage" />
<input id="fileName" hidden value="" />
<div class="form-group row">
<div class="col-2">
<label asp-for="News.NewsHeading"></label>
</div>
<div class="col-10">
<input asp-for="News.NewsHeading" class="form-control" />
</div>
<span asp-validation-for="News.NewsHeading" class="text-danger"></span>
</div>
<div class="form-group row">
<div class="col-2">
<label asp-for="News.NewsImage"></label>
</div>
<div class="col-10">
#*<input asp-for="News.NewsImage" type="file" class="form-control" id="NewsImage">*#
#*Photo property type is IFormFile, so ASP.NET Core automatically creates a FileUpload control *#
<div class="custom-file">
<input asp-for="NewsImageForUpload" class="custom-file-input form-control">
<label class="custom-file-label">Click here to change photo</label>
<input type="submit" value="Upload Image" asp-page-handler="OnPostUploadImage" id="btnUploadImage" />
</div>
</div>
<span id="imageStatus" class="text-danger"></span>
<span asp-validation-for="NewsImageForUpload" class="text-danger"></span>
</div>
<div class="form-group row">
<div class="col-3 offset-3">
<input id="btnSave" type="submit" value="Create" class="btn btn-primary form-control" />
</div>
<div class="col-3">
<a asp-page="Index" class="btn btn-success form-control">Back to List</a>
</div>
</div>
</form>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="https://cdn.ckeditor.com/4.14.0/full/ckeditor.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script>
$(document).ready(function () {
$("#btnSave").addClass("disable-button");
$('.custom-file-input').on("change", function () {
var fileName = $(this).val().split("\\").pop();
$(this).next('.custom-file-label').html(fileName);
$("#fileName").val(fileName);
$("#btnSave").removeClass("disable-button");
});
if ($("#fileName").val() == "") {
//alert("Select Image...");;
}
});
</script>
</div>
#section Scripts{
<partial name="_ValidationScriptsPartial" />
<script>
$(function () {
$('#btnUploadImage').on('click', function (evt) {
console.log("btnUploadImage");
evt.preventDefault();
console.log("btnUploadImage after evt.preventDefault()");
$.ajax({
url: '#Url.Page("", "OnPostUploadImage")',
//data: new FormData(document.forms[0]),
contentType: false,
processData: false,
type: 'post',
success: function () {
alert('Uploaded by jQuery');
}
});
});
});
</script>
}
.cs file CODE
public async Task<IActionResult> OnPost()
{
if (ModelState.IsValid)
{
return Page();
}
else
{
return Page();
}
}
public IActionResult OnPostUploadImage()
{
//Some code here
}
Verify that you add the following code to the ConfigureServices method of startup.cs:
services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
If you want to enter the OnPostUploadImage method, the url of the Ajax request needs to be changed to #Url.Page("", "UploadImage") without adding OnPost.
And the Ajax request should send the anti-forgery token in request header to the server.
Change your ajax as follow:
#section Scripts{
<partial name="_ValidationScriptsPartial" />
<script>
$(function () {
$('#btnUploadImage').on('click', function (evt) {
console.log("btnUploadImage");
evt.preventDefault();
console.log("btnUploadImage after evt.preventDefault()");
$.ajax({
url: '#Url.Page("", "UploadImage")',
//data: new FormData(document.forms[0]),
contentType: false,
processData: false,
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
type: 'post',
success: function () {
alert('Uploaded by jQuery');
}
});
});
});
</script>
}
You can refer to this for more details.

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>

grab the value of an element in a different template

The code below is trying to grab the username and password from input elements on a template.login and createUser when a button which is in template.footer is clicked.
Being new to javascript and Meteor, my code below probably butchered both.
I thought to make a method call from the footer click event, this call gets the username and password and fires Meteor accounts create and store the returned userId in a local session to be used later. blah..blah..
But how can I get access to input values in one template from another?
so I need your help. Thanks
Template.footer.events({
'click .myClass': function (event, template) {
Meteor.call('loginUser', username,password);
}
});
Meteor.methods({
//store the useId returned from createUser in a local session userId
loginUser: function (username, password) {
Accounts.createUser(username, password, function () {
Session.set(userId, this.value);
});
}
});
<template name="footer">
<footer>
<nav class="navbar navbar-default navbar-fixed-bottom">
<div class="container">
<div class="row">
{{#each footerButtons}}
<h2>
<button class="col-xs-{{footerButtonsScaling}} myClass" type="button">{{text.toUpperCase}}</button>
</h2>
{{/each}}
</div>
</div>
</nav>
</footer>
</template>
<template name="login">
<form action="">
<input type="text" name="username" placeholder="type your ID" value="{{username}}">
<input type="password" name="password" placeholder="type your PIN" value="{{password}}">
</form>
</template>
You can just use jQuery to access field values anywhere in the DOM:
var username = $('[name="username"]').val();
var password = $('[name="password"]').val();

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