Rails - Access AJAX Triggering Element in Callback - ruby-on-rails

I have a view, say show.js.erb. And I have a link in another view such that
link_to "MyLink", my_object_path, :remote => true
successfully returns the show.js.erb view. My question is, from within that view, is there any way to access the element that triggered the AJAX call without having to resort to generating an id specific to individual elements a la ...
I want to be able to use this view callback to open a small dialog next to whatever element was clicked on, but I can't seem to find a way to access the triggering element.
I tried using $(this) but that doesn't work.
I'd like to do something along the lines of
$(this).after("some new html here");

My solution was to bind a pre-submit class to the element, in my case a popup modal window. It's a similar solution to the post linked to above in that it uses the pre-submit bindings, but tailored to use classes instead.
In public/javascripts/application.rb:
jQuery(function($) {
$(".poppable").bind("ajax:loading", function() { $(this).addClass("popped"); });
});
Then in my view for the popup content (e.g. app/views/mymodel/popup.js.erb):
var p = $(".poppable.popped");
p.removeClass("popped");
/* Do what I need to with p ... */
If this doesn't look kosher, I'm all ears but it works for now.

Related

What would be the correct return type in MVC when no page refresh required

My web page uses Jquery to overload a screen. In this overlay, the user can type some detail and click the submit button.
What I'd like to do is, when the user clicks on submit, the overlay doesn't disappear (as it would do with a page refresh), but a message appears, such as "all done"
The question I have though, is, what is the correct return type? I've gotten myself into a muddle I'm sure.
I tried to make the return type string, and return the string. Sadly, this redirected me to a page with the string value.
I then thought I would need to return a ContentResult() with return Content(myString). The result was the same as returning a string.
I then tried to return void, and simply in my controller use ViewBag.Status ="All done"; This now takes me an empty page.
How can I make the message show "All done" or "Complete" without losing the state? Am I trying to do the impossible without Ajax or similar?
Yes, you are trying to do the impossible. When a controller action gets hit on a synchronous request (e.g. a form submission) you are always going to get a full-page load. That's exactly what a synchronous request is. In effect, the "refresh" has already happened before your action code even runs; the return type of the action is irrelevant. For partial updates, you need an asynchronous request, which means AJAX.
The typical approach to this would be to load in your overlay and then, submit the form from the overlay via AJAX, return a partial view and target a container with jQuery. You'd typically create some kind of generic wrapper for your overlays that will do this for all form posts within any overlay.
Alternatively, you could look at returning JSON and using a JavaScript templating engine like Handlebars to populate the view.
Either way it's a good idea to look at wrapping all of this up in some "generic" JavaScript code that will do the same thing for form posts in all of your overlays; then you can stop worrying about the client-side code and focus on just returning the right thing from your controller actions.
If you want to do that WITHOUT ajax, you will need to return the whole underlaying page again, including the popup in a visible state.
What you (probably) SHOULD do is to use ajax and return a json result. Something like this jQuery solution:
$(document).on('click', '[type="submit"]', function(){
var $form = $(this).closest('form');
$.ajax({
url: $form.action,
type: 'post',
data: $form.serialize(),
success: function(response){
// write success message to user
}
});
});

ASP MVC + AJAX, trying to Update a div asynchronously

I'm new to Asp MVC, and I'm trying to accomplish a little async update (I'm using MVC3 RC2, with Razor, but I can manage with ASPX solutions too).
I have a Master page, which renders a shopping cart box on every page by calling Html.RenderAction("Cart","Shop"). The Cart action of the ShopController calls the database, etc, and outputs the results. This works.
First problem: if I put an ActionLink in this partial view (like Html.ActionLink("Remove")), then even if I call PartialView() from the Remove action, it renders only the shopping cart, and nothing else (in essence, my page disappears).
Second problem: There is a div called "cartContent" inside this partial view. I want to be able to put a link ANYWHERE (not just on the Master page or in the partial view), which when pressed calls a controller Action, and then updates ONLY the cartContent div based on the results. I've tried Ajax.ActionLink but it does the same as Html.ActionLink, even though I imported the Microsoft.MvcAjax js libs.
Also, if I solve the first problem, I want that to be async as well.
What solution do I use? I've tried setting UpdateTargetID to "cartContent", I've tried wrapping the cartContent into an Ajax.BeginForm, nothing. Do I HAVE to use jQuery (which I know nothing of)? Do I serialize some response to JSON, and update the div manually in Javascript? (I'm not really good at JS, I'm coming from the C# side of things)
You put a link wherever you want:
#Html.ActionLink("remove item", "remove", "somecontroller",
new { id = Model.Id }, new { #class = "remove" })
And then in a separate javascript file:
$(function() {
$('.remove').click(function() {
// when the link is clicked
// perform an ajax request:
$.ajax({
url: this.href,
type: 'delete',
success: function(result) {
// when the AJAX call succeed do something with the result
// for example if the controller action returned a partial
// then you could show this partial in some div
$('#someDivId').html(result);
}
});
// don't forget to cancel the default action by returning false
return false;
});
});
Remark: if the div you are updating contains also the link then you might need to use the .live() function or the click event handler will not work the second time because the DOM will be modified:
$('.remove').live('click', function() {
...
});

View Master Page and PostBack

I have a dropdown list on my master page that needs to postback after being changed. After the postback, whatever page initiated the postback needs to be re-displayed.
My question is where do I handle this? Obviously I do not want to have to modify every Action in my project... My guess is to maybe postback to some other fixed action and have that action redirect back to the page that is the referrer. Am I correct? Any thoughts?
Thanks.
Jason
In Site.Master, I ended up wrapping the dropdown within its own form that posted back to a dedicated controller/action.
<% Using Html.BeginForm("ChangeRole", "Home")%>
<div id="roleSelector">Change Role: <%=Html.DropDownList("Role", DirectCast(ViewData.Item("Roles"), SelectList), New With {.onchange = "this.form.submit();"})%></div>
<% End Using%>
In the controller I used the following code to change the mode and then redirected back to the referring URL.
<AcceptVerbs(HttpVerbs.Post)> _
Public Function ChangeRole() As ActionResult
Me.CurrentUser.SetRole(DirectCast([Enum].Parse(GetType(Models.ApplicationRoles), Me.Request.Item("Role")), Models.ApplicationRoles))
Return Redirect(Request.UrlReferrer.ToString())
End Function
I am unsure if this is the recommended way but I have been unable to think of another solution.
When you post back from the dropdown list change what are you doing? Can you maybe handle this in a jQuery call thus eliminating the need to re-display the page at all?
Calls to Action Methods can be asynchronous as griegs says, as such, you can post whatever information you need from the radio buttons to an action method without needing to reload the page.
If you need to update a part of the page, you can replace it with the contents of a rendered action method. If you use the jQuery ajax methods, you can post specific information to your methods.
For example, something like this:
$(document).ready(function()
{
$("#myRadioButton").change(function()
{
//Post to your action method, with the value of the radio button, function to call on success
$.post('yourActionMethodUrl', $(this).val(), function()
{
//Update some part of the page
});
});
});
This is based on memory, so you may need to check the syntax.

ASP.NET MVC radiobutton not working in the parent view to call partial view

I have two strongly Typed partial views (Developers list and Testers list) and the respective views are Developers.ascx and Testers.ascx
Now I want to load one partial view based on the radiobutton selected.
The below code is not working on radio button change.
Code Snippet:
$('input:radio[name=Type]').change(function() {
var url = '/Home/Developers';
if ($(this).val() === '2') {
url = '/Home/Testers';
}
$("#result").load(url);
});
I tried $("input[name=Type]").click(function()
But din't work.
I would appreciate if anyone can provide any clue why the partial view is not loading on change event. or some guidelines.
Thanks
Rita
You can try to add a line with
if ($(this).val() === '2') {
alert('hello');
just to make sure that your code actually runs at all.
You can also call a function in the onChange()-event of the html element, instead of triggering it via $('input:radio[name=Type]').change.
Do you need to compare with three equal signs? Are you certain that the value will be '2' and not 2?
As long as the document is fully loaded and, as Marwan states above, your url:s actually point to action methods that do anything, it should work.
btw: shouldn't this be tagged with jquery or something else than just mvc?

ASP.NET MVC Ajax: How to update an Ajax.ActionLink itself on-click

I have a page that displays a list with a of elements with a large number of elements, each of which has a boolean property, representing an Enabled and a Disabled state.
I need to provide the user with a link for each list item, and the link text must show the opposite status (so if the item is enabled, the link text must display 'Disable').
When the user clicks the link for a Disabled, the corresponding link text for the item must change to 'Enable' (and vice versa).
I would like to NOT reload the entire list for each click, just the text of the ActionLink itself, so my question is:
Is it possible to update just an ActionLink itself when the user clicks the link, or do I have do handle this using custom javascript?
As far as I remember, you can add HTML attributes to the "a" tag by newing up an anonymous class as the last param on most overloads.
Off the top of my head this can be written like the following:
Html.ActionLink("Name", "Action", "Controller", new { #class = 'updateId' });
(You may be able to do this with an ID which would be preferable over a class - if not just use a unique class name to avoid updating multiple items.)
Then you can use javascript to access the class "updateId" and change the inner html.
In the case of jQuery:
$("a.updateId").html("NewName");
This can be done with a custom user control contained within the element to update. A writeup of the solution can be found here. No custom client-side scripting is necessary.

Resources