How to make #Ajax.ActionLink not update - ajax

Is there any way to make #Ajax.ActionLink() not update UpdateTargetId?
For example, with something like this:
#Ajax.ActionLink("All", "Get_Books_By_Id", new { ID = 0 },
new AjaxOptions() {
HttpMethod = "GET",
UpdateTargetId = "div_records",
InsertionMode = InsertionMode.Replace,
LoadingElementId = "div_load"
}
)
Get_Books_By_Id is returning PartialView with data for table in PartialView, but I would like to not update UpdateTargetId when data (List) count is 0, for example.
Is there any way to send via control something what would tell ajax not to update? Or is there any other way?

You can do it in two ways:
Remove the update target id and instead use the OnSuccess handler
function onSuccess(result){
var fragment = $(result);
if(fragment.find("tr").length >= 0)
$("div_records").html(fragment)
}
Change your controller to return a different status code from your action
public ActionResult Get_books_by_id()
{
var myBooks = _repostiory.GetBooksById();
if(!myBooks.Any())
return new HttpStatusCodeResult(HttpStatusCode.NotFound);
return PartialView("mybooks", myBooks);
}
I've used both methods before, and obviously you will need to tailor the selects and actions to your use case.

Related

Using AjaxExtensions.RouteLink

To address a particular requirement in ASP.net MC3, I wanted to use AjaxExtensions.RouteLink
But I wonder how to use it in a view.
For example:
#AjaxExtensions.RouteLink(ajaxHelper, link.Text, new { controller="Home",action="List",
category = id },
new AjaxOptions { UpdateTargetId = "itemList",InsertionMode=InsertionMode.Replace },
new { #class = "item" })
But while running it throws me error "The name 'ajaxHelper' does not exist in the current context". Since I am new to this usage,it stops me.Could anyone please share some details of using this one ? Thanks much
Used something like below instead:
#foreach (var link in Model)
{
if (link.SubCat.Count == 0)
{
#Ajax.RouteLink(link.Text, new
{
controller = "Home",
action = "List",
pId = link.Id,
parentCatId=link.ParentCatId
},
new AjaxOptions
{
UpdateTargetId = "itemList", //div name
InsertionMode = InsertionMode.Replace
},
new { #class = "menuitem" }
)
}
The above code is in a PartialView. But now the problem with this is , it doesn't update the result to the Target provided. Instead it replaces the result to the whole page. Hopefully somebody now can give me a clue to get rid of this.

Can a hacker modify any parameters sent as part of an Ajax.ActionLink Call

i have the following Ajax.actionlink inside a view to add an answer under a question:-
#Ajax.ActionLink("Add Answers",
"Create", "Answer",
new { questionid = question.QuestionID},
new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
HttpMethod = "Get",
UpdateTargetId = "removetable"
})
while will call the following action method:-
public ActionResult Create(int questionid)
{
ViewBag.IsRight = new SelectList(repository.FindAllAnswerDescription().ToLis(), "IsRight", "description", 1);
ViewBag.questionid = questionid;
Answer answer = new Answer();
return PartialView("_answer",answer); }
so my question is will a hacker be able to modify the new { questionid = question.QuestionID}, parameter send by the ajax link ? and if yes how i can avoid this.
BR
Edited:-
i am doing the following check using a helper method (IsauthorizedBy) on the post action method to check if the user is authorized to answer a question or not:-
[HttpPost]
public ActionResult Create(int questionid, Answer a)
{
q = repository.findquestion(questionid);
if ((q == null) || (!q.IsauthorizedBy(User.Identity.Name))){
return ("error");}
if (ModelState.IsValid)
{
repository.AddAnswer(a);
repository.Save();
return PartialView("_details",a);
}
return(a);}
so will it handel a hacker who will try to modify the question id and answer a question he is not authorized to answer.
BR
Yes but you want to ensure on the server side they have access to this question by querying their permissions and some database scheme in place ensuring they have access to this. If it's not feasible then you can use
Html.AntiModelInjectionFor from
mvcsecurity.codeplex.com plus
[ValidateAntiModelInjection()]
You never trust anything coming from the client-side. Everything can be altered on the way, either in the scripts or on the network.
Since it's only an id, you need to be careful and do extra checks on the server

How to update underlying ViewModel property when deleting a Photo using an Ajax.ActionLink?

My situation is this:
I have this ViewModel:
public class RealtyViewModel
{
public RealtyViewModel()
{
Realty = new Realty();
Photos = new Collection<File>();
}
public Realty Realty { get; set; }
public Collection<File> Photos { get; set; }
}
I pass this RealtyViewModel to my Edit.cshtml view. Inside the Edit view I call a Photos.cshtml partial view. The Photos partial view also uses the same #model RealtyViewModel.
Now, inside the Photos.cshtml partial view I do an AJAX request to delete a photo:
#Ajax.ImageActionLink
(#Url.Content(Model.Photos[i].Path), #Localization.Delete, "640", "480",
"DeletePhoto", new {realtyId = Model.Realty.Id, photoId = Model.Photos[i].Id},
new AjaxOptions()
{
Confirm = #Localization.DeleteConfirmation,
HttpMethod = HttpVerbs.Post.ToString(),
OnComplete = string.Format("deletePhotoFromPage('{0}')",
Model.Photos[i].Id),
OnSuccess = "LoadCycle",
UpdateTargetId = "myDiv",
InsertionMode = InsertionMode.Replace
}, new {data_photoId = Model.Photos[i].Id})
I run this code:
[HttpDelete]
public ActionResult DeletePhoto(string realtyId, string photoId)
{
Realty realty = DocumentSession.Load<Realty>(realtyId);
realty.Photos.Remove(photoId);
File photo = DocumentSession.Load<File>(photoId);
// Deletes the file in the database
DocumentSession.Advanced.DatabaseCommands.Delete(photoId, null);
// Deletes the file in the disk
System.IO.File.Delete(Server.MapPath(photo.Path));
return new EmptyResult();
}
The problem is: my current realtyViewModel that I passed to the Edit view still references the photos I have deleted using the AJAX calls. Then when I try to save an updated model, it saves everything again holding the old references to the photos I have just deleted.
How can I update my model ( remove the deleted photos from [ model.Realty.Photos ] ) so that it reflects the current state of my Edit view?
Note: now it's working because I'm using the Session object to store the Ids of deleted photos, but it's not the way I think it should be. There must be a beautiful solution to this that just doesn't come to my mind...
A beautiful solution would be: after a success deletion, the Ajax call should return the deleted photo Id so that I could remove it from [ model.Realty.Photos ]. Then, when I tried to save an edited Realty, it would reflect the changes correctly.
After a discussion on chat it seems that you have hidden fields in your DOM that you need to remove:
#for (int i = 0; i < Model.Realty.Photos.Count(); i++)
{
#Html.HiddenFor(
m => m.Realty.Photos[i],
new { data_photoid = Model.Realty.Photos[i] }
)
}
Now you could have your controller action return the id of the photo that has to be deleted using JSON for example instead of an empty result:
[HttpDelete]
public ActionResult DeletePhoto(string realtyId, string photoId)
{
...
return Json(new { photoId = photoId });
}
and on the client:
function deletePhotoFromPage(result) {
...
$(':hidden[data-photoid="' + result.photoId + '"]').remove();
}
and also you should use the OnSuccess option instead of OnComplete in your Ajax link options:
OnSuccess = "deletePhotoFromPage"
instead of:
OnComplete = string.Format("deletePhotoFromPage('{0}')", Model.Photos[i].Id),
OnComplete could be invoked even in case of error.

MVC3 routes - how to separate after the last dash in url?

Given the following routes:
routes.MapRoute(name: "CityHomePage1", url: "{city}-{state}", defaults: new { controller = "Home", action = "GeoHomePage" });
routes.MapRoute(name: "CityHomePage2", url: "{city}-{state}/", defaults: new { controller = "Home", action = "GeoHomePage" });
routes.MapRoute(name: "CityStateResults", url: "{city}-{state}/{searchTerm}", defaults: new { controller = "Results", action = "SearchCityState" });
routes.MapRoute(name: "CityStateCategoryResults", url: "{city}-{state}/{category}/{searchTerm}", defaults: new { controller = "Results", action = "SearchCityStateCategory" });
This works well when the cities do not have dashes ("-") in them, however I am now changing the way multiple cities are displayed in the URL from having an underscore between them, to now having dashes.
So, if the URL reads http://www.site.com/Gardena-Ceretos-Santa_Monica-California/someterm it the routes will no longer work.
How would I grab the state as everything after the last "-" and before the "/" in my routes to extract the state?
Looking at this now, I should have structured the URLS as /city-city-city/state/searchtearm, but for now, I have to stick with the current structure.
Thanks.
This is a situation where routing does not have any tools to assist you. There are two options.
First, change your token to {cityState}, make that the parameter in your action methods, and parse the cityState string in your controller actions.
Second, change your token to {cityState} (I promise, this is a different option), and then use a custom RouteHandler to parse the cityState string, and add city and state route tokens to pass to your existing actions. The RouteHandler would look like so:
using System.Web.Mvc;
using System.Web.Routing;
public class MyRouteHandler : IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
var routeData = requestContext.RouteData;
var cityState = routeData.Values["cityState"].ToString();
var parts = cityState.Split(new string[] { "-" }, StringSplitOptions.RemoveEmptyEntries);
var state = parts.Last();
var citySb = new StringBuilder();
foreach (var part in parts)
{
if (part != state)
{
if (citySb.Length > 0)
citySb.Append("-");
citySb.Append(part);
}
}
routeData.Values.Add("city", citySb.ToString());
routeData.Values.Add("state", state);
var handler = new MvcHandler(requestContext);
return handler;
}
}
Then, change each of your routes to be similar to this:
routes.MapRoute(
"CityHomePage1",
new Route(
"{cityState}",
new RouteValueDictionary(
new { controller = "Home", action = "GeoHomePage" }),
new MyRouteHandler()
)
)
);

ASP.Net MVC Route issue

I have an area called MyArea and it's registered like so:
context.MapRoute(null, "MyArea", new { controller = "MyAreaController", action = "Index" });
//Properties
context.MapRoute(null, "MyArea/properties", new { controller = "Property", action = "Index" });
context.MapRoute(null, "MyArea/properties/edit/{propertyId}", new { controller = "Property", action = "Property" });
//Units
context.MapRoute(null, "MyArea/properties/edit/{propertyId}/units/{unitId}", new { action = "Unit", propertyId = 1, unitId = 1 });
It should work that one property has many units, so I would like my url to look something like this:
http://localhost:50182/myarea/properties/edit/4/units/1
The code i use for the Html.ActionLink looks like:
#Html.ActionLink("Add new Unit", "Unit", "Unit", new { propertyId = 1, unitId = 1 })
I have an Unit controller with an action called Unit. Pleas help, what am i missing?
Thanks!!
You say "I have an Unit controller with an action called Unit. Pleas help, what am i missing?"
and your route mapping is currently ...
context.MapRoute(null, "MyArea/properties/edit/{propertyId}/units/{unitId}", new { action = "Unit", propertyId = 1, unitId = 1 });
How would you expect MVC to know what controller to use for that route? You need to specify controller = "Unit"
Update
Switch the order of
context.MapRoute(null, "MyArea/properties/edit/{propertyId}", new { controller = "Property", action = "Property" });
//Units
context.MapRoute(null, "MyArea/properties/edit/{propertyId}/units/{unitId}", new { action = "Unit", propertyId = 1, unitId = 1 });
in your route registration. Otherwise, something that should map to the second route will be intercepted by the first.

Resources