ASP MVC - many request at one Ajax.BeginForm click - javascript

I have question about requests - their count.
Im using Ajax.BeginForm and onSuccess option.
But when I click that form my JS handler for OnSuccess option fires up many times.
I looked up for my request and its looks like this:
Image with number of request
So my question is: why if I click on AjaxForm it makes many request?
Thanks
View with Ajax action link:
#foreach (var item in Model)
{
if (item.Accepted == false)
{
<text>
<tr>
<td>
#Html.DisplayFor(modelItem => item.Accepted)
</td>
<td>
#Html.DisplayFor(modelItem => item.IsOrganizer)
</td>
<td>
#Html.DisplayFor(modelItem => item.PlayerRating)
</td>
<td>
#Html.DisplayFor(modelItem => item.FirstName)
</td>
<td>
#Ajax.ActionLink("Akceptuj", // <-- Text to display
"AcceptPlayer", // <-- Action Method Name
new { id = item.PlayerId },
new AjaxOptions
{
HttpMethod = "POST",
})
</td>
</tr>
</text>
}
}
Controller action:
[Authorize]
public ActionResult AcceptPlayer(long id)
{
using (var Players = new DbMigrationExample2Entities())
{
Player playerToAccept = Players.Player.Find(id);
if (playerToAccept == null)
{
return HttpNotFound();
}
playerToAccept.Accepted = true;
Players.SaveChanges(); return View();
}

If you have included jquery.unobtrusive-ajax.min.js twice once in the layout once in the partial. So your browser executes the js inside twice which will subscribe twice on the form click event that is why doing two POST instead of one.
So you need to remove the jquery.unobtrusive-ajax.min.js from the partial.
Note: If your are using a partial with a layout you don't need to duplicate the js included in the partial because it's already done by the layout. There are some good articles about layouts and partials.
Second think if problem persist then the solution here :
First ajax request is sent multiple times
If nigher this all solution is not working in your case then definitely you need to change your Ajax.ActionLink into Html.ActionLink Like :
#Html.ActionLink(article.Title, new { controller = "Akceptuj", action = "AcceptPlayer", id = item.PlayerId }, new AjaxOptions { HttpMethod = "POST" })
Cheers !!

Related

Ajax paging is duplicating _layout page while using pagination to replace page content

I am using x.PagedList to use pagination in my ASP.NET MVC page. The only problem I have with the plugin is , it used a page refresh when I navigate between pages.
To avoid that I am using jQuery calls to replace page contents as explained in this article.
My View and javascript looks like this.
<div id="circuitsContent">
<table class="table">
<tr>
--Header
</tr>
#foreach (var item in Model)
{
<tr>
--Loop through and create content
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.ID }) |
#Html.ActionLink("Details", "Details", new { id = item.ID }) |
#Html.ActionLink("Delete", "Delete", new { id = item.ID })
</td>
</tr>
}
</table>
</div>
<div id="circuitContentPager">
#Html.PagedListPager((IPagedList)Model, page => Url.Action("Circuits", new { page }))
</div>
#section scripts
{
<script language="javascript" type="text/javascript">
$(document).ready(function () {
$(document).on("click", "#circuitContentPager a[href]", function () {
$.ajax({
url: $(this).attr("href"),
type: 'GET',
cache: false,
success: function (result) {
$('#circuitsContent').html(result);
}
});
return false;
});
});
</script>
And this is my controller code:
public ActionResult Circuits(int? page)
{
var pageNumber = page ?? 1;
var circuits = _repo.GetAllCircuits().OrderBy(circ=>circ.ID).ToList();
var pagedCircuits = circuits.ToPagedList(pageNumber, 25);
return View(pagedCircuits);
}
What am I missing here?
Your ajax call returns the html from Circuits() method which is the same view you have used to render the page initially, which includes all the initial html, but you only replacing part of of the existing page, so elements such as the paging buttons generated by the #Html.PagedListPager() method are going to be repeated. Your also generating invalid html because of duplicate id attributes (you will have multiple <div id="circuitsContent"> elements
There are 2 ways you could solve this.
Create a separate controller method that returns a partial view of just the <table> and call that method, however you would need to extract the value of the page number for the href attribute of you pager buttons to pass that as well.
Using your current Circuits() method, test if the request is ajax, and if so, return a partial view of just the <table>.
public ActionResult Circuits(int? page)
{
var pageNumber = page ?? 1;
var circuits = _repo.GetAllCircuits().OrderBy(circ=>circ.ID);
var pagedCircuits = circuits.ToPagedList(pageNumber, 25);
if (Request.IsAjaxRequest)
{
return PartialView("_Circuits", pagedCircuits);
}
return View(pagedCircuits);
}
Note: Do not use .ToList() in your query. That is defeating the whole purpose of using server side paging because .ToList() immediately downloads all the records fro the database.
Where _Circuits.cshtml would be
#model IEnumerable<yourModel>
<table class="table">
<thead>
<tr>
// <th> elements
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
.... // Loop through and create content
</tr>
}
</tbody>
</table>
Note that your header elements should be in a <thead> element and the records in a <tbody> element.

Using iterative variable from C# for loop in JavaScript function

On one of my pages I have a for loop to iterate through a list of "Projects" (which is the main model for my website) and display some of their data. The following code is nested in a table and the middle cells removed for redundancy.
foreach (var item in Model.Projects)
{
<tr>
<td>#Html.DisplayFor(modelItem => item.SubmissionNumber)</td>
<td>#Html.DisplayFor(modelItem => item.Status)</td>
<!-- and so on -->
<td>#Html.ActionLink("Detail", "DisplayDetails", new { id = item.ProjectID })</td>
</tr>
}
The "Detail" link in the last cell will ideally make a box pop up (I'm thinking of using a Modal via Bootstrap) containing all of the data for the project. The "DisplayDetails" controller action returns a partial view that presents this information, but since I'm not using JavaScript or anything to render the partial view on the current page it renders it as it's own unformatted page. This is the controller action:
[HttpGet]
public ActionResult DisplayDetails(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Project project = db.Projects.Find(id);
if (project == null)
{
return HttpNotFound();
}
return PartialView("~/Views/Projects/_Detail.cshtml", project);
}
Ideally I would pass the ID to the controller using AJAX like I did below (which is code from another page of my website, again edited to remove redudancy):
$("#show").on("click", function () {
$.ajax({
url: '/Projects/SearchTable',
type: "GET",
data: {
Line1: $('#' + '#Html.IdFor(m => m.Project.ProjectAddress.Line1)').val(),
// and so on
County: $('#' + '#Html.IdFor(m => m.Project.ProjectAddress.County)').val(),
}
}).done(function(partialViewResult) {
$(".wrapper").html(partialViewResult);
$(".wrapper").css('display', 'block');
});
});
And by doing this I can embed the partial view onto the current page instead of it opening as a new page. I'm just not sure how to pass the project ID for a specific row in the table as data to the controller. Is this even possible? If not is there another way to achieve the same result?
You can replace your ActionLink with this:
<td>Details</td>
Then,
$(".details").on("click", function (e) {
e.preventDefault();
var projectId = $(this).data('id');
// Make the AJAX call here...
});

Asp Net MVC 5 refresh a table in a partial view

So i ran into a little problem and i am having a hard time understanding what I should do to get the result I want/need.
So my application is supposed to show the route a certain object made in the last 2 hours. When the user loads the app they see several points scattered through out the map and when they click on one of those objects the route it made in the last 2 hours is shown, and a table I have is supposed to be updated with those coordinates. Now I make the call to fill the partial view when I get all the locations the object went to in the controller method.
this is how I start all of this (when the user clicks a point the following is executed)
(I am using openlayers 3 but it is irrelevant to this question)
$.ajax({
type: "GET",
url: '/Controller/GetRoutes',
dataType: "json",
success: function (result) {
alert('Added');
var layerLines = new ol.layer.Vector({
source: new ol.source.Vector({
features: [
new ol.Feature({
geometry: new ol.geom.LineString(routes, 'XY'),
name: 'Line'
})
]
})
});
map.addLayer(layerLines);
},
error: function (xhr, ajaxOptions, thrownError) {
//some errror, some show err msg to user and log the error
alert(xhr.responseText);
}
});
So as you can see from this code the method GetRoutes() is going to be responsible for getting the information on where the object has been to.
This is the controller (I omitted most of the code thats responsible for drawing the actual routes since its quite a bit chunky)
[HttpGet]
public JsonResult GetRoutes()
{
var lastpoints = get an arraylist with all the points I want
var name = get the name of the object
RouteInformation(lastPoints,name);
return Json(lastPoints, JsonRequestBehavior.AllowGet);
}
I know I should probably change something here but i do not know what.
The method that gives me the last points is not mine, but I am required to use it so I have no other choice but to accept the arrayList it returns to me.
this is the RouteInformation method
public ActionResult RouteInformation(ArrayList routeList, string name )
{
List<ObjPoint> routes = routeList.OfType<ObjPoint>().ToList();
List<ObjRoute> objRoutes = new List<ObjRoute>();
objRoutes.Add(new ObjRoute()
{
name = name,
ObjPoints = routes
});
return PartialView("RouteDetailsView", objRoutes);
}
My issue is updating/refreshing that table, I have it in a partial view but I have no idea on what I have to do in order update that table with the information I want to display (i can get that information I just canĀ“t seem to show it).
ObjPoint is composed of latitude,longitude, date, time.
This is the ObjRoute model
public class ObjRoute
{
public string name { get; set; }
public List<ObjPoint> ObjPoints { get; set; }
}
And now the Views ...
this is how the "main view" calls the partial view
<div>
#Html.Partial("routeDetailsView")
</div>
And this is my partial view
#model webVesselTracker.Models.ObjRoute
#{
ViewBag.Title = "RouteDetailsView";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div>
<table id="routeTable" class="table">
<tr>
<th>
Name
</th>
<th>
Latitude
</th>
<th>
Longitude
</th>
<th></th>
</tr>
#if (Model != null) {
foreach (var item in Model.ObjPoints)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Latitude)
</td>
<td>
#Html.DisplayFor(modelItem => item.Longitude)
</td>
</tr>
}
}
else
{
<tr>
<td>
No object has been selected, please select one
</td>
</tr>
}
</table>
</div>
Now I know I could probably do this by adding some sort of json request in the js file and from there on build the table, but I would like to know how to do this with Razor and where I have gone wrong in the code/logic.
Am I supposed to add some ajax elsewhere?
So to summarize this:
-User sees points.
-User clicks point to see the route it made.
-App draws the route and then sends the route information to a method table so it can be added to the table
the user can see that information
Thank you for your time and if I missed something please point it out so I can fix or explain it better.
I finally gave up and looked into knockout.js, it managed to solve all the issues I was having
knockout.js

Redirect action with parameters in JQuery

In my ASP.Net project I'm trying to redirect a page to other action after select a row table and click on a button. So I have this code:
JQuery:
function editItem(tableId, url) {
if ($("#" + tableId + " .selected").exists()) {
var thisRowId = $("#" + tableId + " .selected").attr("id");
window.location.replace(url, { operation: "edit", carId: thisRowId });
}
};
//more code
View (ManagementCar):
#model myProject.Model.Car.Car[]
<table class="table" id="tableCars">
<thead>
#*some code to header*#
</thead>
<tbody>
foreach (var item in Model)
{
<tr id="#(item.Id)" onclick="selectRow('tableCars', '#(item.Id)')">
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.OwnerName)
</td>
<td>
#(item.IsSold == true ? "Yes" : "No")
</td>
</tr>
}
</tbody>
</table>
<br />
<button id="btEdit" type="button" class="disable" onclick="editItem('tableCars','CarOperation')">Edit</button>
Controller:
[HttpGet]
public ActionResult CarOperation(string operation, int carId)
{
//some code...
return RedirectToAction("ManagementCar", "Backoffice");
}
But I have a Server Error after redirect saying carId parameter is null. I debug my jquery and that parameter isn't null. I tried also doing
$.get(url, { operation: "edit", carId: thisRowId });
instead
window.location.replace(url, { operation: "edit", carId: thisRowId });
but it don't redirect.
How can I solve this?
set it by giving it a new value like this.
window.location = window.location.replace(url, "shouldBeAstringNotAJsonObject");
The problem with using window.location is that the referrer is not passed on the request as this behaviour simply mimics a new request as if you had typed the URL into the address bar. If you intend to use website analytics, a reliable referrer will be quite important. I use jQuery to generate a dynamic link upon which I call click().
var url = '/my/url';
$('')[0].click();
Notice I click() the underlying element not the jQuery selected object, the reason being that a jQuery click only raises the event and the href is not navigated to whereas indexing to the element and clicking that will cause the same behaviour you would expect as if you had actually clicked a link on the page.
I have put together a jQuery.navigate plugin that neatly wraps this up and abstracts your site map away from your UI logic, which you might find useful. For example, using my plugin would mean you could remove your editItem function altogether and simply change your markup to something like this?
<tr id="#(item.Id)" onclick="$.navigate('to', 'edit', { id : '#(item.Id)' })">
Ok, I finally solved the problem with a new url routing config and the following code:
My RouteConfig:
routes.MapRoute(
name: "ManipulatingCar",
url: "{controller}/{action}/{operation}/{carId}"
);
My JQuery:
editItem = function (tableId, url) {
if ($("#" + tableId + " .selected").exists()) {
var thisRowId = $("#" + tableId + " .selected").attr("id");
var fullUrl = url + "/edit/" + thisRowId;
window.location = fullUrl;
}
};
Basically, controller action parameters must match with the configurations specified in RouteConfig.cs

Durandal. Pass additional data to other view

I've got a view that needs to be populated conditionally.
Scenario:
A manager will select a users name on screen B, then will be navigated to the same form the user filled in EG. screen A, except that the said manager will have the option to approve or deny the request of the user.
I've seen that in my VM on screen A I can do the following.
var vm = {
activate: function (data) {
console.log(data);
var id = data.id || -1;
if (id !== -1) {
router.isNavigating(true);
http.json('/api/user/'+ id )
.done(function (response) {
ko.viewmodel.updateFromModel(vm.userInfo, response);
router.isNavigating(false);
});
}
}
};
And then B (view & view model)
view
<table>
<thead>
<tr>
<td>User</td>
<td>Date Requested</td>
<td>Action</td>
</tr>
</thead>
<tbody>
<tr>
<td>Mike</td>
<td>19 Jun 2013
</td>
<td>
<input type="button" value="Go" data-bind="click: function() { buttons.goTo(6) }" />
</td>
</tr>
</tbody>
</table>
viewmodel
define(['durandal/plugins/router'], function (router) {
var buttons = {
goTo: function (id) {
console.log('goTo clicked');
//this does work in conjunction with my code on B
router.navigateTo('#/userinfo?id=' + id);
}
};
var vm = {
buttons: buttons
};
return vm;
});
My issue is that I'm not sure what the best way/or how to for that matter to get Durandal to navigate to page A from B... Is what I'm doing right? As it feels a little bit "hacky"
The navigation, at least to me, is designed to mimic standard MVC web navigation. In this case, since you already know that you want to go to 6, why not use an anchor like so
<a href="#/userinfo?id=6"/>
A better way would be to register your route with an id splat like so your route would become
routes.map({route: 'userinfo/:id, ...
<a href="#/userinfo/6" />
This way you can access the splat on the activate method..there are several examples out there but I don't have links to them. Basically the activate method of your userinfo viewmodel will accept a parameter and from there you can load an entity or whatever you like. Hope this helps.
Brad

Categories

Resources