manage serverside validaton when I use jquery post - c#

From razor view I'm sending js object using jquery to the mvc controller. Reason why I do it using jquery post method and not razors form is that I need to manage dynamic input of certain fields. On the view certain fields (inputtextbox) are dynamically added to the view (from 0 - 10) and I manage that solution using js on the page.
var myJsObj = ...
$.ajax({
type: 'POST',
traditional: true,
contentType: 'application/json',
url: '/MyController/SomeAction',
data: JSON.stringify({ model: myJsObj}),
success: function () {
}
});
On the server side, mvc receives that model and in case of some error I want to return this object back to the view.
[HttpPost]
public ActionResult SomeAction(MyModel model)
{
if(!ModelState.IsValid)
{
ModelState.AddModelError("", "Error occured!");
return View(model);
}
return RedirectToAction("Index");
}
I have inside razor view
Html.ValidationSummary
but since I'm using jquery post I dont know how to receive back to the view and display error like I would use regular razor form. Or if you know better approach to manage dynamically added input boxes on the razor view please post. Any help please.

I think you've got a couple of options here:
If you prefer to continue to use an Ajax POST as you've shown above, then you need to take the response from the POST and inject it back into your current HTML document. For example,
$.ajax({
type: 'POST',
traditional: true,
contentType: 'application/json',
url: '/MyController/SomeAction',
data: JSON.stringify({ model: myJsObj}),
success: function (data) {
// This is the case where the MVC action found model validation
// errors, and so it is responding with an HTML document that
// shows the errors.
var returnedBodyHtml = $(data).find('body').html();
$('body').html(returnedBodyHtml);
}
});
(That's untested code up there, so you may have to debug a little bit.) But this code doesn't handle the case where the server responded with a redirect (in the case of successful validation). So, check out this post for some options there.
Your other option is to use the standard Form submit. I know you said you had some dynamically generated input controls on your page, but that doesn't mean that you can't do a Form submit. You just need to make sure that these dynamically generated elements have the correct "name" attribute on them, so that their values get mapped appropriately to the Model on the server side action that is accepting the POST. For example, if your Javascript is dynamically generating an HTML element like this, and inserting it into the form:
<input type="text" name="myDynamicallyGeneratedInput[0]" />
<input type="text" name="myDynamicallyGeneratedInput[1]" />
<input type="text" name="myDynamicallyGeneratedInput[2]" />
<input type="text" name="myDynamicallyGeneratedInput[3]" />
then your Form submit will still work, as long as on the server side, your MyModel class has that corresponding property:
class MyModel
{
public List<string> MyDynamicallyGeneratedInput {get; set;}
}

This is what I have done to display errors for dynamic inputs. First off, take a look at this post to give you a better understanding. I have modified my code to better suit my needs, but you can check if it works for your application.
use-asp-net-mvc-validation-with-jquery-ajax.
I would then consume the return result in the ajax post error callback. It returns a code 400 'Bad Request' on validation errors. The validator variable is the form validator object.
error: function (xhr, textStatus, errorThrown) {
var statusCode = parseInt(xhr.status);
if (statusCode == 400) {
var data = $.parseJSON(xhr.responseText);
var message = "";
$.each(data, function (i, item) {
var propertyName = "" + item.key + "";
if ($("input[name='" + item.key + "']").length > 0) {
var errorObj = {};
errorObj[item.key] = item.error;
validator.showErrors(errorObj);
}
else {
message += "<div>" + item.key + ": " + item.error + "</div>";
}
});
if (message != "") {
//display message
}
}
}
I hope this helps. Good luck.

Related

How to call C# method from Javascript in ASP.NET Core?

I have a username textbox in my Index.cshtml file and I want to check for matches in our Active Directory whenever the user changes the text inside the textbox and then maybe display it in a DropDownList, so the user can choose form it.
So I call a JavaScript function on the oninput event of the textbox and now the question is how do I call my C# method FindUser() in Index.cshtml.cs from that JS function? I have tried a lot of what I've read, ajax call doesn't work, adding [WebMethod] and making the method static doesn't work and most on the internet is on MVC which I'm not using.
Textbox in Index.cshtml:
<input type="text" class="form-control" oninput="findUsers()" />
JavaScript function:
function findUsers() {
$.ajax({
url: 'Index\FindUser',
success: function (data) {
alert(data);
},
error: function (error) {
alert("Error: " + error);
}
})
}
leads the browser to alert
Error: [object Object]
Method in Index.cshtml.cs:
public void FindUser()
{
// code
}
The method is not even called from the JS function.
Also I've read a few times that calling a C# method from the view is not the proper way of doing it. If so, how can I achieve my goal then?
I see you're using Razor pages. A method in razor page model is not a routed method (it can't be called by requesting a route), and that's why trying to send an ajax request to Index\FindUser won't work, and the error returned by server would be 404 not found.
Alternatively you can use razor page handlers.
In your Index.cshtml.cs rename the method FindUser() to OnGetFindUser() or OnGetFindUserAsync() if the method is an asynchronous method.
You can then call this method by sending a request to "Index?handler=FindUser".
// Note the difference in method name
public IActionResult OnGetFindUser()
{
return new JsonResult("Founded user");
}
function findUsers() {
$.ajax({
type: 'GET',
// Note the difference in url (this works if you're actually in Index page)
url: '?handler=FindUser',
success: function (data) {
alert(data);
},
error: function (error) {
alert("Error: " + error);
}
})
}
Further suggested read
I am not very experienced yet, I have only started programming last year, but I hope I can help a little bit.
I also had a similar problem, but I could not execute a function directly from JavaScript. You could maybe create an API call to C# and make the API execute the function you want, and then return the data back to the client.
If I don't misunderstand, you want the user to type some text, and then return from your database a list based on the typed text.
You could use an onChange in the input tag, and each time it changes, it executes an API request to the server, which will search whatever you need and return it as a json. Then in JavaScript, you parse the data and put it in a select tag.
Hope it helps.
Ok so first off, you are calling jquery inside javascript function.
Calling a controller action method from ajax is pretty easy.
https://api.jquery.com/jquery.ajax/
You need to determine the request type, the url, the datatype returned, parameters passing etc and then set a breakpoint on the controller action and on the ajax request success and error functions. Then you will be able to see why it has succeeded or failed.
The way i would do it would be to give the input an id, then when a user types text catch the event.
https://api.jquery.com/category/events/
Don't confused jquery and javascript.
Jquery is a framework that packs javascript inside it.
Javascript is the native language.
You can use onkeyup or onblur like this
onblur: When you leave the input field, a function is triggered
onkeyup: A function is triggered when the user releases a key in the
input field
Then modify your code like this
html file:
<input type="text" class="form-control" id="username" oninput="findUsers()" />
js
function findUsers() {
var username= document.getElementById("username").value;
$.ajax({
type: 'GET',
url: '/Home/FindUser
dataType: 'json',
data: {username},
success: function (data) {
console.log(data);
},
error: function (error) {
console.log(error);
}
});
}
You must return something like this. You are using void keyword so it will not return anything to FE side
public JsonResult FindUser(string username)
{
var object = {
// something here
}
return Json(object);
}
Change your API like this:
public bool FindUser(string value)
{
if (value == "Joe")
return true;
else
return false;
}
Then call it like this:
<script type="text/javascript">
function findUsers() {
var value = document.getElementById("value").value;
$.ajax({
type: 'GET',
url: '/Home/FindUser,
data: value,
dataType: 'json',
success: function (data) {
alert(data);
},
error: function (error) {
alert(error);
}
});
}
</script>
<br />
<input type="text" class="form-control" id="value" oninput="findUsers()" />
you can call method exactly you want with
small addition to Index.cshtml. First line may be:
#page "{handler?}"
then call from ajax:
url:'/index/FindUser'
in Index.cshtml.cs calling method:
void OnGetFindUser(){}

Jquery .post method is sending a null value. How to pass actual value to controller?

I have a controller that applies to an edit view in asp.net MVC. I have an actionlink that sends the row Id to the controller which then brings back the correct row to see in the associated view.
I then have a partial view below that. That also requires a parameter in order to bring associated data from another table.
I have a Jquery .post call that runs after the page is loaded. I can alert out and show the exact value I want to send to the controller.
$(document).ready(function () {
var url = "/Home/MmsAndNotes";
var Uc = $("#Id").serialize();
alert(Uc);
$.post(url, {Id: Uc}, function (data) {
alert("what is Uc now? " + uc); //just for testing
});
})
I have also used it this way.
$(document).ready(function () {
var url = "/Home/MmsAndNotes";
var Uc = $("#Id").val();
alert(Uc);
$.post(url, Uc, function (data) {
});
})
the alerts come up and show the value I want. However, when the .post call runs, it sends a null value. Here is my controller.
public ActionResult MmsAndNotes(string Id)
{
//Declare LogisticsVM for individual policy info
LogisticsMMS_NotesVM model;
if(uc == null)
{
return Content("uc is empty.");
}
int val = Convert.ToInt32(uc);
using (Db db = new Db())
{
LogisticsMMS_NotesDTO dto = db.LogisticsMMS.Find(val);
//confirm policy exists
if (dto == null)
{
return Content("This policy cannot be found." + val);
}
model = new LogisticsMMS_NotesVM(dto);
}
return PartialView(model);
}
It always returns as uc is empty. I repeat, when the alerts come up. I get the correct value to send to the controller. But once it sends, something happens and it converts to null. HELPPPPP.. please .. I'm losing my mind over this one.
I don't know why, but changing my $.post() call to an $.ajax({}) call solved the issue. As you can see above, I had the $.post call. Using this instead,
$.ajax({
type: "POST",
url: "/Home/MmsAndNotes",
dataType: 'text',
data: { Id: Uc }
});
Solved it. I thought Jquery's shortened calls worked the same way. They certainly might, but doing it this way was the only way it worked for me.
P.S. Thanks Tyler (above) for your comments.
this solution should be work :
$(document).ready(function () {
$.ajax({
url: '/Home/MmsAndNotes',
type: 'GET',
dataType: "html",
data: { uc : $("#Id").val() },
success: function (result) {
code here
}
});
})
You need to verify if $("#Id").val() is not empty

Transferring info from view to Controller

I'm working on an asp-mvc application and facing the following issue:
I have a model with simple properties plus one property which is a list of my custom object, and I render the Ienumerable property as mentioned here:
Passing IEnumerable property of model to controller post action- ASP MVC
In my view, I have a button that is supposed to add items to the ienumerable property of my model. Of Course, I don't want to lose already inserted data, so I need to pass the model to the corresponding action.
I've noticed that the model os transferred entirely only upon post. So, I did something like:
$(".addButton").click(function (event) {
event.preventDefault();
$("#FilterForm").submit();
#{ Session["fromAddFullItem"] = "true";}
return false;
});
And then in my controller, I do something like:
public ActionResult Index(FilterModel model)
{
if (Session["fromAddFullItem"].ToString() == "true")
{
Session["fromAddFullItem"] = "false";
return AddBlankItemTemplate(model);
}
I've read that assigning session in js is not recommended, but also tried TempData, and there the data was always null.
My problem is that Session["fromAddFullItem"] is always true, even when I come from another button. If I put breakpoint in addbtn click in line- Session["fromAddFullItem"] = "false";, and press the other button, I see that for some odd reason the mentioned breakpoint is hit, even though I haven't pressed the add button.
Any help? Maybe there is another way to achieve what I want. Currently, no matter which button I press (which posts the form), it comes as Session["fromAddFullItem"] = "false" and goes to action AddBlankItemTemplate. Thanks.
EDIT - AJAX POST
$(".addButton").click(function(event) {
event.preventDefault();
var modelData = JSON.stringify(window.Model);
$.ajax({
url: '#Url.Action("AddBlankItemTemplate")',
type: 'POST',
dataType: 'json',
data: modelData,
contentType: 'application/json; charset=utf-8',
});
return false;
});
and controller
public ActionResult AddBlankItemTemplate(string modelData)
EDIT 2:
$(".addButton").click(function (event) {
event.preventDefault();
$.ajax({
url: '#Url.Action("AddBlankItemTemplate")',
data: $("#FilterForm").serialize()
}).success(function(partialView) {
$('DetailsTemplates').append(partialView);
});
});
and Controller:
public ActionResult AddBlankItemTemplate(FilterModel model)
The line #{ Session["fromAddFullItem"] = "true";} is Razor code and will be run on page rendering and load regardless of where you put it in the page.
It's not client side code so won't wait for your js code to run. If you're trying to synchronise state between js and MVC have you looked into angularjs which could simplify these actions.

Resolve Controller Path in Javascript File

I'm using a Kendo grid to display results from a webservice. The webservice is accessed in a controller and then we point the Kendo grid dataSource to the controller like so:
JavaScript
var servicePath = "/Home/Search";
var postData = { "searchTerm" : searchTerm, "targetDB" : targetDB }
var grid = $("#grid1").kendoGrid({
pageable: {
pageSize: 10
},
dataSource: {
error: function (e) {
if (e.errors !== false) {
$("#errorContainer").html(e.errors);
}
},
transport: {
read: {
url: servicePath,
dataType: "json",
data: postData,
type: "POST"
}
},
},
dataBound: function (e) {
//Do Stuff
}
});
Controller
[HttpPost]
public ActionResult Search(string searchTerm, string targetDB)
{
//Do Search and Return JSON
}
Problem
This works wonderfully when my URL is http://localhost/Home/Index but fails whenever it's something else, such as http://localhost/ (default when project is run from root). I've experienced the same problems using a jQuery .ajax call as the kendo grid service call.
Question
So my question is, how can I put in the correct service URL for the Kendo Grid (or in general when pointing to a controller) and know it will work in all path variations?
I've tried using variations of location.host to get the full URL regardless then append the controller and method, but the Kendo service call fails with no error.
I imagine I should be able to parse the url and use what I need, but I've found that when I am at the root of the webpage I can't figure out what to put to make an ajax call work. I've tried using the controller/method and the entire url? I've also tried various techniques described below.
What am I missing? Is there a convention or technique I could use instead?
Edit
I also tried putting a hidden field on the page with a value of the controller URL:
<input type="hidden" value="#Url.Action("Search", "Home"); " id="serviceURL" />
And then using that value in the JS:
var servicePath = $("#serviceURL").val();
But I found that the value of #Url.Action() (Value : Home/Search) is the same whether your url is http://localhost/ or http:localhost/Home/Index, so no luck. This still does not work when you're on the root page where the url looks something like "localhost/".
Thanks!

How to call an MVC Action using only JavaScript?

I have this Kendo UI dropdownlist with a select event that is handled by a JavaScript function.
I need to call an action result from a controller that runs a LINQ query to populate a Kendo UI grid on my page. My problem is the only way I can find to handle this even is with JavaScript and I have been unable to figure out how to call my action result from my controller from the JavaScript event function.
This is what the DropDownList looks like...
#(Html.Kendo().DropDownList()
.Name("Options")
.DataTextField("Text")
.DataValueField("Value")
.BindTo(new List<SelectListItem>() {
new SelectListItem() {
Text = "Policies Not Archived",
Value = "1"
},
new SelectListItem() {
Text = "View All Policies",
Value = "2"
},
new SelectListItem() {
Text = "Filter Policies",
Value = "3"
}
})
.Events(e =>
{
e.Select("select");
})
)
and my JavaScript event handler that needs to call the action result
function select(e) {
}
and depending on the selection an ActionResult like this,
public ActionResult ViewAllPolicies()
{
//mycode
}
see this post
var url = '#Url.Action("ViewAllPolicies","YourController")';
$.ajax({ url: url, success: DataRetrieved, type: 'POST', dataType: 'json' });
in controller
public ActionResult ViewAllPolicies()
{
//Should return json format
}
url – this is the URL where request is sent. In my case there is
controller called contacts and it has action calles
ListPartiesByNameStart(). This action method takes parameter
nameStart (first letter of person or company). success – this is the
JavaScript function that handles retrieved data. You can write there
also anonymous function but I suggest you to use functions with names
because otherwise your code may get messy when functions grow. type –
this is the type of request. It is either GET or POST. I suggest you
to use POST because GET requests in JSON format are forbidden by
ASP.NET MVC by default (I will show you later how to turn on GET
requests to JSON returning actions). dataType – this is the data
format that is expected to be returned by server. If you don’t assign
it to value then returned result is handled as string. If you set it
to json then jQuery constructs you JavaScript object tree that
corresponds to JSON retrieved from server.
Instead of returning json, you can also return a PartialView and in the .done function grab an element and replace it with the results from the partial view. PartialView actions basically return a fragment of HTML, and so you can just stuff that anywhere you want on the page:
$.ajax({
url: urlToPartialViewAction,
type: 'POST',
dataType: 'JSON',
data: '123'
})
.done(function (result) {
$('#someDivPlaceholder').replaceWith(result);
});
You could have something like a link or grey div and wire up to it's click event and then call this, the link might say "View Receipt" and when you click it you call an action that returns a partial view with the receipt, and so when they click it the div/link is replaced with the result. Kind of like the "View More Comments" links you see on social sites.
Note that you can't have a partial view by itself, it must be called through an action
public PartialViewResult _GetReceipt(string id)
{
ReceiptViewModel vm = //query for receipt data
return PartialView(vm);//render partial view and return html fragment
}
Once the select function executes, you need to make an AJAX call back to your Controller. You can use jQuery.ajax() (a wrapper for the most common AJAX operations) in the select function,
function select(e) {
var url = '#Url.Action("ViewAllPolicies", "PolicyController")';
var selectedPolicy = $('#Options').val(); // The option selected
$.ajax({
url: url,
type: 'POST',
dataType: 'JSON',
data: selectedPolicy
})
.done(function (data) {
// Display the data back from you Controller
});
}
You can look at the Kendo site for more info on how the DropDownList works.

Categories