ActionLink with ajax enabled get's invoked as a normal GET - c#

I have a page, that should update a "process" kinda window when an action is aplied. Kinda like a visible log. Click "start upload" and the div tag underneath will be updated with information.
The problem is, that when i click the "start upload" link it just jumps to that page and don't do a ajax call and update the div.
Controller
public ActionResult ProcessWindow(decimal id)
{
IMG_SETTINGS_FOLDERS img_settings_folders = db.IMG_SETTINGS_FOLDERS.
Single(i => i.SETTINGS_FOLDER_ID == id);
return PartialView("ProcessWindow", img_settings_folders);
}
View
#Ajax.ActionLink("Start upload", "ProcessWindow",
new { id = Model.SETTINGS_FOLDER_ID },
new AjaxOptions { UpdateTargetId = "processWindowssssss" })
<div id="processWindowssssss"></div>

Solved...
When you use unobtrusive ajax, you need to include "jquery.unobtrusive-ajax.min.js"...
If people who write toturials were to read this, please extend your "js" include info to contain this information too.
Answer found from Brad Wilson on Unobtrusive Ajax. http://bradwilson.typepad.com/blog/2010/10/mvc3-unobtrusive-ajax.html
\T

Related

Partial view call, call Index before if not opened

i have a website like this simple image
Everything in the redbox is the Index page with a default layout, the blue shows my partial view.
I have a mvc controller for emails, via a ajax actionlink i change the partial view. So you don't have to reload the complete page if you want to switch the folder.
Everything works fine if you go the follow way:
-Click on Email in the Navbar and you comes to the Index page from Email which opens a automatic the Inbox Partial view.
This is my code in the Html to call the Inbox Partial:
<div id="emailBody">
#Html.Action("EmailPartial", new { module = "1", id = "1,2" })
</div>
The Partial Controller has the follow code:
public PartialViewResult EmailPartial(string module, string id = "1,2", int start = 0, int anzahl = 100)
{
if (module == "1")
{
List<Emailstatus> emailStati;
List<int> TagIds = id.Split(',').Select(int.Parse).ToList();
emailStati = Emailstatus.AllList().Where(x => x.Id.In(TagIds)).ToList();
List<Emailgesendetview> emails = Emailgesendetview.AllListByBenutzerIdAndEmailStatus(benutzerId, emailStati, start, anzahl);
if (id == "1,2")
ViewBag.position = 1;
else if (id == "1")
ViewBag.position = 2;
else
ViewBag.position = Int32.Parse(id);
return PartialView("EmailGesendet", emails);
}
}
A click on the middle-right navigation bar triggers the follow code:
<li id="menu2">
#Ajax.RawActionLink(string.Format("<i class='fa fa-circle'></i> Unread"),
"EmailPartial",
"Email",
new { id = "1", module = "1", start = 0, anzahl = 100 },
new AjaxOptions()
{
HttpMethod = "GET",
AllowCache = false,
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "emailBody"
},
new { #class = "class"})
</li>
Everything works fine.
Now i want to add some submenu items to the navbar on the left but i have no idea ( okay i have a bad one... ) how to call the index page before i call the Partialview.
Okay let me explain a litte bit more my problem...
If the user is one the Email page i could easy use the same code but if the user is on a different page (maybe support or something else) and he clicks now on the Outbox link. Now i should call the Index Email page with the outbox partial view.
So i see 2 little problems,
Before i call the Email index page, i must check on which page i am actually because i dont want to reload the complete page if i am at the Email index page with another partial view. At this moment i only want to reload the partial view with a new model. (That step is easy).
My idea to check on which page i am, is to set a "pagestatus" in my viewbag. Is there a better option?
So now if i am on a other page then Email, i cant call the partial view because i have to call the Email Index page before.
My (i think it is a bad idea) is to create different Email index pages (Index1, Index2, Index3). These Pages could have different partial view call like this:
Index1:
<div id="emailBody">
#Html.Action("EmailPartial", new { module = "1", id = "1,2" })
</div>
Index2:
<div id="emailBody">
#Html.Action("EmailPartial", new { module = "2", id = "1" })
</div>
Index3:
<div id="emailBody">
#Html.Action("EmailPartial", new { module = "3", id = "1" })
</div>
So my solution is:
Check on which page i am and if i am on a different Controller, call the Index which i need.
I think that is not a "clear" solution.
Has anyone a better solution? Creating pages for different partialview calls does not sound good...
Thank you

Ajax.BeginForm that can redirect to a new page without submit

I have something like this:
#using (Ajax.BeginForm("Validate", "Basket", new AjaxOptions
{
UpdateTargetId = "panelId",
HttpMethod = "Post",
InsertionMode = InsertionMode.Replace,
OnSuccess = "SuccessMethod"
}))
{
#if(Model != null)
{
my action...
}
else
{
Response.Redirect(Url.Action("Index", "Home"))
}
}
It works perfect when I use submit button, because partial is refreshing, and layout stay the same.
I have a problem, when my Model became null, because user make a remove action on my page. Then I want to make redirect to my home page (different layout), but when I do that (like in my code), I get two layounts on my page, because of InsertionMode.Replace mode.
How can I omit the Ajax.BeginForm in my view?
Because you're using an ajax form (Ajax.BeginForm) the framework overwrites just the form, giving you the two layouts when you redirect from within the ajax form (as only the html within the form is redirected, the rest of the page outside the form is not redirected).
You can get around this with some javascript/jquery:
First, remove the Response.Redirect
This can be replaced by a placeholder div to indicate no results, or the code can check if there were no results - without more code, it can't be determined if/how this would be done in your specific case, so in the general case, add a placeholder, eg:
#if (Model == null)
{
<div class='nomodel'></div>
}
Second, update the OnSuccess code inside SuccessMethod() to check if there's no model (or check if there are no order rows), then redirect the entire page, eg:
if ($(".nomodel").length > 0) {
location.href = '#Url.Action("Index", "Home"))'
}

MVC4 WebGrid and Ajax Pagination

I have a simple question (may not be a simple answer!) with the WebGrid in MVC4.
I have a functional Grid like so
<div id="Submitted">
#Html.Grid(
Model.Submitted, displayHeader: false, fieldNamePrefix: "Submitted_", ajaxUpdateContainerId: "Submitted",
columns: new WebGridColumn[]{
new WebGridColumn(){ ColumnName = "Date",Header = "Date",Style = "",CanSort = false,Format = x => x.Date.ToString(Globals.Default.DATEFORMAT) },
new WebGridColumn(){ ColumnName = "ID",Header = "Review",Style = "", CanSort = false, Format = x=>#Html.ActionLink("Review","Review","Company",new{ID = x.ID },new{}) }
})
</div>
When reloading the "Submitted" div with Ajax when the next page button is clicked, it generates the next page fine - but it's going to the original action on the controller, which should be a full page.
How does it filter out everything other than the grid itself? with some clever C# code or jQuery?
EDIT:
To clarify, I'm not asking how to do the paging better, or myself, as far as I'm concerned the default paging with the webgrid is working perfectly as it should - I'm asking how the WebGrid does it's ajax paging when posting back to an action which is returning a FULL page.
It does this using jquery load() and functionality that allows it to select just the relevant incoming nodes. This is taken from http://msdn.microsoft.com/en-us/magazine/hh288075.aspx
To allow the script to be applied just to a WebGrid, it uses jQuery selectors to identify elements with the ajaxGrid class set. The script establishes click handlers for the sorting and paging links (identified via the table header or footer inside the grid container) using the jQuery live method (api.jquery.com/live). This sets up the event handler for existing and future elements that match the selector, which is handy given the script will be replacing the content.
You should put your grid in a partialview and update it by Ajax. In controller you should find the request's type. If it is a ajax request(by Request.IsAjaxRequest() ) you must return the partialview, otherwise you must return the original view.
If you are using ajax.beginform you must do something like this:
#using (Ajax.BeginForm("Index", new AjaxOptions { OnFailure = "searchFailed", HttpMethod = "POST", UpdateTargetId = "Submitted" }))
{
...
}
<div id="Submitted">
#Html.Partial("_partialviewname", Model)
</div>
rn
and in controller:
public ActionResult Index(int? page)
{
...
if (Request.IsAjaxRequest())
{
return PartialView("_partialviewname", db.model)
}
return View(db.model)
}

The best approach to send data to a Partial View Model and .html() being slow

Imagine I have a Partial View with a list of users ( loop ) where each user is another partial view with details about one.
foreach (var user in Model.Users)
{
<a href="#" onclick="JavascriptFunction(user.Id);">Details<a>
}
When I click the above Details link for one of the list items a popup (JQuery modal dialog() ) pops up with details about that selected user. Or at least that's the goal. I need to get the selected user details to a new popup that opened.
So now I need to populate the model behind the partial view that the popup will contain with user details before .dialog('Open') triggers.
Question: What's the best way, from within a Javascript function ( onclick JavascriptFunction function in the example above) to call an ActionMethod and populate the Partial View model before the dialog is displayed ?
Right now I'm doing it the following way but for whatever reason I'm getting major delays in data being rendered on the page. I see blank div for good 5-10 seconds before .html() finally displays data:
On the main list page:
<div id="userPopup"></div>
Javascript that suppose to load Partial view with User details from an ActionMethod:
$.post('#Url.Action("Details","User")', { id: userId},
function (data) {
$("#userPopup").html(data);
});
Possibly there is a way to pre-load a partial view on the page and then just load my data into its Model without re-writing the entire PartialView ?
That would be the ideal scenario but I don't think there is a way to do it, is there ?
Thank you in advance ! Don't hesitate to ask questions if anything sounds confusing.
I dont think you should preload all the user details on the main page, what if you have 1000+ users and the visitor is not clikcking the details link ! I would do it in this way. Whenever user clicks on the link, make a call to an action method which returns the data.
So in your main view,
#foreach(var user in Model.Users)
{
#Html.ActionLink(user.Name, "Details", "User",
new { Id = user.ID, }, new { #class ="popupLink" })
}
<script type="text/javascript">
$(function(){
$(".popupLink").click(function (e) {
e.preventDefault();
var url = this.href;
var dialog = $("#dialog");
if ($("#dialog").length == 0) {
dialog = $('<div id="dialog" style="display:hidden"></div>').appendTo('body');
}
dialog.load(
url,
{}, // omit this param object to issue a GET request instead a POST request, otherwise you may provide post parameters within the object
function (responseText, textStatus, XMLHttpRequest) {
dialog.dialog({
close: function (event, ui) {
dialog.remove();
},
modal: true,
width: 460
});
}
);
});
});
</script>
In User controller, have an action method called "Details which accepts the Id as parameter and return the View of User details
public ActionResult Details(int id)
{
var usre=repositary.GetUser(id);
return View(user);
}
Have your HTML markup for details in the DetailsView.
This code use jQuery UI model dialog. So you need to include that.

MVC 3 - How do you return a Display Template from an action method?

I have a view that displays a list of comments. It does this via the DisplayTemplate. All I have to do is something like #Html.DisplayFor(x => x.BlogPost.PostComments) and all the comments render appropriately.
There is a form at the bottom of the page to add a new comment. This page utilizes progressive enhancement. So if javascript is disabled then the form submits like normal, adds the comment to the database, then redirects to the action that renders the blog post. However, if javascript is available then jQuery hijacks the form's submit and makes the post via ajax. Well because the comment markup is in a display template, I don't know how to return it from the action method so that jQuery can drop it on the page.
I know how to do this with partial views. I would just have the action method return the right partial view and jquery would append the response to the comment container on the page.
Before I go chopping out my display template in favor of a partial view, is there a straight forward way that I'm missing to send back a display template from the controller?
Here is my action method:
public ActionResult AddComment(PostComment postComment)
{
postComment.PostedDate = DateTime.Now;
postCommentRepo.AddPostComment(postComment);
postCommentRepo.SaveChanges();
if (Request.IsAjaxRequest())
return ???????
else
return RedirectToAction("BlogPost", new { Id = postComment.BlogPostID });
}
When the page loads it doesn't need to worry about it because it uses the templates in the standard way:
<div class="comments">
#Html.DisplayFor(x => x.BlogPost.BlogPostComments)
</div>
I just want to know how I might send a single comment that utilizes the display template back to jQuery.
You may try returning the partial HTML representing the newly posted comment:
if (Request.IsAjaxRequest())
{
return PartialView(
"~/Views/Shared/DisplayTemplates/Comment.cshtml",
postComment
);
}
and on the client side append this comment to the comments container:
$.post('#Url.Action("AddComment")', { ... }, function (result) {
$('#comments').append(result);
// or $('#comments').prepend(result); if you want it to appear on top
});
Does this question give you what you are looking for? Seems to indicate that you can call a HTML helper from an action.
Create a partial view /Shared/DisplayTemplate.cshtml with the following razor code:
#Html.DisplayFor(m => Model)
Then in your controller (or preferably in a base controller class) add a method along these lines:
protected PartialViewResult PartialViewFor(object model)
{
return PartialView("DisplayTemplate",model);
}
In the OP's case then:
public ActionResult AddComment(PostComment postComment)
{
postComment.PostedDate = DateTime.Now;
postCommentRepo.AddPostComment(postComment);
postCommentRepo.SaveChanges();
if (Request.IsAjaxRequest())
return PartialViewFor(postComment);
else
return RedirectToAction("BlogPost", new { Id = postComment.BlogPostID });
}

Categories