Question

Let's say I have a list of users:

User/Index.cshtml

@model IEnumerable<MvcHoist.Models.UserProfileViewModel>

<table>
    @foreach (var user in Model)
    {
        @Html.Partial("_User", user)
    }
</table>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

...and (using a partial) next to each user is a "Follow" or "Unfollow" link, as appropriate:

_User.cshtml partial

@model MvcHoist.Models.UserProfileViewModel
<tr>
    <td>
        @if (Model.IsFollowed)
        {
            @Ajax.ActionLink("Unfollow", "Unfollow", new { id = Model.UserProfile.UserId }, new AjaxOptions
               {
                   HttpMethod = "POST"
               })
        }
        else
        {
            @Ajax.ActionLink("Follow", "Follow", new { id = Model.UserProfile.UserId }, new AjaxOptions
               {
                   HttpMethod = "POST"
               })
        }
    </td>
</tr>

How can I replace the "Follow" Ajax.ActionLink with an "Unfollow" Ajax.ActionLink after the Follow action has completed successfully? Using a single Ajax.ActionLink by changing the linkText and actionName would be fine, too.

Can this be done purely with Ajax.ActionLink (without diving too deeply into jQuery)? Animating the change would be even better.

Was it helpful?

Solution

Instead of the @if (...) condition, render both links, but render the second link with a style of "display:none;".

The style attributes might look something like this:

..., new { style="display:@(Model.IsFollowed ? "block" : "none")" }, ...
..., new { style="display:@(Model.IsFollowed ? "none" : "block")" }, ...

Add an OnComplete handler or a little bit of jQuery (or alternative) to toggle both links upon success.

For the animation, you could use the jQuery fadeIn() and fadeOut() functions.

OTHER TIPS

While I would have liked a pure Ajax.ActionLink solution (if possible), @SimonGoldstone's more jQuery-based approach (similar to this answer) gets the job done. Here's how it turned out:

User/Index.cshtml

@model IEnumerable<MvcHoist.Models.UserProfileViewModel>

<table>
    @foreach (var user in Model)
    {
        @Html.Partial("_User", user)
    }
</table>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")

    <script>
        var toggleFollowUnfollowLinks = function (followLink, unfollowLink) {
            // based on https://stackoverflow.com/a/5545969/103058 and https://stackoverflow.com/a/19689745/103058
            var fout = followLink.is(":visible") ? followLink : unfollowLink;
            var fin = !followLink.is(":visible") ? followLink : unfollowLink;

            fout.fadeOut("fast", function () {
                fin.fadeIn();
            });
        };
    </script>
}

_User.cshtml partial

@model MvcHoist.Models.UserProfileViewModel

@{
    var unfollowLinkId = Guid.NewGuid().ToString();
    var followLinkId = Guid.NewGuid().ToString();
    var onSuccess = String.Format("toggleFollowUnfollowLinks($('#{0}'), $('#{1}'))", followLinkId, unfollowLinkId);
}

<tr>
    <td>
        @Ajax.ActionLink("Unfollow", "Unfollow", new { id = Model.UserProfile.UserId }, new AjaxOptions
               {
                   HttpMethod = "POST",
                   OnSuccess = @onSuccess
               }, new { id = @unfollowLinkId, @style = @Model.IsFollowed ? "display:block" : "display:none" })

        @Ajax.ActionLink("Follow", "Follow", new { id = Model.UserProfile.UserId }, new AjaxOptions
               {
                   HttpMethod = "POST",
                   OnSuccess = @onSuccess
               }, new { id = @followLinkId, @style = !@Model.IsFollowed ? "display:block" : "display:none" })
    </td>
</tr>

Generating unique IDs (using Guid.NewGuid()) was necessary to prevent an action on e.g. the third row from affecting the Ajax.ActionLink in the first row.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top