Inserire HTML all'interno di Html.ActionLink (), oltre a Nessun link di testo?


169

Ho due domande:

  1. Mi chiedo come non posso visualizzare il testo del collegamento quando si utilizza Html.ActionLink()in una vista MVC (in realtà, questo è Site.Master).

Non esiste una versione sovraccarica che non consente il testo del collegamento e quando provo a passare solo uno spazio vuoto string, il compilatore mi dice che ha bisogno di una stringa non vuota.

Come posso risolvere questo problema?

  1. Devo inserire i <span>tag all'interno del tag anchor, ma non funziona Html.ActionLink();. Mi piacerebbe vedere il seguente output:

    Span text

Come posso inserire i tag all'interno del tag anchor in ASP.NET MVC?


Quale sarebbe lo scopo / l'uso di un link di azione vuoto?
David,

1
Sto usando uno sprite di immagini per una barra di navigazione, e quello <li>che stai vedendo è un particolare pulsante di navigazione (con dimensioni, pos sullo sfondo, ecc. Specificato nel foglio di stile CSS). Ma deve essere collegato a qualcosa, quindi non voglio visualizzare il testo. Voglio che lo sprite lo faccia per me.
MegaMatt,

Risposte:


322

Invece di utilizzare Html.ActionLink è possibile eseguire il rendering di un URL tramite Url.Action

<a href="<%= Url.Action("Index", "Home") %>"><span>Text</span></a>
<a href="@Url.Action("Index", "Home")"><span>Text</span></a>

E per fare un URL vuoto potresti avere

<a href="<%= Url.Action("Index", "Home") %>"></a>
<a href="@Url.Action("Index", "Home")"></a>

3
Ho dovuto usare <a href="@Url.Action("Index", "Home")"> <span> Text </span> </a>, il mio sviluppatore non è in giro per chiedere perché dovevo fare questo, ma può essere utile per chiunque cerchi di usare la risposta sopra e scoprire che non ha funzionato.
Dave Haigh,

2
@ Url.Action è quando si utilizza il modello di rasoio. Ho aggiornato la risposta in modo che tu possa vedere entrambi.
David,

<a href=@Url.Action("Create", "Product")><span>Create</span></a>funziona anche. I preventivi non sono richiesti.
David,

1
Per contenuti statici, perché non digitare direttamente l'html? Sembra meno verboso e più semplice
SkeetJon

Non è più un'opzione reale in Asp.Net Core 2 se si desidera utilizzare Ajax.
Zorkind,

17

Un'estensione HtmlHelper personalizzata è un'altra opzione. Nota : ParameterDictionary è il mio tipo. Potresti sostituire un RouteValueDictionary ma dovresti costruirlo in modo diverso.

public static string ActionLinkSpan( this HtmlHelper helper, string linkText, string actionName, string controllerName, object htmlAttributes )
{
    TagBuilder spanBuilder = new TagBuilder( "span" );
    spanBuilder.InnerHtml = linkText;

    return BuildNestedAnchor( spanBuilder.ToString(), string.Format( "/{0}/{1}", controllerName, actionName ), htmlAttributes );
}

private static string BuildNestedAnchor( string innerHtml, string url, object htmlAttributes )
{
    TagBuilder anchorBuilder = new TagBuilder( "a" );
    anchorBuilder.Attributes.Add( "href", url );
    anchorBuilder.MergeAttributes( new ParameterDictionary( htmlAttributes ) );
    anchorBuilder.InnerHtml = innerHtml;

    return anchorBuilder.ToString();
}

14

Ecco una soluzione (bassa e sporca) nel caso in cui sia necessario utilizzare Ajax o alcune funzionalità che non è possibile utilizzare quando si effettua il collegamento manualmente (utilizzando il tag):

<%= Html.ActionLink("LinkTextToken", "ActionName", "ControllerName").ToHtmlString().Replace("LinkTextToken", "Refresh <span class='large sprite refresh'></span>")%>

È possibile utilizzare qualsiasi testo anziché "LinkTextToken", è lì solo per essere sostituito, è importante solo che non si presenti in nessun altro punto all'interno di Actionlink.


6
+1 Bella idea. A Razor, dovrai rappare tutto questo inHtml.Raw()
Carrie Kendall il

Grazie :) Ora che vedo quello che abbiamo usato, quasi mi imbarazzo, fare queste cose sul server è un tale spreco di risorse del server ...
Goran Obradovic,

1
Dato che sto usando @ Ajax.ActionLink e non mi andava di impostare manualmente tutti gli date-attributi, questa è la soluzione migliore per me. +1
asontu,

Grazie, ha funzionato come un incantesimo anche quando usavo Ajax.ActionLink. Non sembrava rallentare nulla e sono riuscito a mantenere lo stesso layout e lo stesso stile.
Blacky Wolf,

Voglio solo dire che questo non funziona in .Net Core, ToHtmlString () è stato rimosso in v2 non sono sicuro di v1
Zorkind

12

Basta usare Url.Actioninvece di Html.ActionLink:

<li id="home_nav"><a href="<%= Url.Action("ActionName") %>"><span>Span text</span></a></li>

@CraigStunz perché dovremmo usare Url.Action invece di Html.ActionLink?
Roxy'Pro,

6

Questo ha sempre funzionato bene per me. Non è disordinato e molto pulito.

<a href="@Url.Action("Index", "Home")"><span>Text</span></a>


Url.Action non ha un costruttore che prenderà htmlAttributes. Non è lo stesso di ActionLink.
barrypicker

2

Ho finito con un metodo di estensione personalizzato. Vale la pena notare che, quando si tenta di posizionare HTML all'interno di un oggetto Anchor, il testo del collegamento può essere a sinistra o a destra dell'HTML interno. Per questo motivo, ho optato per fornire parametri per HTML interno sinistro e destro - il testo del collegamento è nel mezzo. L'HTML interno sinistro e destro sono facoltativi.

Metodo di estensione ActionLinkInnerHtml:

    public static MvcHtmlString ActionLinkInnerHtml(this HtmlHelper helper, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues = null, IDictionary<string, object> htmlAttributes = null, string leftInnerHtml = null, string rightInnerHtml = null)
    {
        // CONSTRUCT THE URL
        var urlHelper = new UrlHelper(helper.ViewContext.RequestContext);
        var url = urlHelper.Action(actionName: actionName, controllerName: controllerName, routeValues: routeValues);

        // CREATE AN ANCHOR TAG BUILDER
        var builder = new TagBuilder("a");
        builder.InnerHtml = string.Format("{0}{1}{2}", leftInnerHtml, linkText, rightInnerHtml);
        builder.MergeAttribute(key: "href", value: url);

        // ADD HTML ATTRIBUTES
        builder.MergeAttributes(htmlAttributes, replaceExisting: true);

        // BUILD THE STRING AND RETURN IT
        var mvcHtmlString = MvcHtmlString.Create(builder.ToString());
        return mvcHtmlString;
    }

Esempio di utilizzo:

Ecco un esempio di utilizzo. Per questo esempio volevo solo l'html interno sul lato destro del testo del link ...

@Html.ActionLinkInnerHtml(
    linkText: "Hello World"
        , actionName: "SomethingOtherThanIndex"
        , controllerName: "SomethingOtherThanHome"
        , rightInnerHtml: "<span class=\"caret\" />"
        )

risultati:

questo si traduce nel seguente HTML ...

<a href="/SomethingOtherThanHome/SomethingOtherThanIndex">Hello World<span class="caret" /></a>

1

Ho pensato che questo potrebbe essere utile quando si utilizza bootstrap e alcuni glypicons:

<a class="btn btn-primary" 
    href="<%: Url.Action("Download File", "Download", 
    new { id = msg.Id, distributorId = msg.DistributorId }) %>">
    Download
    <span class="glyphicon glyphicon-paperclip"></span>
</a>

Questo mostrerà un tag A, con un collegamento a un controller, con una bella icona a graffetta su di esso per rappresentare un collegamento per il download e l'output html viene mantenuto pulito


1

Ecco un'amplia espansione della risposta di @ tvanfosson. Ne sono stato ispirato e ho deciso di renderlo più generico.

    public static MvcHtmlString NestedActionLink(this HtmlHelper htmlHelper, string linkText, string actionName,
        string controllerName, object routeValues = null, object htmlAttributes = null,
        RouteValueDictionary childElements = null)
    {
        var htmlAttributesDictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

        if (childElements != null)
        {
            var urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext);

            var anchorTag = new TagBuilder("a");
            anchorTag.MergeAttribute("href",
                routeValues == null
                    ? urlHelper.Action(actionName, controllerName)
                    : urlHelper.Action(actionName, controllerName, routeValues));
            anchorTag.MergeAttributes(htmlAttributesDictionary);
            TagBuilder childTag = null;

            if (childElements != null)
            {
                foreach (var childElement in childElements)
                {
                    childTag = new TagBuilder(childElement.Key.Split('|')[0]);
                    object elementAttributes;
                    childElements.TryGetValue(childElement.Key, out elementAttributes);

                    var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(elementAttributes);

                    foreach (var attribute in attributes)
                    {
                        switch (attribute.Key)
                        {
                            case "@class":
                                childTag.AddCssClass(attribute.Value.ToString());
                                break;
                            case "InnerText":
                                childTag.SetInnerText(attribute.Value.ToString());
                                break;
                            default:
                                childTag.MergeAttribute(attribute.Key, attribute.Value.ToString());
                                break;
                        }
                    }
                    childTag.ToString(TagRenderMode.SelfClosing);
                    if (childTag != null) anchorTag.InnerHtml += childTag.ToString();
                }                    
            }
            return MvcHtmlString.Create(anchorTag.ToString(TagRenderMode.Normal));
        }
        else
        {
            return htmlHelper.ActionLink(linkText, actionName, controllerName, routeValues, htmlAttributesDictionary);
        }
    }

1
È fantastico che tu sia stato ispirato e abbia la capacità di farlo. Tuttavia, guardo le istruzioni foreach nidificate e voglio eseguire. Semplicemente non è gestibile dalla maggior parte degli sviluppatori. Se è piuttosto impostato nel metodo di estensione del tipo black box in pietra, allora probabilmente ok, ma ha un odore di codice. Non facile per gli occhi per qualcosa che è piuttosto semplice. Grazie per i tuoi sforzi.
Tom Stickel,

Sono molto d'accordo sul nidificazione dei loop. Per ragioni di sintonia è lì. Da un punto di vista dell'ottimizzazione, sì, il loop nidificato dovrebbe essere nel proprio metodo privato e i parametri devono essere affermati, il codice deve essere molto più difensivo, ecc.
William-kid,

0

È molto semplice.

Se vuoi avere qualcosa come un'icona glyphicon e poi "Wish List",

<span class="glyphicon-heart"></span> @Html.ActionLink("Wish List (0)", "Index", "Home")

0

La mia soluzione usando i componenti bootstrap:

<a class="btn btn-primary" href="@Url.Action("resetpassword", "Account")">
    <span class="glyphicon glyphicon-user"></span> Reset Password
</a>

0

Prova di seguito il codice che potrebbe esserti di aiuto.

 @Html.ActionLink(" SignIn", "Login", "Account", routeValues: null, htmlAttributes: new {  id = "loginLink" ,**@class="glyphicon glyphicon-log-in"** }) 

solo una semplice aggiunta, @ class e poi l'effettiva classe css mi aiutano a risolvere il mio problema
Ahsanul
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.