Different behaviour posting to controller via javascript than directly from submit button - javascript

I have this button in a form:
<button id="save" type="submit" formaction="#Url.Action("SaveEvent")" formmethod="post">Save</button>
Which posts to this controller:
public async Task<ActionResult> SaveEventAsync(EventDataModel vm)
{
// save to db etc...
TempData["Saved"] = true;
return RedirectToActionWithReturnUrl("EventDetail", new { eventId = vm.EventId });
}
This redirects me fine to the detail page. But if I then add this JS function to do the post, I don't get redirected nor do I see the value in TempData.
$('#save').click(function(e){
e.preventDefault();
$.post( "SaveEvent", {
EventID: "#Model.EventId",
SomeValue: 123
});
}
I tried redirecting in the JS function but it doesn't return me the newly saved values:
window.location = '#Html.Raw(#Url.Action("EventDetail", new { eventId = #Model.EventId}))';
Could someone please explain why the redirect in the controller does not work when posting from JS?

The Redirect related methods in controller (Redirect,RedirectToAction etc) returns a 302 response with the new url to be redirected to as the value of the location header and browsers will usually issue a new GET request to that.
You should not be making the call to an action method which returns a 302 response from an ajax call. Instead, you should return a json response to the ajax call which is making the request.
public async Task<ActionResult> SaveEventAsync(EventDataModel vm)
{
// save to db etc...
return Json(new {status = "success"});
}
and in your $.post method callback, inspect the response and do the redirection.
$('#save').click(function(e){
e.preventDefault();
var url="#Url.Action("SaveEvent","YourControllerName")";
$.post(url, { EventID: "#Model.EventId", SomeValue: 123 }, function(res){
if (res.status === "success") {
window.location.href =" #Url.Action("EventDetail","YourControllerName",
new { eventId=Model.EventId })";
}
});
});
I updated your code to use Url.Action method to build the correct relative url to the action method(s). If you javascript code is inside a separate js file, build the base url in your razor page and pass to your js code as explained in this post.

Related

How to return a view from laravel controller function upon ajax call?

I am working on a bookstore project where books can be added to cart, a user can select many books for adding them to cart. when the user clicks on the Add to Cart button, I am adding the IDs of the selected books in a JS array called cart. When all the selected books are added to the cart then I want to link <a> tag with ajax call that will hit the url of a controller function and will send the JS cart array object to the controller function and then in the controller function, I want to return view to the browser, I do not want the controller function to return the response back to the ajax call but instead I want to return the view to the browser.
Here is the JS function that adds the ID of the selected books to the cart JS array:
function addToCart(id)
{
if(! cart.includes(id) ) cart.push(id);
cartLength.html(cart.length);
$('#successCart'+id).html('Book added to cart.');
}
Here is the <a> tag that calls the ajax function, the function name is showCart():
<a href="#" onclick="event.preventDefault(); showCart();">
<i class="fa fa-shopping-cart"></i>
<span id="cartLength"></span>
</a>
Here is the showCart() function that has ajax code:
function showCart()
{
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$.ajax({
url:"cart",
method:'post',
data:{cart:cart},
dataType: 'html'
})
.done(function(msg){
});
.fail(function(msg){
alert(msg.responseJSON.errors);
});
}
Here is the controller function - I want this function to directly return the view to the browser without sending it back to the ajax call:
public function showCart(Request $request)
{
return view('cart', ['cart' => $request->cart ]); // this should be returned to the browser and not to the ajax call
}
Here is the route for the controller function:
Route::post('/cart', 'HomeController#showCart')->name('home.cart');
EDIT:
I have temporarily solved the issue with the following tricks but that is not a permanent solution:
After calling the showCart() function from ajax for sending the cart array variable from js to laravel controller, I used the following logic to store the books in a session variable whose ids are stored in the cart array:
public function showCart(Request $request)
{
session()->put('cart_books', Book::whereIn('id', $request->cart)->get());
session()->save();
return "success";
}
After storing the result of the query in a session variable, I created another GET route for /cart as below:
Route::get('/cart', 'HomeController#viewCart');
Then upon success of the post ajax call, I called /cart with get method as below:
.done(function(msg){
console.log('calling cart');
location.href = "cart"; // Here I call the `/cart` with `get` method which will hit the `viewCart()` function of HomeController which will return the view back to the browser along with the results that were stored in the session variable.
})
And this is the viewCart() controller function that returns the view to the browser and sends the session variable's data to the view:
public function viewCart()
{
$random_books = Book::all()->random(4);
$categories = Category::all();
return view('cart', ['cart_books' => session()->get('cart_books'),
'random_books' => $random_books, 'categories' => $categories]);
}
I want the controller function to return the view to the browser without returning it to the ajax call, any help is appreciated in advance.
You can return Raw html from ajax call by rendering and returning the view inside your controller as,
return view('cart', ['cart' => $request->cart])->render();
This will return the raw HTML and you can further use it. However, returning HTML from ajax is not a good way, You can return JSON from the controller and render the view in frontend according to the JSON data.
As the others said you can use
return view('cart', ['cart' => $request->cart])->render();
and in you jQuery do
.done(function(response){
document.write(response);
});
Or you can return the link that its content should be shown to the user and redirect the user in your done method. So in your back-end you'll have
return route('cart', ['cart' => $request->cart]);
and in your front-end you'll have
.done(function(response){
location.href = response;
});
In the controller function just add render method like the following line
public function showCart(Request $request)
{
return view('cart', ['cart' => $request->cart ])->render();
}
For js:
$.ajax({
method: 'POST', // Type of response and matches what we said in the route
url: '{{ route('home.cart') }}', // This is the url we gave in the route
data: {'cart' : cart}, // <-- this is your POST data
success: function(response){ // What to do if we succeed
console.log(response);
},
error: function(jqXHR, textStatus, errorThrown) { // What to do if we fail
console.log(JSON.stringify(jqXHR));
console.log("AJAX error: " + textStatus + ' : ' + errorThrown);
}
});
You're doing a XHR, so you shouldn't return the whole HTML view from your controller unless you plan to replace your existing element with the returned HTML, like how you're doing with addToCart. What you need here is a redirection after your POST, and your temporary solution isn't actually a bad solution :) Here's a similar question as yours with the same answer. In fact, I highly recommend your temporary solution over the alternative solution below.
Since you wish to use the view returned from your controller without returning it to your ajax, a rather unorthodox approach would be to POST through a <form>. You can dynamically create a <form>, with the <input>s of your data, and submit.
function postData(actionUrl, method, data) {
var mapForm = $('<form id="mapform" action="' + actionUrl + '" method="' + method.toLowerCase() + '"></form>');
for (var key in data) {
if (data.hasOwnProperty(key)) {
mapForm.append('<input type="hidden" name="' + key + '" id="' + key + '" value="' + data[key] + '" />');
}
}
$('body').append(mapForm);
mapForm.submit();
}
function showCart()
{
postData('cart', 'post', cart);
}
I borrowed the above code from here. You can do the same with vanilla JS too.

Submit on an ASP.NET MVC form?

Is there a way I can get the returned value from an action using .submit event listener in jQuery?
I have a problem which is when the action is completed it returns a JSON file and my browser navigates to an empty page and just display the JSON returned. I don't want that to happen, I want to be able to read the JSON result and based on it decide what to do.
Here's my POC:
View:
#using (Html.BeginForm("SubmitTest", "DMS", FormMethod.Post, htmlAttributes: new { id = "formId" }))
{
<input type="submit" value="Sumbit" />
}
Controller:
public JsonResult SubmitTest()
{
return Json("Done");
}
Script:
$(document).ready(function () {
$("formId").submit(function () {
alert("Submitted");
});
});
you can add event.preventDefault or return false to prevent the default event from occurring . so it won't navigate to an empty page.
$(document).ready(function () {
$("formId").submit(function () {
alert("Submitted");
return false;
});
});
EDIT:
if you want to get the response you need to make an ajax request and get the form data from the fields. you can't get the response with submit function.
$(document).ready(function () {
$("formId").submit(function () {
/// make an AJAX request
$.post(
$(this).attr('action'), //// action url
$(this).serialize(), //// serialize form fields
function(json) {
alert(json);/// json response
}, 'json');
return false; /// prevent navigation
});
});
Use an AJAX form instead of the HTML form, this way you can check the response after it is submitted and do whatever you need using the OnSuccess handler.
For detailed info refer to this article

How to auto refresh a partial view?

How to auto refresh a partial view?
public PartialViewResult Chat(string people)
{
if (User.Identity.IsAuthenticated)
{
var model = new MessageVM()
{
realReceiver = people,
messageList = db.messages.Where(x => x.sender == User.Identity.Name || x.sender == people).ToList().Take(30)
};
return PartialView("_Chat", model);
How to auto refresh this partialview
Just to test quickly, change your controller action for Chat from POST to GET. Then call it by pasting the address in your browser address bar. You can include the value for people parameter like this at the end of the URL:
?people=valueForPeople
Check the returned HTML and ensure that is what you are expecting. Once you have confirmed the action is returning the HTML you want, then you can change back to POST if you prefer. Then use the jQuery code below.
One option is to setup a timer on the client side which will call your controller and then you can do whatever you need with the returned data.
window.setInterval(function() {
// send get request to server
$.ajax({
url: '/Chat',
type: "POST", // or use GET
data: whateverYourArgumentsAre, // people
success: function (partialViewHtml) {
$("#divLt").html(partialViewHtml);
});
},
error: function () {
alert('Something went wrong');
}
});
}, 5000); // Every 5 seconds, 5000 ms
Html.Action("Messages","Chat", new { people= "give some data"})

JQuery not calling HttpPost method on my controller. How can I fix this, or what could be going wrong?

I have a special case where I need to have a grid with an "Add New Record" row, that exists within an MVC form.
Since I can't submit the new record details, without submitting the entire form, I decided to make the record submit button call a Javascript method that should POST the data to a method on my controller. In short, here is an example of what I'm doing. The code below is copy-and-pasted from my project, with only minor modifications for brevity.
...
<table>
CODE HERE FOR MY GRID...
</table>
...
<input class="data_field" id="MainSession_Name" type="text" />
<input class="data_field" id="MainSession_Type" type="text" />
<button id="btnAddMainSession" class="button" onclick="SubmitMainSession()" type="button">Add Session</button>
...
<script>
var SubmitMainSession = function()
{
var data = {
Name: $('MainSession_Name').val(),
RecType: $('MainSession_Type').val(),
};
$.post(
{
url: "/Session/Add",
data: data,
callback: function(res, status)
{
if (res !== "OK")
alert("There was a problem processing the request. " + res);
else
location.reload(true);
}
});
}
</script>
My intent is simple. After the user enters new details for a session, they will click on the Add Session button. JQuery will make a POST request passing my data to my page controller.
Here is an abbreviated variation of my controller:
//Index that initially loads the data.
public ActionResult Index(int id = -1)
{
SessionModel sm = new SessionModel(id);
sm.CanEdit = true;
return View(sm);
}
//The containing model manages a HUGE form,
//across multiple BootStrap.js tabs. We save
//all other, non-sub-record related deets here.
public ActionResult Submit(SessionModel model)
{
model.Save();
return Redirect(Url.Content("~/"));
}
//Since there are multiple grids, I need to
//have a way to add new Session records.
//This is my first attempt at trying to
//create a POST method on my controller.
[HttpPost]
public string Add(AddSessionObject data)
{
//If I can ever get here, I'll save the data.
return "OK";
}
public class AddSessionObject
{
public string Name;
public string RecType;
}
What I'm experiencing is that when I make the $.post(...) call in JQuery, MVC always calls the Index(...) method, rather than the Add(...) method. What am I doing wrong?
try using this syntax:
var data = {
Name: $('MainSession_Name').val(),
RecType: $('MainSession_Type').val(),
};
$.post("/Session/Add", data, function(res, status) {
if (res !== "OK")
alert("There was a problem processing the request. " + res);
else
location.reload(true);
});
https://api.jquery.com/jquery.post/

Calling a HTTP POST method in a MVC Controller from the View's Javascript & Database saving

I am trying to update a value in my database. When the user presses the update button this script is called.
View Code:
<script>
function scr_UpdateQuote(field) {
var r = confirm("Are you sure you want to update your quote?");
if (r == true) {
var textBox_UserTitle = document.getElementById(field);
*CODE TO POST METHOD HERE*
}
}
</script>
In the controller, the value is then revived and saved into the database. A message is sent back to let the user know their quote was updated.
Controller Code:
[HttpGet]
public ActionResult UpdateQuote(string newQuote)
{
*REPLACE QUOTE IN DATABASE*
ViewBag.QuoteUpdated = "Your Quote has been updated.";
return View();
}
I am having difficulty finding out how to write the code described between the **'s
(For the database part I have a user-id that can be used to identify the row)
You can use form posting like this:
$("#YourForm").submit(function() {
$.post("/YourController/UpdateQuote", $("#YourForm").serialize())
//this will serialize your form into:
// newQuote=someValue&&someOtherVariable=someOtherValue etc.
.done(function(data) {
// do what ever you want with the server response
});
})
or you can use an ajax post:
$.ajax({
type: "POST",
url: "/YourController/UpdateQuote",
data: {newQuote: document.getElementById(field)},
dataType: "json",
success: function(data) {
// do what ever you want with the server response
},
error: function(){
// error handling
}
});
For using the data, assuming you have an DbContext called MyDbContext:
[HttpGet]
public ActionResult UpdateQuote(string newQuote)
{
// get userID somehow, either from session, or pass as another parameter here
using (var dc = new MyDbContext)
{
var quoteToUpdate = dc.QuotesTable.FirstOrDefault(q => q.UserID == userID)
quoteToUpdate.quoteColumn = newQuote;
dc.SaveChanges();
}
ViewBag.QuoteUpdated = "Your Quote has been updated.";
return View();
}

Categories

Resources