Tried looking in stackoverflow because this looked so trivial. Found many similar questions and read through them. Found no solution using these examples. Here is my code, can anyone help?
function testAjax() {
return $.ajax({
type: "GET",
url: '#Url.Action("Nodes","Competence", new { userId = Sven });',
contentType: "application/json;charset=utf-8",
dataType: "json"
});
}
var promise = testAjax();
promise.success(function (data) {
var dataConverted = JSON.stringify(data);
$('#tree').treeview({ data: dataConverted, multiSelect: true });
});
ASP.NET MVC method
public JsonResult Nodes(string userId)
{
var temp = userId;
var list = new List<Node>();
list.Add(new Node("Test1"));
list.Add(new Node("Test2"));
list.Add(new Node("Test3"));
return Json(list, JsonRequestBehavior.AllowGet);
}
EDIT:
Just before I was about to turn crazy on Halloween night, i figured out to try in a new session. Turns out it was just a caching problem..Thanks for the help everyone
Since your server may not expecting a request with JSON content, try removing the contentType parameter on your ajax call. Its default value is "application/x-www-form-urlencoded; charset=UTF-8" and is fine for most cases.
It's type should be "POST"
return $.ajax({
type: "POST",
url: '#Url.Action("Nodes","Competence")',
data: { userId: "Test" },
contentType: "application/json;charset=utf-8",
dataType: "json"
});
As it's a GET verb, it'll be easiest to pass this in as a querystring value. This also conforms better with a RESTful design.
For example replace #Url.Action("Nodes","Competence")
with
#Url.Action("Nodes","Competence", new { userId = id });
Then you can delete the data property. This will append ?userId=valueOfId into your url and then it should be mapped correctly to your action with the userId correctly populated.
Update
As #freedomn-m stated:
This will generate the url when the view is built server-side. If the
parameters never change, then fine - but it's relatively unlikely that
the parameters won't change, in which case you should add the url
parameters at runtime if you want them on querystring.
This is completely accurate. Without knowing your exact implementation I can only make assumptions. But technically you could wrap your ajax call in a function and then you could either pass in the userId and generate the url within that function or pass in the url, performing the url generation outside of the function.
This would mean that you only need one function that performs the ajax request and you can have another function that gets the userId (and possibly generates the url) and then passes that into the ajax function. How you store the userId is entirely up to you, but one thing I would suggest is investigating data attributes which is a fairly well defined way for storing data on html elements.
Related
I'm using ajax POST method
to send objects stored in an array to Mvc Controller to save them to a database, but list in my controller is allways empty
while in Javascript there are items in an array.
here is my code with Console.Log.
My controller is called a ProductController, ActionMethod is called Print, so I written:
"Product/Print"
Console.Log showed this:
So there are 3 items!
var print = function () {
console.log(productList);
$.ajax({
type: "POST",
url: "Product/Print",
traditional: true,
data: { productList: JSON.stringify(productList) }
});}
And when Method in my controller is called list is empty as image shows:
Obliviously something is wrong, and I don't know what, I'm trying to figure it out but It's kinda hard, because I thought everything is allright,
I'm new to javascript so probably this is not best approach?
Thanks guys
Cheers
When sending complex data over ajax, you need to send the json stringified version of the js object while specifying the contentType as "application/json". With the Content-Type header, the model binder will be able to read the data from the right place (in this case, the request body) and map to your parameter.
Also you do not need to specify the parameter name in your data(which will create a json string like productList=yourArraySuff and model binder won't be able to deserialize that to your parameter type). Just send the stringified version of your array.
This should work
var productList = [{ code: 'abc' }, { code: 'def' }];
var url = "Product/Print";
$.ajax({
type: "POST",
url: url,
contentType:"application/json",
data: JSON.stringify(productList)
}).done(function(res) {
console.log('result from the call ',res);
}).fail(function(x, a, e) {
alert(e);
});
If your js code is inside the razor view, you can also leverage the Url.Action helper method to generate the correct relative url to the action method.
var url = "#Url.Action("Print","Product)";
I have a solution in my MVC project which allows me to show and/or hide a loading screen whenever I want to:
$("#divLoading").show();
$("#divLoading").hide();
This "divLoading" essentially contains the loading screen. Now this solution works fine most of the time; even if I want to use Ajax in order to show the loading screen when the script begins execution and hide it when the function is done. Something like:
$("#btnTreatData").click(function () {
$("#divLoading").show();
// Some stuff
$.ajax({
contentType: 'application/json; charset=utf-8',
url: '#Url.Action("TreatValidationData", "Article")',
type: "POST",
data: JSON.stringify({ listOfCheckedData: listOfCheckedData }),
success: function (result) {
$("#tableControl").html(result);
$("#divLoading").hide();
}
});
}
This works fine. However, there is one specific edge-case where I can't get this to work properly.
Essentially, this project uses a plugin named EEPlus (http://epplus.codeplex.com/) in order to export data into an XLS file. It's very practical for the user because they simply click on the button, and there's no redirection involved; when the file is done, the user is prompted to download it by the browser itself.
Essentially, my export method does something like this:
public void ExportListUsingEPPlus(string filter, string type)
{
// A boat load of data processing and formatting that isn't relevant here
// Once the work is done:
// Write in an Excel file
using (var memoryStream = new MemoryStream())
{
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", $"attachment; filename={filename}.xlsx");
excel.SaveAs(memoryStream);
memoryStream.WriteTo(Response.OutputStream);
Response.Flush();
Response.End();
}
}
You will notice this method doesn't return anything. It doesn't need to; in the View itself, it is called like this:
<li class="separator"><input value="Export xls" class="add" name="btn_submit" id="btn_excel" type="button" onClick="location.href='#Url.Action("ExportListUsingEPPlus", "Article", new { filter = #ViewBag.CurrentFilter, type="TEST"})'"></li>
Which is okay... except that if I try to use a loading screen for this, because exporting data can take a long while:
function exportWithLoadingScreen()
{
$("#divLoading").show();
$.ajax({
contentType: 'application/json; charset=utf-8',
url: '#Url.Action("ExportListUsingEPPlus", "Article", new { filter = #ViewBag.CurrentFilter, type = "TEST" })',
type: "POST"
}).complete(function (result) { $("#divLoading").hide();});
}
Ajax :
Doesn't proc a "success" event.
Doesn't proc a "failure" event.
Procs a "complete" event... but, of course, without location.href = '...', it doesn't actually do anything (the file is created in memory but the user is never prompted to download it).
If I try to use the same thing but caring about location.href, it procs the "complete" event far too early, possibly because it only cares when the redirection is complete, NOT when the method is done!
I really don't know what else I could try at this point, but it's so important to show a loading screen for this, because it really can take a long while.
Any ideas as to what else I could do? I'd appreciate it a lot!
EDIT: I'll be more precise and concise. This:
function exportWithLoadingScreen() {
$("#divLoading").show();
location.href = '#Url.Action("ExportListUsingEPPlus", "Article", new { filter = #ViewBag.CurrentFilter, type = "TEST" })';
$("#divLoading").hide();
}
Doesn't work, because all actions are simultaneous, so I have to use ajax. But this:
function exportWithLoadingScreen() {
$("#divLoading").show();
$.ajax({
contentType: 'application/json; charset=utf-8',
url: '#Url.Action("ExportListUsingEPPlus", "Article", new { filter = #ViewBag.CurrentFilter, type = "TEST" })',
type: "POST"
}).complete(function (result) { $("#divLoading").hide(); })
};
Doesn't work either, because location.href is NOT executed (=> user is not prompted for download). But THIS:
function exportWithLoadingScreen() {
$("#divLoading").show();
$.ajax({
contentType: 'application/json; charset=utf-8',
url: '#Url.Action("ExportListUsingEPPlus", "Article", new { filter = #ViewBag.CurrentFilter, type = "TEST" })',
type: "POST"
}).complete(function (result) { window.location.assign(result);})
};
Doesn't work, because the returned data is completely wrong (server error), because the ExportListUsingEPPlus method doesn't return anything.
EDIT EDIT: Edited question's title to refocus the question.
I think the confusion is made by the fact that you want to use an Ajax call, but also need to redirect the page.
Ajax is used to request data from the server back to the current page so that you can update the current page with the new data.
A redirect abandons the current page and replaces it with a new one entirely.
Here is another answer that explains it, with something that can simulate an Ajax request - but it still isn't an Ajax request if it is redirecting...
https://stackoverflow.com/a/9970672/4619012
You can get help from calling ajax events. Find it here https://api.jquery.com/Ajax_Events/
I need to pass list of strings from multiple select to the controller. Though the requirement looked very simple to me, I was breaking my head for the past hour in this. I have did a fair research on this, but unable to succeed.
Below is my Javascript code. Please ignore the comments. I was successfully able to fetch the list of items in the multiple select. While i do the ajax call, I get the error "Object reference not set an instance of an object.
function submitForm() {
var selected = $('#selectedTasks option').map(function(){
return this.value
}).get()
var postData = { selectedTasks : selected } //corrected as suggested
//selectedTasks = JSON.stringify({ 'selectedTasks': selected });
alert(postData);
$.ajax({
type: "POST",
//contentType: 'application/json; charset=utf-8',
url: '#Url.Action("AssignTasks", "MonthEndApp")',
dataType: 'json',
data: postData,
traditional: true,
success: function (data) {
alert("Success");
},
error: function (xhr) {
alert(xhr.responseText);
}
});
}
MonthEndAppController.cs
[HttpPost]
public void AssignTasks(List<String> selectedTasks)
{
//do something
}
Can someone guide me where exactly I have gone wrong? Can someone suggest me what is wrong?
EDIT : As suggested by Mr. Rory I have made the java script changes. Now the Java script part works absolutely fine. But the Controller is not getting called when the ajax request is made. Can someone help me out if something wrong in the call made to controller ?
Have you tried with string[] instead of List<String> ?
The parameter your AssignTasks action is expecting is called selectedTasks, not values:
var postData = { selectedTasks: selected };
Also note that when debugging anything in JS you should always use console.log() over alert(), as the latter coerces all types to a string, which means you're not seeing a true representation of the actual value.
I'm working on a ASP.NET MVC project that uses some jQuery on the client side. I have a jQuery call like this, which works correctly:
$.post($('form').attr("action"), $('form').serialize(), function(data){
// Deal with the data that came back from the ASP.NET MVC controller
}
I want to do the exact same call, except I also want to send in a custom header. I am able to successfully create and send a custom header like this:
var token = $('input[name="__RequestVerificationToken"]').val();
var headers = {};
headers['__RequestVerificationToken'] = token;
$.ajax({
url: "/report_observation/" + submitType,
cache: false,
type: "POST",
data: {
'viewModel': $('form').serialize(),
},
headers: headers,
success: function (data) {
// Deal with the data that came back from the ASP.NET MVC controller
},
error: function (response) {
alert("Error: " + response);
}
});
There are two problems with this second bit of code. One is that I have to make a custom url to go to the correct controller, and I don't know of a way to simply use $('form').attr("action") to automatically go to the correct place.
The second -- and bigger -- problem is that I'm not able to pass over the form data with $('form').serialize() as I could in the one liner $.post example. Doing a #Html.Raw(Json.Encode(Model)) in my Razor cshtml file doesn't send over the model for the whole form, presumably because this code is within a partial view that doesn't know the state of the models in the other partial views that make up this form.
Anyway, I'm thinking there must be an easy way to take this code...
var token = $('input[name="__RequestVerificationToken"]').val();
var headers = {};
headers['__RequestVerificationToken'] = token;
...and incorporate the headers property into this bit of code:
$.post($('form').attr("action"), $('form').serialize(), function(data){
// Deal with the data that came back from the ASP.NET MVC controller
}
However, I can't figure out the correct syntax. Any ideas?
OK, I figured it out. The second example can indeed work if the data field looks like this:
data: $("form").serialize(),
In other words, I had to NOT assign it to the viewModel parameter.
yes, for the second problem use that dev5000 says, and, for the URL, simply get the value for the attribute action fo the form and use it:
var url = $("from").attr("action");
$.ajax({
url: url,
...
})
I'm struggling to achieve the following, I have a page where a user Logs a Call, the user needs to input various fields and selects from several dropdowns, I then need to post that data (either via JQuery or the controller) to another page, where the user can view the entered data and decide to commit it or not.
I've been going back and fourth for ages now, trying to figure out how to post data from my cshtml to my controller and then redirect to another page with that data persisting.
I've tried to redirect via JQuery and/or the controller and just can't seem to get one or the other working.
Code extracts below:
cshtml:
$.ajax({
url: dir + '/Submit/',
async: true,
type: 'POST',
data: JSON.stringify(callData),
contentType: 'application/json; charset=utf-8',
complete: function () { },
success: function (data) {
}
})
Controller:
[HttpPost]
public ActionResult Submit(SupportCallModel callData)
{
SupportCallModel newData = new SupportCallModel();
newData.SupportCallID = 1;
newData.CallTypeID = callData.CallTypeID;
newData.TroubleShooting = callData.TroubleShooting;
newData.EmailRequest = callData.EmailRequest;
newData.MailDate = callData.MailDate;
newData.FSEOnSite = callData.FSEOnSite;
newData.FSEEmployeeID = callData.FSEEmployeeID;
newData.CallCategory = callData.CallCategory;
newData.CallType = callData.CallType;
newData.CallItem = callData.CallItem;
newData.Summary = callData.Summary;
newData.Description = callData.Description;
newData.ExternalReference = callData.ExternalReference;
newData.CallStatusID = callData.CallStatusID;
newData.CallPriorityID = callData.CallPriorityID;
newData.CallCoEmployeeID = callData.CallCoEmployeeID;
return RedirectToAction("Verify", newData);
}
public ActionResult Verify(SupportCallModel postData)
{
return View(postData);
}
Using ajax is pointless since ajax calls stay on the same page (return RedirectToAction("Verify", newData); is ignored). You can just do a normal submit. Assuming your rendering all the required inputs for SupportCallModel in view, then it will post back. I would recommend you include
[HttpPost]
public ActionResult Submit(SupportCallModel callData)
{
if (!ModelState.IsValid)
{
return View(callData);
}
...
at the top of the method in case the model contains validation errors.
You then create a new instance of SupportCallModel based on the properties of callData which also seems pointless (why not just pass callData instead of newData?)
If SupportCallModel contains only properties which are Value types then you can use return RedirectToAction("Verify", newData); or return RedirectToAction("Verify", callData);. Internally a RouteValueDictionary is created based on the name and value of each property and postData will be correctly bound in the Verify() method. If however any of the properties are complex types or collections then binding will fail for those properties. In that case you need to persist the model so it can be retrieved in the Verify method. My recommendation would be to persist to the database (either a separate table or the existing table that includes a field indicating a pending status), but you could use Session or TempData (in conjuction with .Peek so its not lost if the user hits the refresh button).
I'm not sure exactly what the Verify GET method is rendering, but if it does not include controls for all properties then the Verify submit button will need to post back some ID value that allows you the retrieve the model again from the database or session and finally save it to the database.
It's not working because you're redirecting on the server side when you're making the call via AJAX.
Your redirects should be made on the client side since you're calling the ActionResult on a non-traditional sense (AJAX).
You can remove the return RedirectToAction("Verify", newData); from your action result since it will not do anything. You can probably just return something that specifies whether the call was valid or not.
For your data to persist on another page, you will have to save the data into a temp table in DB so you can show it when you do a redirect.
$.ajax({
url: dir + '/Submit/',
async: true,
type: 'POST',
data: JSON.stringify(callData),
contentType: 'application/json; charset=utf-8',
complete: function () {
},
success: function (data) {
if (data && data.isValid) {
// Grab the tempId that was saved temporarily for verification.
var tempId = data.tempId;
// Perform redirect
window.location = dir + '/Verify/' + tempId;
}
}
});
In your url post...
$.ajax({
url: '#Url.Action("Submit","{ControllerName}")',
async: true,
type: 'POST',
data: JSON.stringify(callData),
contentType: 'application/json; charset=utf-8',
complete: function () { },
success: function (data) {
window.location.href = '#Url.Action("Verify","{ControllerName}", Model);'
}
})
You could model this all without Ajax using standard form posts to MVC controllers reasonably simply.
Assuming your flow looks something like this:
Make the Submit POST return a view containing the data sent in the model. If that data can be verified make the view allow the data on that form to be posted to a Confirm controller action.
In this design the data is entirely transient, the data sent in the HTTP form payload on the initial post is then returned as a form within the returned HTML. This data is then in turn sent to the Verify action.
To do this in your case I think it might be as simple as calling the Submit with the Post verb as a none Ajax call and amending it so the return line looks like return View("Verify", newData);
You will also obviously need to do something else with Verify to do something in that action method.