How to put span element inside ActionLink MVC3?

How can I put a span element inside ActionLink BUT NOT WITH URL.ACTION?

This:

 <li><span>
     @Ajax.ActionLink("LinkText", "ControllerName", new AjaxOptions
                 {
                     UpdateTargetId = "div",
                     InsertionMode = InsertionMode.Replace,
                     HttpMethod = "GET",
                     LoadingElementId = "progress"

                 })
 </span></li>

generates this:

<li>
<span>
<a href="/Home/ControllerName" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" data-ajax-update="#scroll" 
 data-ajax-mode="replace" data-ajax-method="GET" 
 data-ajax-loading="#progress" data-ajax="true">LinkText</a>
</span>
</li>

But I need something else. How can I create a custom MVC3 ActionLink method that generates this output:

<li>
    <a href="/Home/ControllerName" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" data-ajax-update="#scroll" 
     data-ajax-mode="replace" data-ajax-method="GET" 
     data-ajax-loading="#progress" data-ajax="true">

     <span>LinkText</span> // this span generated inside <a>

    </a>
</li>

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

How to put span element inside ActionLink BUT NOT WITH URL.ACTION

Simple answer: you can’t. The ActionLink method HTML encodes the link text and there’s not much you could do about it (you could open a ticket at Microsoft so that they provide an overload that allows you to do this in ASP.NET MVC vNext).

At the moment you could write a custom html helper that won’t encode:

public static class AjaxExtensions
{
    public static IHtmlString MyActionLink(
        this AjaxHelper ajaxHelper,
        string linkText,
        string actionName,
        AjaxOptions ajaxOptions
    )
    {
        var targetUrl = UrlHelper.GenerateUrl(null, actionName, null, null, ajaxHelper.RouteCollection, ajaxHelper.ViewContext.RequestContext, true);
        return MvcHtmlString.Create(ajaxHelper.GenerateLink(linkText, targetUrl, ajaxOptions ?? new AjaxOptions(), null));
    }

    private static string GenerateLink(
        this AjaxHelper ajaxHelper, 
        string linkText, 
        string targetUrl, 
        AjaxOptions ajaxOptions, 
        IDictionary<string, object> htmlAttributes
    )
    {
        var a = new TagBuilder("a")
        {
            InnerHtml = linkText
        };
        a.MergeAttributes<string, object>(htmlAttributes);
        a.MergeAttribute("href", targetUrl);
        a.MergeAttributes<string, object>(ajaxOptions.ToUnobtrusiveHtmlAttributes());
        return a.ToString(TagRenderMode.Normal);
    }
}

and then:

@Ajax.MyActionLink(
    "<span>LinkText</span>", 
    "ActionName", 
    new AjaxOptions {
        UpdateTargetId = "div",
        InsertionMode = InsertionMode.Replace,
        HttpMethod = "GET",
        LoadingElementId = "progress"
    }
)

Method 2

I know this is old but I use this quick and dirty way for adding styled button links in my grids. You could add overloads to include route names/etc. as well. Hope this helps someone.

public static MvcHtmlString GridAnchor(this HtmlHelper html, string linkText, string actionName, string controllerName, 
            object routeValues, object htmlAttributes)
        {
            var result = new TagBuilder("a");
            var url = UrlHelper.GenerateUrl(null, actionName, controllerName, new RouteValueDictionary(routeValues), html.RouteCollection,
                                            html.ViewContext.RequestContext, true);
            result.Attributes.Add("href", url);
            result.MergeAttributes(new RouteValueDictionary(htmlAttributes));
            result.InnerHtml = "<span>" + linkText + "</span>";

            return MvcHtmlString.Create(result.ToString());
        }

Method 3

I modified Darins answer just a bit to be able to accomodate RouteValues.

    public static class AjaxExtensions
    {
        public static IHtmlString MyActionLink(
            this AjaxHelper ajaxHelper,
            string linkText,
            string actionName,
            AjaxOptions ajaxOptions
        )
        {
            var targetUrl = UrlHelper.GenerateUrl(null, actionName, null, null, ajaxHelper.RouteCollection, ajaxHelper.ViewContext.RequestContext, true);
            return MvcHtmlString.Create(ajaxHelper.GenerateLink(linkText, targetUrl, ajaxOptions ?? new AjaxOptions(), null));
        }

        public static IHtmlString MyActionLink(
            this AjaxHelper ajaxHelper,
            string linkText,
            string actionName,
            object routeValues,
            AjaxOptions ajaxOptions
        )
        {
            System.Web.Routing.RouteValueDictionary routeVals = new System.Web.Routing.RouteValueDictionary(routeValues);

            var targetUrl = UrlHelper.GenerateUrl(null, actionName, null, routeVals, ajaxHelper.RouteCollection, ajaxHelper.ViewContext.RequestContext, true);
            return MvcHtmlString.Create(ajaxHelper.GenerateLink(linkText, targetUrl, ajaxOptions ?? new AjaxOptions(), null));
        }


        private static string GenerateLink(
            this AjaxHelper ajaxHelper,
            string linkText,
            string targetUrl,
            AjaxOptions ajaxOptions,
            IDictionary htmlAttributes
        )
        {
            var a = new TagBuilder("a")
            {
                InnerHtml = linkText
            };
            a.MergeAttributes(htmlAttributes);
            a.MergeAttribute("href", targetUrl);
            a.MergeAttributes(ajaxOptions.ToUnobtrusiveHtmlAttributes());
            return a.ToString(TagRenderMode.Normal);
        }

    }

Method 4

I know this is an old thread, but you can also do something inline along the lines of:

<li><span>
@{
    var lnk = Ajax.ActionLink("LinkText", "ControllerName", new AjaxOptions {
                 UpdateTargetId = "div",
                 InsertionMode = InsertionMode.Replace,
                 HttpMethod = "GET",
                 LoadingElementId = "progress"
             });
@Html.Raw(lnk.ToString().Replace(">LinkText<", "><span>LinkText</span><")); 
// Remember to include the open and closing >< !
}
</span></li>

Its a hack I know, but you could easily write an extension along these lines

Method 5

How difficult is it to achieve this by using JQuery?

We can always use JQuery and append the <span></span> once the DOM is loaded.

May be not the perfect solution but for developers using jquery and dont want to write html helpers classes as above answer this might be the work around.

Method 6

I modified markdotnet’s answer using Jetbrain’s Annotation package to provide intellisense on the actionName parameter. I Also changed the linkText parameter to improve code visualizing; VS will treat it as HTML code, instead of just a simple string.

Example:

@Ajax.MyActionLink(
@<div>
    <span>Click me</span>
</div>,
"MyAction",
new { Id = 1 },
new AjaxOptions
{
    UpdateTargetId = "targed-id",
    OnComplete = "oncomplete();"
})

Extension class:

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
using System.Web.WebPages;
using JetBrains.Annotations;

public static class AjaxExtensions
{
    public static IHtmlString MyActionLink(
        this AjaxHelper ajaxHelper,
        Func<dynamic, HelperResult> linkHtml,
        [AspMvcAction] string actionName,
        AjaxOptions ajaxOptions
    )
    {
        var targetUrl = UrlHelper.GenerateUrl(null, actionName, null, null, ajaxHelper.RouteCollection, ajaxHelper.ViewContext.RequestContext, true);
        return MvcHtmlString.Create(ajaxHelper.GenerateLink(linkHtml, targetUrl, ajaxOptions ?? new AjaxOptions(), null));
    }

    public static IHtmlString MyActionLink(
        this AjaxHelper ajaxHelper,
        Func<dynamic, HelperResult> linkHtml,
        [AspMvcAction] string actionName,
        object routeValues,
        AjaxOptions ajaxOptions
    )
    {
        System.Web.Routing.RouteValueDictionary routeVals = new System.Web.Routing.RouteValueDictionary(routeValues);

        var targetUrl = UrlHelper.GenerateUrl(null, actionName, null, routeVals, ajaxHelper.RouteCollection, ajaxHelper.ViewContext.RequestContext, true);
        return MvcHtmlString.Create(ajaxHelper.GenerateLink(linkHtml, targetUrl, ajaxOptions ?? new AjaxOptions(), null));
    }


    private static string GenerateLink(
        this AjaxHelper ajaxHelper,
        Func<dynamic, HelperResult> linkHtml,
        string targetUrl,
        AjaxOptions ajaxOptions,
        IDictionary<string, object> htmlAttributes
    )
    {
        var a = new TagBuilder("a")
        {
            InnerHtml = linkHtml(null).ToString()
        };
        a.MergeAttributes(htmlAttributes);
        a.MergeAttribute("href", targetUrl);
        a.MergeAttributes(ajaxOptions.ToUnobtrusiveHtmlAttributes());
        return a.ToString(TagRenderMode.Normal);
    }

}


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x