ASP.NET Core MVC - VIew is not updated correctly - Ajax? - ajax

I have an ASP.NET Core 6 MVC application.
On one page I have a table; I want to support drag'n'drop for its rows. Afterwards the User is able to click on "Submit" and make the changes permanent.
The changes are sent to the controller and persisted to the database, however when I redirect to the GET to show the page again, a part of it is wrong!
#model MyViewModel
<form>
#Html.HiddenFor(y=>y.Id)
<table id="orderTable" class="table">
<thead>
<tr>
<th>
Name
</th>
<th>
Order
</th>
</tr>
</thead>
<tbody>
#foreach (var data in Model.Data)
{
<tr id='#data.Id'>
<td>#data.Name</td>
<td>#data.Order</td>
</tr>
}
</tbody>
</table>
<div class="form-group">
<input type="submit" value="Save" id="SaveOrderButton" />
</div>
</form>
<script>
$(document).ready(function() {
$('#orderTable tbody').sortable();
$("#SaveOrderButton").click(function(e) {
e.preventDefault();
var newOrder = $('#orderTable tbody').sortable('toArray');
$.ajax({
url: '/Controller/Update',
type: 'POST',
data: { rowOrder: newOrder, id: #Html.Raw(Model.Id) },
success: function(response) {
console.log(response);
},
error: function(xhr,status, error){
console.log("An error occurred: " + xhr.responseText);
}
});
});
});
</script>
Backend:
[HttpGet]
public async Task<IActionResult> Order(int id)
{
var data= await context.Data
.AsNoTracking()
.Where(x => x.Id== id)
.ToListAsync();
data = data.OrderByDescending(y => y.Order.HasValue)
.ThenBy(y => y.Order)
.ToList();
var viewModel = new MyViewModel()
{
Data = data,
Id = id,
};
ModelState.Clear(); // found on SO, but does not change anything
return View(viewModel);
}
[HttpPost]
public async Task<IActionResult> Update(int[] rowOrder, int id)
{
var data= await context.Data
.Where(y => rowOrder.Contains(y.Id))
.ToListAsync();
for (int i = 0; i < rowOrder.Count(); i++)
{
data.First(y => y.Id == rowOrder[i]).Order = i;
}
try
{
context.UpdateRange(data);
await context.SaveChangesAsync();
}
catch (Exception ex)
{
logger.LogError("..........");
return Json(500, "Could not update new order.");
}
return RedirectToAction(nameof(Controller.Order), new { id= id});
}
Okay, so I go the the view with GET and everything is shown correctly, then I change something and click on "Save". Everything in the POST will be correctly done. The database is updated.
I then redirect to the GET method again, there everything is loaded correctly from the database and in the correct order.
Then I set a breakpoint in the View and there the stuff in the for is correct too.
However, when I look in the browser, the "Order" column is wrong. The table still shows the data how it looked like after I reordered it and before I clicked on "Save".
What is happening here? Is the sortable lib using a cache in the background that I have to invalidate?
I don't use a cache anywhere in my project, btw.
Also, when I go to the console after a POST, the whole website's HTML is in there.
When I now reload the page with the GET, everything is shown how it is supposed to be.
Has it something to do with Ajax? I have already removed the success and error events, which doesn't change anything.

Has it something to do with Ajax? I have already removed the success
and error events, which doesn't change anything.
Yes, the issue relates the Ajax method.
As we all known, when we use Ajax to update the part of view page, after calling the action method, it will return the response result to the success function, then in the success function, we get the updated data from the response, and then dynamic populate the table to update the page and achieve the part of page refresh behaviors.
So, in your scenario, you can try to use the following methods to display the updated data.
Method 1:
In the Update Action method, return the updated data as result, instead of redirect to another action result. Then, in the Ajax success function, get the data from response, then clear the table content first and re-populate it using the response data.
Method 2:
In the Ajax success function, use location.reload(); method to reload current page, or use window.location.href to refresh the current page.

Related

ASP.NET MVC partial view refresh on button click

I'm using VS 2013, MVC 5.
Here is the content of my partial view (_Sales.cshtml):
#model IEnumerable<SomeModel>
<div id="outer">
<div id="inner1">
#(Html.Kendo().Chart<SomeModel>(Model)
...
)
</div>
<div id="inner2">
<table>
<tr>
<td>Total Sales </td>
<td>#Model.First().TotalSales.ToString("C")</td>
</tr>
<tr>
<td>Total Discount </td>
<td>#Model.First().TotalDiscount.ToString("C")</td>
</tr>
</table>
</div>
</div>
Below is an action method used while loading first time:
public ActionResult _Sales()
{
IEnumerable<SomeModel> salesList = null;
SearchCriteriaObject criteria = null;
salesList = getting data as list;
return PartialView(salesList);
}
So far, all work fine as expected. That's my partial view is rendering fine with initial data.
Now my requirement is I need to refresh my partial view as user specify search criteria and hit search button.
Here is the search button specific action method:
public ActionResult Get_BulletChartData_Updated(SearchViewModel criteriaModel)
{
IEnumerable<SomeModel> salesList = null;
SearchObject criteria = new SearchObject();
if (ModelState.IsValid)
{
if (criteriaModel != null)
{
//populating criteria here
}
salesList = //Getting data in list format
}
return PartialView(salesList);
}
On search button click event handler in javascript, I do this:
$("#btnSearch").click(function () {
...
var Url = $('#Url').val(); //Getting action method url from hidden field
$.ajax({
type: "POST",
dataType: 'HTML',
data: JSON.stringify(SearchViewModel),
url: Url, //#Url.Action("Get_SalesDataFiltered", "Sales")
contentType: "application/json; charset=utf-8",
success: function (result)
{
alert('success');
//$("#outer").load(result);
},
error: function ()
{
alert("error");
}
});
On search button click, I always get error alert message.
Could you please guide me the correct way to achieve this.
I'm new to MVC. Please feel free to ask for more info.
If you provide me with code, it'd be great.
Thanks.
I think that your problem is that you post a json object, while your post method has as a parameter a SearchViewModel object.
I believe that If you change this
data: JSON.stringify(SearchViewModel)
to this
data: $("#yourFormId").serialize()
you will get the expected result.

MVC3 Razor Ajax.ActionLink won't use POST method

I've got a page that contains multiple links. These links should do an ajax post and callback. However, the link is doing a Get instead of a Post. This causes a 404 error since I do not have an action method to handle a get at the requested URL.
If I remove the HTTPPost attribute from my Action method, the link works, but the call back fails and the Json I return is rendered in a new page.
Here is the code I'm using in my view.
<td id="action-#item.ItemID">#Ajax.ActionLink("Add", "AddToOrder", new { itemID = item.ItemID }, new AjaxOptions { HttpMethod = "POST", OnSuccess = "actionCompleted" }, new { id = "add-" + item.ItemID })</td>
This ends up adding this HTML:
<td id="action-012679"><a data-ajax="true" data-ajax-method="POST" data-ajax-success="actionCompleted" href="/mysite/neworder/AddToOrder?itemID=012679" id="add-012679">Add to Order</a></td>
My Controller has the following Action Method.
[HttpPost]
public JsonResult AddToOrder(string itemID) {
return Json(new { id = itemID, Action = "Added", "Just getting this working"});
}
My callback method that is called on Success looks like this:
<script language="javascript" type="text/javascript">
function actionCompleted(response, status, data) {
alert("We have returned");
}
</script>
If I change the [HTTPPost] attribute on my action method to [HTTPGet] I get an Json error. I can fix this by adding the JsonRequestBehavior.AllowGet to my return value, but this doesn't use the call back function defined on the page and fails.
Any help would be appreciated.
Probably you don't have jquery.unobtrusive-ajax.js script attached to page and link is gracefully degraded to regular anchor.
In order to have this working properly. You need to add references to these scripts on your page:
MicrosoftAjax.js
MicrosoftMvcAjax.js

How to POST to database through URL

I'm writing a web application in Spring/Hibernate that handles basic voting functionality. I want to have a link to /vote/{gameId} which will add that vote to the database for that specific ID. I'm really at a loss as for how to accomplish this though. Here's what I've tried in my controller:
#RequestMapping(value="/vote/{gameId}", method = RequestMethod.POST)
public String addVote(#PathVariable("gameId")
Integer gameId) {
Vote vote = new Vote();
vote.setGameId(gameId);
voteService.addVote(vote);
return "redirect:/games/wanted.html";
}
Here's where the link shows up in a jsp:
<c:if test="${!empty games}">
<table>
<tr>
<th>Game Title</th>
<th>Votes</th>
<th> </th>
</tr>
<c:forEach items="${games}" var="game">
<tr>
<td><c:out value="${game.title}"/></td>
<td>Placeholder</td>
<td>Vote!</td>
</tr>
</c:forEach>
</table>
</c:if>
When I try this though I just get a 404 error. Any insight would be great.
This is how you make a post call with plain Javascript:
var url = "vote";
var params = "id=1";
http.open("POST", url, true);
//Send the proper header information along with the request
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.setRequestHeader("Content-length", params.length);
http.setRequestHeader("Connection", "close");
http.onreadystatechange = function() {//Call a function when the state changes.
if(http.readyState == 4 && http.status == 200) {
alert(http.responseText);
}
}
http.send(params);
You need to call this in the onclick of your link.
On the other hand it is a lot easier if, for example, you use the jQuery Javascript library:
For your particular case it would be something like:
$.post("vote", { id: "1" } );
Or the full jQuery answer (remember to replace #linkid with the id of you tag):
$(document).ready(function() { //this runs on page load
// Handler for .ready() called.
$('#linkid').click(function(event) { //this finds your <a> and sets the onclick, you can also search by css class by type of tag
$.post("vote", { id: "1" } );
return false; //this is important so that the link is not followed
});
});

Partial view in MVC3 Razor view Engine

I have an view in MVC3 Razor view engine like following image. Now i want to Confirm Connection Action Output show under this link text not New page. How can i done this work?
Please explain with example code.
My View Like this :
#model ESimSol.BusinessObjects.COA_ChartsOfAccount
#{
ViewBag.Title = "Dynamic Account Head Configure";
}
<h2>Dynamic Account Head Configure</h2>
<table border="0">
<tr>
<td> Select an Server Connection </td>
<td style="width:5px">:</td>
<td>#Html.DropDownListFor(m => m.DBConnections, Model.DBConnections.Select(x => new SelectListItem() { Text = x.ConnectionName, Value = x.DBConnectionID.ToString()}))</td>
</tr>
<tr>
<td> </td>
<td style="width:5px"></td>
<td>#Html.ActionLink("Confirm Connection", "ConformConnection")</td>
</tr>
</table>
AND My Controller action Like following :
public ActionResult ConfirmConnection()
{
return PartialView();
}
I'm a big fan of using jquery and ajax for this kind of thing ...
http://api.jquery.com/jQuery.ajax/
If you are following the typical MVC model then you can add an action link to the page using something like ...
#Html.ActionLink("controller", "action", args);
but I would go for the ajax driven approach ...
<script type="text/javascript">
var ajaxBaseUrl = '#Url.Action("yourController", "ConformConnection", new { args })';
$(link).click(function () {
var currentElement = $(this);
$.ajax({
url: ajaxBaseUrl,
data: { any other queryString stuff u want to pass },
type: 'POST',
success: function (data) {
// action to take when the ajax call comes back
}
});
});
});
</script>
First move your markup to a partial view. After that define an action method that renders your partial view.
[ChildActionOnly]
public ActionResult ConfirmConnection(COA_ChartsOfAccount model)
{
return PartialView("MyPartialView", model);
}
ChildActionOnly attribute makes sure this action method cannot be called by a HTTP request.
Then you can display it whenever you want using Html.Action method.
#Html.Action("ConfirmConnection", "MyController", new { model = Model })
Ignore passing the model as a parameter if it doesn't change by the page you display it. You can retrieve it in your action method.

The error of can not find View in Ajax form

I ask a similar question here
So I add Some OnComplete Functions and Id to Ajax Forms, And there is:
This is My View:
#foreach(var item in Model) {
<tr id="TR#(item.Id)">
#{Html.RenderPartial("_PhoneRow", item);}
</tr>
}
_PhoneRow:
#model PhoneModel
#using(Ajax.BeginForm("EditPhone", new { id = Model.Id }, new AjaxOptions {
UpdateTargetId = "TR" + Model.Id,
OnComplete = "OnCompleteEditPhone"
}, new { id = "EditAjaxForm" + Model.Id})) {
<td>#Html.DisplayFor(modelItem => Model.PhoneNumber)</td>
<td>#Html.DisplayFor(modelItem => Model.PhoneKind)</td>
<td><input type="submit" value="Edit" class="CallEditPhone" id="edit#(Model.Id)" /></td>
}
Controller:
public ActionResult EditPhone(long Id) {
//Get model by id
return PartialView("_EditPhoneRow", model);
}
public ActionResult SavePhone(PhoneModel model) {
//Save Phone, and Get Updatet model
return PartialView("_PhoneRow", model);
}
_EditPhoneRow
#model PhoneModel
#using(Ajax.BeginForm("SavePhone", new { id = Model.Id }, new AjaxOptions {
UpdateTargetId = "TR" + Model.Id,
OnComplete = "OnCompleteSavePhone"
})) {
<td>#Html.EditorFor(modelItem => Model.PhoneNumber)</td>
<td>#Html.EditorFor(modelItem => Model.PhoneKind)</td>
<td><input type="submit" value="Save" class="SaveEditPhone" id="save#(Model.Id)" /></td>
}
And Oncomplete Scripts:
function OnCompleteEditPhone() {
$('input.SaveEditPhone').click(function () {
var id = $(this).attr("id").substring(4);
$('form#SaveAjaxForm' + id).trigger('submit');
});
}
function OnCompleteSavePhone() {
$('input.CallEditPhone').click(function () {
var id = $(this).attr("id").substring(4);
$('form#EditAjaxForm' + id).trigger('submit');
});
}
So Click Edit Worked perfect, Then Click Save Worked good also, But in second time when i click the Edit Button I have an Error in Post Action I copy the Firebug console here:
http://Mysite/members/editphone/7652 200 OK 582ms
http://Mysite/members/savephone/7652 200 OK 73ms
http://Mysite/members/editphone/7652 500 internal server error 136ms
<title>The view 'EditPhone' or its master was not found or no view engine supports the searched locations. The following locations were searched: ...
So where is the problem? If I remove OnCompleteSavePhone The Edit button for second time not worked, and with this function I have an error that not make any sense, How Can I fix it? I actually load partial views by Ajax, And need the buttons of this views worked correctly, at first every thing is fine but after Ajax result They don't, I think to add some Oncomplete functions, but there is an error also.
Your previous question is answered now. You had broken markup. As a consequence of this you no longer need to care about any OnComplete events and doing some auto triggers, form submissions and stuff. This will be handled by the Ajax.BeginForm infrastructure automatically for you.

Resources