Unobtrusive validation doesn't work with Ajax.BeginForm - asp.net-mvc

I have View with Model1 where I put Ajax.BeginForm() and in this View i have PartialView with Model2 where i put Ajax.BeginForm(). So only in first form working unobtrusive validation. Why only in first form working validation?
first View
#model Model1
#using (Ajax.BeginForm("Action1","Controller",null,new AjaxOption(){ onSuccess = "alert('=)')"},null)
{
<intput type="submit" value="Save" />
}
Model2 model2 = new Model2();
#Html.EditorFor(m=>model2)
**In Model2 view i have. **
#model Model2
#using (Ajax.BeginForm("AddStreet","Controller",new AjaxOption(){onSuccess = "alert('=)'")},option,null)
{
#Html.LabelFor(m => Model.Name):
#Html.TextBoxFor(m => Model.Name)
#Html.ValidationMessageFor(m => Model.Name)
<intput type="submit" value="Save" />
}
Thanks #Darin Dimitrov for answer.

That's because the second view is loaded with AJAX at a later stage and you need to call $.validator.unobtrusive.parse(...)
immediately after its contents is injected into the DOM in order to enable unobtrusive validation. Look at the following blog post for more details.
So in your case, instead of alerting in the OnSuccess callback of the first AJAX call, subscribe to a javascript function which will invoke this method:
#using (Ajax.BeginForm(
"Action1",
"Controller",
null,
new AjaxOptions {
OnSuccess = "onSuccess",
UpdateTargetId = "result"
},
null)
)
{
<input type="submit" value="Save" />
}
and then in your javascript file:
var onSuccess = function(result) {
// enable unobtrusive validation for the contents
// that was injected into the <div id="result"></div> node
$.validator.unobtrusive.parse($(result));
};

You need to add those 2 files in you Partial View even if it is already in the Shared/_Layout.cshtml:
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
Or place this in your Partial:
<script type="text/javascript" language=javascript>
$.validator.unobtrusive.parse(document);
</script>

This solution worked best for me.
$.validator.unobtrusive.parse(document);

The answer of Darin Dimitrov only works when validate() of the jquery validate plugin has not been called until the Ajax success handler is called. I can't think of a scenario where this could be the case, thus i wonder why the answer was accepted as correct.
Perhaps a change in the jquery validate code in the past now causes the following issue:
The issue is that validate() executes the following line first
// Check if a validator for this form was already created
var validator = $.data( this[ 0 ], "validator" );
if ( validator ) {
return validator;
which means that the validator object is returned when validate() is called without and further handling of the options passed.
This also means that a later call to $.validator.unobtrusive.parse(...) or $.validator.unobtrusive.parseElement(...) which executes a
$form.validate(this.options) <- this.options holds the new rules parsed from HTML
to update the options of the validator has no effect because the options are not processed at all.
The solution here is to update the validator manually like
var $htmlCode = $("your html");
$.validator.unobtrusive.parse($htmlCode, true); // true means no validate() call
// now get the validation info collected in parse()
var validationInfo = $form.data("unobtrusiveValidation");
var $validator = $form.validate(); // get validator and ...
$validator.settings.rules = validationInfo.options.rules; // ... update its rules
$validator.settings.messages = validationInfo.options.messages; // ... update its messages
Revalidating the form (e.g. clicking submit) should now result in the expected results.
Here is a full example witch also includes code from the already accepted answer:
Razor
#using (Ajax.BeginForm(
"Action1",
"Controller",
null,
new AjaxOptions {
OnSuccess = "onSuccess",
UpdateTargetId = "result"
},
null)
)
{
<input type="submit" value="Save" />
}
Javascript
var onSuccess = function(result) {
var $htmlCode = $(result);
$.validator.unobtrusive.parse($htmlCode, true); // true means no validate() call
// now get the validation info collected in parse()
var validationInfo = $form.data("unobtrusiveValidation");
var $validator = $form.validate(); // get validator and ...
$validator.settings.rules = validationInfo.options.rules; // ... update its rules
$validator.settings.messages = validationInfo.options.messages; // ... update its messages
};
--
As a side note, manually updating the validator is also possible by using the rules() method like
$yourHtmlField.rules( "add", {
required: true,
messages: {
required: "Required input"
}
});
as this directly updates the rules of the validator without the unobtrusive stuff. But then the data-val attributes are rendered useless.

You have to add a reference to jquery.unobtrusive-ajax.js to enable the validation within Ajax Form
Something like this:
<script type="text/javascript" src="/Scripts/jquery.unobtrusive-ajax.js"></script>

Related

After grecaptcha.execute(), form.submit not working on ASP.Net MVC 5 form

The form in question is a simple form with reCaptcha v2 on it. Upon clicking the submit button Google challenges the user (me) with the reCaptcha. Every time Google is validating I am a human, the onSubmit is called, the form is serialized correctly, but the form.submit() does not invoke the ASP.Net MVC controller on the server. When Google reCaptcha is removed, the controller is called just fine so I don't think it is anything to do with the ASP.Net code.
JavaScript is not my strong point, so I am assuming a dumb mistake in trying to call the submit. What do I have wrong here?
<script>
var onSubmit = function (token) {
var form = $("form"); // $("#feedbackForm");
console.log(form.serialize());
form.submit();
}
var onGrecaptchaError = function (token) {
grecaptcha.reset();
}
var onloadCallback = function() {
grecaptcha.render('submit', {
'sitekey' : '#reCaptchaPublic',
'callback': onSubmit,
'error-callback': onGrecaptchaError,
'size': 'invisible'
});
};
</script>
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script>
and the razor form code:
#using (Html.BeginForm("Email", "Home", FormMethod.Post, new { id = "feedbackForm" }))
{
#* [SNIP] *#
<div class="formfield clear">
<button id="submit" class="btnSubmit">Send To Leadership</button>
</div>
}
After much searching I finally discovered that you cannot give the submit button an id of submit, that was the problem!

ASP.NET MVC razor form with knockout won't validate

I have model like this (simplified)
public class User
{
[Required]
public string UserName { get; set; }
// Other fields
}
An MVC razor view with knockout viewModel that looks like this:
#using (Html.BeginForm("MyAction", FormMethod.Post, new { id = "profileEditorForm" }))
{
#Html.ValidationSummary(false)
#Html.LabelFor(n => n.UserName)
#Html.TextBoxFor(n => n.UserName, new { data_bind = "value: UserName" })
#Html.ValidationMessageFor(n => n.UserName)
#* Other fields *#
<p>
<input type="submit" value="Save" alt="" title="" />
Cancel
</p>
}
<script type="text/javascript">
$(function() {
var vm = new viewModel(#(Html.Raw(Json.Encode(#Model))));
ko.applyBindings(vm);
$("#profileEditorForm").validate({
submitHandler: function(form) {
alert('Validating ' + ko.toJSON(vm));
if (vm.save)
window.location.href = "/";
return false;
}
});
});
var viewModel = function(model) {
var self = this;
self.UserName = ko.observable(model.UserName);
// Other fields
self.save = function() {
alert('Saving ' + ko.toJSON(self));
}
};
};
</script>
I cannot get it to give me client side validation even though it goes through validate function (the alert insertion indicates that) and then straight into save and to posts back to MVC action something that is not valid.
Can you please help me how to enable client side validation (it is enabled in web.confir) on this form. Is it Knockout that ruins the day (although all the bindings are working perfectly fine? Or is it something I am looking at and don't see?
Help highly appreciated!
Validation doesn't work with knockout bindings....
You have to duplicate the validation in client side. The faster way is using knockout validation plugin, but it is slow when you have a lot of data..
https://github.com/ericmbarnard/Knockout-Validation
Or you can just use jquery validation.
Model Validation Will not work in knockout binding you have to download knockoutValidation.js file and use knockout validations
Example :
Validating UserName in KnockoutJS
var self = this;
self.UserName = ko.observable(UserName).extend({
required: {
message:"Please enter User Name"
}
});

Html.BeginForm not passing parameter

I have the following code that populates a Drop Down List and auto submits a form but it’s not passing the id back to the controller.
<script type="text/javascript">
$(function () {
$("#ArticleID").change(function () {
$('#TheForm').submit();
});
});
</script>
#using (Html.BeginForm("Details", "Article", FormMethod.Post, new { id = "TheForm" })){
#Html.DropDownList("ArticleID", (SelectList)ViewBag.ArticleId, "Select Article")
}
I get:
/Article/Details
But need:
/Article/Details/1
I’m following a tutorial that stops at this point. I’m not quite sure what is going on here regarding TheForm I tried to put ArticleID but that didn’t work. How do I do this?
I've also tried it without jQuery like this,
#using (Html.BeginForm("Details", "Article", FormMethod.Post, new { id = "TheForm" })){
#Html.DropDownList(
"ArticleID",
(SelectList)ViewData["Articles"],
"Please Select an Article",
new
{
onchange = "document.getElementById('TheForm').submit();"
})
}
But it doesn't send the parameter through either.
There is a built in way to render this without selecting the action:
var actionUrl = '#Url.Action("Details", "Article")/' + $('#ArticleID').val();
The url is determined before the page is rendered in the following line:
#using (Html.BeginForm("Details", "Article", FormMethod.Post, new { id = "TheForm" }))
which renders:
<form action="/Article/Details" id="TheForm" method="post">
Since the value that you want to add to the Url, ArticleID, is determined by the dropdown selection, you'll need to manipulate the action attribute of the form using JavaScript.
Something like this would probably work:
<script type="text/javascript">
$(function () {
$("#ArticleID").change(function () {
// The following line was changed to use #naspinski's suggestion
var actionUrl = '#Url.Action("Details", "Article")/' + $('#ArticleID').val();
$('#TheForm').attr('action', actionUrl);
$('#TheForm').submit();
});
});
</script>
With that said, this feel awkward to me. It may be worth considering how that value needs or will be used. Does it really need to be part of a route? If not, you can avoid this manipulating the action attribute altogether.

Search and display on same page in mvc2 asp net

have a simple search form with a textbox. And upon submitting the form I send the contents of the textbox to a stored procedure which returns to me the results. I want the results to be displayed on the same page the form was, except just below it.
Right now I'm doing the following but it's not working out exactly the way I want:
sathishkumar,
You don't tag the question as being an ajax related solution or not. I'm going to present a simple ajax approach which may or may not be suitable.
in the controller:
public ActionResult Search(string searchTerm)
{
// you don't add code re your stored proc, so here is a repo based approach
var searchItems = _repository.Find(x => x.searchfield.Contains(searchTerm));
return PartialView("SearchPartial", searchItems);
}
main view (index.aspx or whatever) (below where your main content is defined, add):
<div id="searchResults"></div>
in another part of the page (semi psuedo-code):
<script type="text/javascript">
function getSearchResults() {
// #yoursearchbox is a textbox on the index.aspx aview
var tdata = { searchTerm: $('#yoursearchbox').val()};
// or your data in the format that will be used ??
$.ajax({
type: "GET",
data: tdata,
url : '<%= Url.Action("Search", "Home") %>',
success: function (result) { success(result); }
});
});
function success(result){
$("#searchResults").html(result);
}
</script>
You'd then add a partial view SearchPartial.ascx that contained your model for the search results.
Hope this helps.
You can use Ajax to solve the problem.
<div>
`#using (Ajax.BeginForm("action", "controller", new AjaxOptions
{
UpdateTargetId = "results",
HttpMethod = "GET",
}))
{
#Html.TextBox()
<input type="submit" value="Search" />
}`
<div id="results"></div>
</div>

ASP.NET MVC ActionLink and post method

Can anyone tell me how can I submit values to Controller using ActionLink and POST method?
I don't want to use buttons.
I guess it has something with jquery.
If you're using ASP MVC3 you could use an Ajax.ActionLink(), that allows you to specify a HTTP Method which you could set to "POST".
You can't use an ActionLink because that just renders an anchor <a> tag.
You can use a jQuery AJAX post.
Or just call the form's submit method with or without jQuery (which would be non-AJAX), perhaps in the onclick event of whatever control takes your fancy.
You can use jQuery to do a POST for all your buttons. Just give them the same CssClass name.
Use "return false;" at the end of your onclick javascript event if you want to do a server side RedirectToAction after the post otherwise just return the view.
Razor Code
#using (Html.BeginForm())
{
#Html.HiddenFor(model => model.ID)
#Html.ActionLink("Save", "SaveAction", "MainController", null, new { #class = "saveButton", onclick = "return false;" })
}
JQuery Code
$(document).ready(function () {
$('.saveButton').click(function () {
$(this).closest('form')[0].submit();
});
});
C#
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SaveAction(SaveViewModel model)
{
// Save code here...
return RedirectToAction("Index");
//return View(model);
}
#Aidos had the right answer just wanted to make it clear since it is hidden inside a comment on his post made by #CodingWithSpike.
#Ajax.ActionLink("Delete", "Delete", new { id = item.ApkModelId }, new AjaxOptions { HttpMethod = "POST" })
Here was an answer baked into the default ASP.NET MVC 5 project I believe that accomplishes my styling goals nicely in the UI. Form submit using pure javascript to some containing form.
#using (Html.BeginForm("Logout", "Account", FormMethod.Post, new { id = "logoutForm", #class = "navbar-right" }))
{
<a href="javascript:document.getElementById('logoutForm').submit()">
<span>Sign out</span>
</a>
}
The fully shown use case is a logout dropdown in the navigation bar of a web app.
#using (Html.BeginForm("Logout", "Account", FormMethod.Post, new { id = "logoutForm", #class = "navbar-right" }))
{
#Html.AntiForgeryToken()
<div class="dropdown">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
<span class="ma-nav-text ma-account-name">#User.Identity.Name</span>
<i class="material-icons md-36 text-inverse">person</i>
</button>
<ul class="dropdown-menu dropdown-menu-right ma-dropdown-tray">
<li>
<a href="javascript:document.getElementById('logoutForm').submit()">
<i class="material-icons">system_update_alt</i>
<span>Sign out</span>
</a>
</li>
</ul>
</div>
}
ActionLink will never fire post. It always trigger GET request.
Use the following the Call the Action Link:
<%= Html.ActionLink("Click Here" , "ActionName","ContorllerName" )%>
For submitting the form values use:
<% using (Html.BeginForm("CustomerSearchResults", "Customer"))
{ %>
<input type="text" id="Name" />
<input type="submit" class="dASButton" value="Submit" />
<% } %>
It will submit the Data to Customer Controller and CustomerSearchResults Action.
This is taken from the MVC sample project
#if (ViewBag.ShowRemoveButton)
{
using (Html.BeginForm("RemoveLogin", "Manage"))
{
#Html.AntiForgeryToken()
<div>
#Html.Hidden("company_name", account)
#Html.Hidden("returnUrl", Model.returnUrl)
<input type="submit" class="btn btn-default" value="Remove" title="Remove your email address from #account" />
</div>
}
}
Use this link inside Ajax.BeginForm
#Html.ActionLink(
"Save",
"SaveAction",
null,
null,
onclick = "$(this).parents('form').attr('action', $(this).attr('href'));$(this).parents('form').submit();return false;" })
;)
My Solution to this issue is a fairly simple one. I have a page that does a customer search one by the whole email and the other by a partial, the partial pulls and displays a list the list has an action link that points to a actionresult called GetByID and passes in the id
the GetByID pulls the data for the selected customer then returns
return View("Index", model);
which is the post method
This has been a difficult problem for me to solve. How can I build a dynamic link in razor and html that can call an action method and pass a value or values to a specific action method? I considered several options including a custom html helper. I just came up with a simple and elegant solution.
The view
#model IEnumerable<MyMvcApp.Models.Product>
#using (Html.BeginForm()) {
<table>
<thead>
<tr>
<td>Name</td>
<td>Price</td>
<td>Quantity</td>
</tr>
</thead>
#foreach (Product p in Model.Products)
{
<tr>
<td>#p.Name</td>
<td>#p.Price.ToString()</td>
<td>#p.Quantity.ToString()</td>
</tr>
}
</table>
}
The action method
public ViewResult Edit(Product prod)
{
ContextDB contextDB = new ContextDB();
Product product = contextDB.Products.Single(p => p.ProductID == prod.ProductId);
product = prod;
contextDB.SaveChanges();
return View("Edit");
}
The point here is that Url.Action does not care whether the action method is a GET or a POST. It will access either type of method. You can pass your data to the action method using
#Url.Action(string actionName, string controllerName, object routeValues)
the routeValues object. I have tried this and it works. No, you are not technically doing a post or submitting the form but if the routeValues object contains your data, it doesnt matter if its a post or a get. You can use a particular action method signature to select the right method.
I have done the same issue using following code:
#using (Html.BeginForm("Delete", "Admin"))
{
#Html.Hidden("ProductID", item.ProductID)
<input type="submit" value="Delete" />
}
This is my solution for the problem.
This is controller with 2 action methods
public class FeedbackController : Controller
{
public ActionResult Index()
{
var feedbacks =dataFromSomeSource.getData;
return View(feedbacks);
}
[System.Web.Mvc.HttpDelete]
[System.Web.Mvc.Authorize(Roles = "admin")]
public ActionResult Delete([FromBody]int id)
{
return RedirectToAction("Index");
}
}
In View I render construct following structure.
<html>
..
<script src="~/Scripts/bootbox.min.js"></script>
<script>
function confirmDelete(id) {
bootbox.confirm('#Resources.Resource.AreYouSure', function(result) {
if (result) {
document.getElementById('idField').value = id;
document.getElementById('myForm').submit();
}
}.bind(this));
}
</script>
#using (Html.BeginForm("Delete", "Feedback", FormMethod.Post, new { id = "myForm" }))
{
#Html.HttpMethodOverride(HttpVerbs.Delete)
#Html.Hidden("id",null,new{id="idField"})
foreach (var feedback in #Model)
{
if (User.Identity.IsAuthenticated && User.IsInRole("admin"))
{
#Html.ActionLink("Delete Item", "", new { id = #feedback.Id }, new { onClick = "confirmDelete("+feedback.Id+");return false;" })
}
}
...
</html>
Point of interest in Razor View:
JavaScript function confirmDelete(id) which is called when the link generated with #Html.ActionLink is clicked;
confirmDelete() function required id of item being clicked. This item is passed from onClick handler confirmDelete("+feedback.Id+");return false; Pay attention handler returns false to prevent default action - which is get request to target. OnClick event for buttons could be attached with jQuery for all buttons in the list as alternative (probably it will be even better, as it will be less text in the HTML page and data could be passed via data- attribute).
Form has id=myForm, in order to find it in confirmDelete().
Form includes #Html.HttpMethodOverride(HttpVerbs.Delete) in order to use the HttpDelete verb, as action marked with the HttpDeleteAttribute.
In the JS function I do use action confirmation (with help of external plugin, but standard confirm works fine too. Don't forget to use bind() in call back or var that=this (whatever you prefer).
Form has a hidden element with id='idField' and name='id'. So before the form is submitted after confirmation (result==true), the value of the hidden element is set to value passed argument and browser will submit data to controller like this:
Request URL:http://localhost:38874/Feedback/Delete
Request Method:POST Status Code:302 Found
Response Headers
Location:/Feedback
Host:localhost:38874
Form Data X-HTTP-Method-Override:DELETE id:5
As you see it is POST request with X-HTTP-Method-Override:DELETE and data in body set to "id:5". Response has 302 code which redirect to Index action, by this you refresh your screen after delete.
I would recommend staying pure to REST principles and using an HTTP delete for your deletes. Unfortunately HTML Specs only has HTTP Get & Post. A tag only can a HTTP Get. A form tag can either do a HTTP Get or Post. Fortunately if you use ajax you can do a HTTP Delete and this is what i recommend. See the following post for details: Http Deletes
Calling $.post() won't work as it is Ajax based. So a hybrid method needs to be used for this purpose.
Following is the solution which is working for me.
Steps:
1. Create URL for href which calls the a method with url and parameter
2. Call normal POST using JavaScript method
Solution:
In .cshtml:
View
Note: the anonymous method should be wrapped in (....)()
i.e.
(function() {
//code...
})();
postGo is defined as below in JavaScript.
Rest are simple..
#Url.Action("View") creates url for the call
{ 'id': #receipt.ReceiptId } creates parameters as object which is in-turn converted to POST fields in postGo method. This can be any parameter as you require
In JavaScript:
(function ($) {
$.extend({
getGo: function (url, params) {
document.location = url + '?' + $.param(params);
},
postGo: function (url, params) {
var $form = $("<form>")
.attr("method", "post")
.attr("action", url);
$.each(params, function (name, value) {
$("<input type='hidden'>")
.attr("name", name)
.attr("value", value)
.appendTo($form);
});
$form.appendTo("body");
$form.submit();
}
});
})(jQuery);
Reference URLs which I have used for postGo
Non-ajax GET/POST using jQuery (plugin?)
http://nuonical.com/jquery-postgo-plugin/
jQuery.post() will work if you have custom data. If you want to post existing form, it's easier to use ajaxSubmit().
And you don't have to setup this code in the ActionLink itself, since you can attach link handler in the document.ready() event (which is a preferred method anyway), for example using $(function(){ ... }) jQuery trick.
Came across this needing to POST from a Search (Index) page to the Result page. I did not need as much as #Vitaliy stated but it pointed me in the right direction. All I had to do was this:
#using (Html.BeginForm("Result", "Search", FormMethod.Post)) {
<div class="row">
<div class="col-md-4">
<div class="field">Search Term:</div>
<input id="k" name="k" type="text" placeholder="Search" />
</div>
</div>
<br />
<div class="row">
<div class="col-md-12">
<button type="submit" class="btn btn-default">Search</button>
</div>
</div>
}
My Controller had the following signature method:
[HttpPost]
public async Task<ActionResult> Result(string k)

Resources