MVC: pass parameter to action using Jquery.ajax() - asp.net-mvc

I'm pretty new to MVC. I need to make ajax call to an Action with parameters using html.Action(). I'm unable to pass this..
Hope it will be helpful for other MVC begineers as well..
HTML:
<%: Html.ActionLink("Add Race", "AddRace",
new {eventId = Model.EventId, fleetId=Model.SelectedFleet.ID},
new{#onclick=string.Format("return checkFleetAddedandScroing()")}) %>
Jquery:
function checkFleetAddedandScroing() {
debugger;
$.ajax({
type: "GET",
url: '<%=Url.Action("CheckFleetExists")%>',
dataType: "json",
cache: false,
success: function (data, textStatus) {
data = eval("(" + data + ")");
if (data == true) {
return true;
}
else {
alert("Cannot Add race becasue you have not yet added any fleets and fleet scoring is checked.");
return false;
}
}, //success
error: function (req) {
}
});
}
Action:
public JsonResult CheckFleetExists(Guid fleetId )
{
bool exists = false;
try
{
exists = !db.Races.Any(r => r.FleetID == fleetId);
}
catch
{
}
return Json(exists, JsonRequestBehavior.AllowGet);
}
I need to pass fleetid to action which is in Model.SelectedFleet.ID. Its being used somewhere on pages. But i'm unable to use that somehow..
please suggest where i'm doing wrong...

It looks like you are trying to invoke a controller action using AJAX when the link is clicked and depending on the result of this call either allow the user to be redirected to the actual AddRace action or be prompted with an error message.
The problem with your code is that you are attempting to return true/false from within the success AJAX callback which doesn't make any sense. You need to always return false from the click callback and inside the success callback, depending on the returned value from the server, redirect manually using the window.location.href function.
HTML:
<%: Html.ActionLink(
"Add Race",
"AddRace",
new {
eventId = Model.EventId,
fleetId = Model.SelectedFleet.ID
},
new {
data_fleetid = Model.SelectedFleet.ID,
#class = "addRace"
}
) %>
Jquery:
<script type="text/javascript">
$(function () {
$('.addRace').click(function (evt) {
$.ajax({
type: 'GET',
url: '<%= Url.Action("CheckFleetExists") %>',
cache: false,
data: { fleetId: $(this).data('fleetid') },
success: function (data) {
if (data.exists) {
// the controller action returned true => we can redirect
// to the original url:
window.location.href = url;
}
else {
alert("Cannot Add race becasue you have not yet added any fleets and fleet scoring is checked.");
}
},
error: function (req) {
}
});
// we make sure to cancel the default action of the link
// because we will be sending an AJAX call
return false;
});
});
</script>
Action:
public ActionResult CheckFleetExists(Guid fleetId)
{
bool exists = false;
try
{
exists = !db.Races.Any(r => r.FleetID == fleetId);
}
catch
{
}
return Json(new { exists = exists }, JsonRequestBehavior.AllowGet);
}
Remark: inside your AddRace controller action don't forget to perform the same verification as you are doing inside your CheckFleetExists. The user could simply disable javascript and the AJAX call will never be done.

change your action like this :
public JsonResult CheckFleetExists(string fleetId)
{
var fleetGuid = Guid.Parse(fleetId);
bool exists = false;
try
{
exists = !db.Races.Any(r => r.FleetID == fleetGuid );
}
catch
{
}
return new JsonResult{ Data = exists};
}
and change you ActionLink so :
<%: Html.ActionLink("Add Race", "AddRace",
new {eventId = Model.EventId, fleetId=Model.SelectedFleet.ID},
new{onclick=string.Format("return checkFleetAddedandScroing({0})",Model.SelectedFleet.ID)}) %>
and your script block may look something like this :
function checkFleetAddedandScroing($fleetId) {
$.ajax({
type: "POST",
url: '<%=Url.Action("CheckFleetExists")%>',
dataType: "json",
data : { "fleetId" : $fleetId },
cache: false,
success: function (data, textStatus) {
data = eval("(" + data + ")");
if (data == true) {
return true;
}
else {
alert("Cannot Add race becasue you have not yet added any fleets and fleet scoring is checked.");
return false;
}
}, //success
error: function (req) {
}
});
}

Problem was in answers that url to action was not complete..i did it using this way
function checkFleetAddedandScroing() {
// debugger;
$.ajax({
type: "POST",
url: '<%=Url.Action("CheckFleetExists", new {eventId=Model.EventId})%>',
dataType: "json",
cache: false,
success: function (data, textStatus) {
data = eval("(" + data + ")");
if (data == true) {
return true;
}
else {
alert("Cannot Add race becasue you have not yet added any fleets and fleet scoring is checked.");
return false;
}
}, //success
error: function (req) {
}
});
}

Related

Unable to send array data using ajax with ASP.NET Core and Entity Framework Core

I am trying to send array to the controller but it's blank in the controller parameter.
Ajax function is:
$('#pending').click(function () {
SaveTestResult("/Reception/PatientTests/SavePendingTest");
});
function SaveTestResult(url) {
var pid = $('.patientId').attr('id');
var tid = "";
var tval = "";
var tpid = "";
var tests = [];
$("table > tbody > tr").each(function () {
testId = $(this).find('.tid').val();
if (typeof (testId) != "undefined") {
tid = testId;
}
var rowText = ""
$(this).find('td').each(function () {
tpid = $(this).find('.tpId').val();
tval = $(this).find('.result').val();
if (typeof (tpid) != "undefined") {
tests.push({ PatientId: pid, TestId: tid, TestParameterId: tpid, TestValue: tval });
}
});
});
// alert(JSON.stringify(tests));
$.ajax({
type: "POST",
url: url,
data: JSON.stringify(tests),
contentType: "application/json",
headers: { "RequestVerificationToken": $('input[name="__RequestVerificationToken"]').val() },
success: function (data) {
alert(data);
},
error: function (e) {
alert('Error' + JSON.stringify(e));
}
});
}
This is the controller method:
[HttpPost]
[Route("Reception/PatientTests/SavePendingTest")]
public async Task<IActionResult> SavePendingTest(List<PendingTestResult> pendingTestResult)
{
if (ModelState.IsValid)
{
foreach (PendingTestResult ptr in pendingTestResult)
{
_db.Add(ptr);
await _db.SaveChangesAsync();
}
// return new JsonResult("Index");
}
return new JsonResult(pendingTestResult); ;
}
But when run the code I see data array filled but inside of the SavePendingTest action, pendingTestResult is empty and not filled! I also tried the [FromBody] tag inside action params, but it does not work either!
Help me resolve this
you are sending a string with no names so the controller can not get the values.
change you code to
$.ajax({
type:"POST",
url:url,
data:test
...
});
the test should be an object not a string.
You can pass the list of objects by :
$.ajax({
type: "POST",
url: "Reception/PatientTests/SavePendingTest",
data: { pendingTestResult: tests },
headers: { "RequestVerificationToken": $('input[name="__RequestVerificationToken"]').val() },
success: function (data) {
alert(data);
},
error: function (e) {
alert('Error' + JSON.stringify(e));
}
});
pendingTestResult in data:{ pendingTestResult: tests } matches the parameter name on action and remove the contentType setting .

How can get image with Jquery Ajax

I can can get picture by Razor '#Action' but with Ajax Can't. I write
in controller:
public ActionResult getCommodityPic()
{
var f= File(Server.MapPath("~/App_Data/CommodityPics/eee/1") + ".jpg", "image/jpg");
return f;
}
and in java script :
$(document).ready(function () {
ShowCommodities();
getCommodityPic();
});
function getCommodityPic() {
$.ajax({
url: '#Url.action("getCommodityPic")',
type: 'Get',
dataType: 'image/jpg',
success: function (Data, Status, jqXHR) {
$('#img1').attr('src', Data);
}
});
$.ajax({
url: '#Url.Action("DownloadPic", "MyController")',
contentType: 'application/json; charset=utf-8',
datatype: 'json',
data: {
id: Id
},
type: "GET",
success: function (Data, Status, jqXHR) {
if (Data != "") {
alert("Empty");
return;
}
window.location ='#Url.Action("DonloadPic","Mycontroller")';
}
});
in Controller:
public ActionResult DownloadPic(int? id)
{
Lesson l = new Lesson();
l = db.Lesson.Single(p => p.id == id);
if (l.picture == null)
{
string targetFolder = System.Web.HttpContext.Current.Server.MapPath("~/Image/book-03.jpg");
byte[] img = System.IO.File.ReadAllBytes(targetFolder);
return File(img, "image/jpg");
}
return File(l.picture, "image/jpg");
}
If you want to display the image dynamically, then try this. You may not need an Ajax call for this.
$('#img1').html('<img src="getCommodityPic" />')
If you want to process the image (read its raw binary) then this answer should help - https://stackoverflow.com/a/20048852/6352160

Calling a server side JsonResult method from JavaScript

I need to call the following JsonResult method:
JsonResult Delete(int pubId)
{
try
{
using (var ctx = new LibsysLiteContext())
{
var p = ctx.Publishers.Find(pubId);
var allPublisher = ctx.Publishers.ToList();
ctx.Publishers.Remove(p);
var total = allPublisher.Count();
return Json(new { success = true, data = allPublisher, total = total }, JsonRequestBehavior.AllowGet);
}
return Json(new RestResult { Success = true, Data = entity, Message = "Country has been deleted" }, JsonRequestBehavior.DenyGet);
return null;
}
catch (Exception e)
{
return Json(new RestResult { Success = true, Message = e.Message }, JsonRequestBehavior.DenyGet);
}
}
from a js function (deleteRows):
var deleteRows = function () {
Ext.Msg.confirm(
'Delete Rows', 'Are you sure?',
function(btn) {
if (btn == 'yes') {
var hh = Ext.getCmp('gg').deleteSelected();
ajax({
//action and controller
url: '#Url.Action( "Publisher", "Delete")',
data: { "Id": Id },
type: 'POST',
dataType: 'json',
});
}
});
};
which is called by a handler of the following button:
X.Button().ID("bntdelete").Text("delete").Icon(Icon.Delete).Handler("deleteRows();"),
It didn't work at all this way! How can I move from client side to the server side from a JavaScript function?
In general calling a serverside [Direct Method] from js you use App.direct.<Method>();
Hopefully you have resolved this by now but in your ajax call you are defining the type as post but what you show on the controller is set as the default get. you need to add
[HttpPost]
public JsonResult Delete(int id)...
to your controller

Remote Validation works on textbox lost focus, but the ModelState.IsValid is always true

I have a model with RemoteValidation Attribute.
When I enter "test" which already exists in the database and I click on an area except the OK button then I get in red colors: "test already exists." So far so good. When I click then the OK buttona post is done to the Create action where I ask for
ModelState.IsValid which is always true ???
Therefore the data is entered in the database and I get a Duplicate Exception...
I know this worked before on my site, I just have changed some stuff and subversion is not
activated arghhh...
What do I wrong?
[HttpPost]
public ActionResult Create(Release release)
{
if (ModelState.IsValid)
{
_releaseDataProvider.AddRelease(release);
return Json(new { success = true });
}
return PartialView(release);
}
public JsonResult ReleaseExists(string Name)
{
bool releaseExists = _releaseDataProvider.ReleaseExists(Name);
if (!releaseExists)
{
return Json(true, JsonRequestBehavior.AllowGet);
}
else
{
return Json(false, JsonRequestBehavior.AllowGet);
}
}
$.ajaxSetup({ cache: false });
$(document).ready(function () {
$('#CreateRelease').click(function (event) { loadDialog(this, event, createRelease); });
});
function loadDialog(link, e, ajaxRequest) {
e.preventDefault();
var $title = link.innerHTML;
var $contenturl = $(link).attr('href');
var $dialog = $('<div></div>');
var $height = $(link).attr('data-dialog-height');
var $width = $(link).attr('data-dialog-width');
$dialog.load($contenturl).dialog({
title: $title,
autoOpen: true,
modal: true,
show: 'fade',
hide: 'fade',
width: $width,
height: $height,
buttons: {
"OK": function () {
ajaxRequest($(this), $('form', this));
},
"Cancel": function () {
$dialog.dialog("close");
}
}
});
}
function createRelease(dlg, form) {
$.ajax({
url: $(form).attr('action'),
type: 'POST',
data: form.serialize(),
success: function (response) {
if (response.success) {
dlg.dialog("close");
// Update UI
}
else {
// Reload the dialog with the form to show model/validation errors
dlg.html(response);
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert(textStatus + '-' + XMLHttpRequest.responseText);
}
});
}
ModelState.IsValid which is always true ???
That's normal, Remote validation rules are applied only when you invoke the controller action through AJAX. The same action is not invoked when the form is submitted normally. So it is up to you to call the corresponding validation method in your POST action:
[HttpPost]
public ActionResult Create(Release release)
{
if (ModelState.IsValid && !_releaseDataProvider.ReleaseExists(release.Name))
{
_releaseDataProvider.AddRelease(release);
return Json(new { success = true });
}
return PartialView(release);
}

ASP.NET MVC Ajax Error handling

How do I handle exceptions thrown in a controller when jquery ajax calls an action?
For example, I would like a global javascript code that gets executed on any kind of server exception during an ajax call which displays the exception message if in debug mode or just a normal error message.
On the client side, I will call a function on the ajax error.
On the server side, Do I need to write a custom actionfilter?
If the server sends some status code different than 200, the error callback is executed:
$.ajax({
url: '/foo',
success: function(result) {
alert('yeap');
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert('oops, something bad happened');
}
});
and to register a global error handler you could use the $.ajaxSetup() method:
$.ajaxSetup({
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert('oops, something bad happened');
}
});
Another way is to use JSON. So you could write a custom action filter on the server which catches exception and transforms them into JSON response:
public class MyErrorHandlerAttribute : FilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
filterContext.ExceptionHandled = true;
filterContext.Result = new JsonResult
{
Data = new { success = false, error = filterContext.Exception.ToString() },
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
}
and then decorate your controller action with this attribute:
[MyErrorHandler]
public ActionResult Foo(string id)
{
if (string.IsNullOrEmpty(id))
{
throw new Exception("oh no");
}
return Json(new { success = true });
}
and finally invoke it:
$.getJSON('/home/foo', { id: null }, function (result) {
if (!result.success) {
alert(result.error);
} else {
// handle the success
}
});
After googling I write a simple Exception handing based on MVC Action Filter:
public class HandleExceptionAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest() && filterContext.Exception != null)
{
filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
filterContext.Result = new JsonResult
{
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
Data = new
{
filterContext.Exception.Message,
filterContext.Exception.StackTrace
}
};
filterContext.ExceptionHandled = true;
}
else
{
base.OnException(filterContext);
}
}
}
and write in global.ascx:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleExceptionAttribute());
}
and then write this script on the layout or Master page:
<script type="text/javascript">
$(document).ajaxError(function (e, jqxhr, settings, exception) {
e.stopPropagation();
if (jqxhr != null)
alert(jqxhr.responseText);
});
</script>
Finally you should turn on custom error.
and then enjoy it :)
Unfortunately, neither of answers are good for me. Surprisingly the solution is much simpler. Return from controller:
return new HttpStatusCodeResult(HttpStatusCode.BadRequest, e.Response.ReasonPhrase);
And handle it as standard HTTP error on client as you like.
I did a quick solution because I was short of time and it worked ok. Although I think the better option is use an Exception Filter, maybe my solution can help in the case that a simple solution is needed.
I did the following. In the controller method I returned a JsonResult with a property "Success" inside the Data:
[HttpPut]
public JsonResult UpdateEmployeeConfig(EmployeConfig employeToSave)
{
if (!ModelState.IsValid)
{
return new JsonResult
{
Data = new { ErrorMessage = "Model is not valid", Success = false },
ContentEncoding = System.Text.Encoding.UTF8,
JsonRequestBehavior = JsonRequestBehavior.DenyGet
};
}
try
{
MyDbContext db = new MyDbContext();
db.Entry(employeToSave).State = EntityState.Modified;
db.SaveChanges();
DTO.EmployeConfig user = (DTO.EmployeConfig)Session["EmployeLoggin"];
if (employeToSave.Id == user.Id)
{
user.Company = employeToSave.Company;
user.Language = employeToSave.Language;
user.Money = employeToSave.Money;
user.CostCenter = employeToSave.CostCenter;
Session["EmployeLoggin"] = user;
}
}
catch (Exception ex)
{
return new JsonResult
{
Data = new { ErrorMessage = ex.Message, Success = false },
ContentEncoding = System.Text.Encoding.UTF8,
JsonRequestBehavior = JsonRequestBehavior.DenyGet
};
}
return new JsonResult() { Data = new { Success = true }, };
}
Later in the ajax call I just asked for this property to know if I had an exception:
$.ajax({
url: 'UpdateEmployeeConfig',
type: 'PUT',
data: JSON.stringify(EmployeConfig),
contentType: "application/json;charset=utf-8",
success: function (data) {
if (data.Success) {
//This is for the example. Please do something prettier for the user, :)
alert('All was really ok');
}
else {
alert('Oups.. we had errors: ' + data.ErrorMessage);
}
},
error: function (request, status, error) {
alert('oh, errors here. The call to the server is not working.')
}
});
Hope this helps. Happy code! :P
In agreement with aleho's response here's a complete example. It works like a charm and is super simple.
Controller code
[HttpGet]
public async Task<ActionResult> ChildItems()
{
var client = TranslationDataHttpClient.GetClient();
HttpResponseMessage response = await client.GetAsync("childItems);
if (response.IsSuccessStatusCode)
{
string content = response.Content.ReadAsStringAsync().Result;
List<WorkflowItem> parameters = JsonConvert.DeserializeObject<List<WorkflowItem>>(content);
return Json(content, JsonRequestBehavior.AllowGet);
}
else
{
return new HttpStatusCodeResult(response.StatusCode, response.ReasonPhrase);
}
}
}
Javascript code in the view
var url = '#Html.Raw(#Url.Action("ChildItems", "WorkflowItemModal")';
$.ajax({
type: "GET",
dataType: "json",
url: url,
contentType: "application/json; charset=utf-8",
success: function (data) {
// Do something with the returned data
},
error: function (xhr, status, error) {
// Handle the error.
}
});
Hope this helps someone else!
For handling errors from ajax calls on the client side, you assign a function to the error option of the ajax call.
To set a default globally, you can use the function described here:
http://api.jquery.com/jQuery.ajaxSetup.

Resources