Mettre du HTML dans Html.ActionLink (), plus aucun texte de lien?

169

J'ai deux questions:

  1. Je me demande comment je peux afficher aucun texte de lien lors de l'utilisation Html.ActionLink()dans une vue MVC (en fait, c'est le cas Site.Master).

Il n'y a pas de version surchargée qui n'autorise pas le texte de lien, et lorsque j'essaie de ne passer qu'un vide string, le compilateur me dit qu'il a besoin d'une chaîne non vide.

Comment puis-je réparer cela?

  1. J'ai besoin de mettre des <span>balises dans la balise d'ancrage, mais cela ne fonctionne pas avec Html.ActionLink();. J'aimerais voir la sortie suivante:

    Texte de portée

Comment puis-je placer des balises à l'intérieur de la balise d'ancrage dans ASP.NET MVC?

MegaMatt
la source
Quel serait le but / l'utilité d'avoir un lien d'action vide?
David
1
J'utilise un sprite d'image pour une barre de navigation, et le <li>que vous voyez est un bouton de navigation particulier (avec la taille, la position d'arrière-plan, etc. spécifiée dans la feuille de style css). Mais il doit être lié à quelque chose, donc je ne veux pas afficher le texte. Je veux que le sprite fasse ça pour moi.
MegaMatt

Réponses:

322

Au lieu d'utiliser Html.ActionLink, vous pouvez afficher une URL via Url.Action

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

Et pour faire une URL vide, vous pourriez avoir

<a href="<%= Url.Action("Index", "Home") %>"></a>
<a href="@Url.Action("Index", "Home")"></a>
David
la source
3
J'ai dû utiliser <a href="@Url.Action("Index", "Home")"> <span> Texte </span> </a>, mon développeur n'est pas là pour me demander pourquoi je devais le faire cela, mais il peut être utile pour quiconque essaie d'utiliser la réponse ci-dessus et de constater que cela n'a pas fonctionné.
Dave Haigh
2
@ Url.Action est lorsque vous utilisez un modèle de rasoir. J'ai mis à jour la réponse pour que vous puissiez voir les deux.
David
<a [email protected]("Create", "Product")><span>Create</span></a>fonctionne également. Les devis ne sont pas obligatoires.
David
1
Pour le contenu statique, pourquoi ne pas taper directement le html? Cela semble moins verbeux et plus simple
SkeetJon
Ce n'est plus une vraie option dans Asp.Net Core 2 si vous souhaitez utiliser Ajax.
Zorkind
17

Une extension HtmlHelper personnalisée est une autre option. Remarque : ParameterDictionary est mon propre type. Vous pouvez remplacer un RouteValueDictionary mais vous devrez le construire différemment.

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();
}
Tvanfosson
la source
14

Voici une solution de contournement (faible et sale) au cas où vous auriez besoin d'utiliser ajax ou une fonctionnalité que vous ne pouvez pas utiliser lorsque vous créez un lien manuellement (en utilisant une balise):

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

Vous pouvez utiliser n'importe quel texte au lieu de 'LinkTextToken', il n'est là que pour être remplacé, il est seulement important qu'il ne se produise nulle part ailleurs dans actionlink.

Goran Obradovic
la source
6
+1 Bonne idée. Dans Razor, vous devrez rapper tout cela dansHtml.Raw()
Carrie Kendall
Merci :) Maintenant que je vois ce que nous avons utilisé, je suis presque embarrassé, faire ces choses sur le serveur est un tel gaspillage de ressources serveur ...
Goran Obradovic
1
Comme j'utilise @ Ajax.ActionLink et que je n'ai pas envie de définir manuellement tous les date-attributs, c'est la meilleure solution pour moi. +1
asontu
Merci, a fonctionné comme un charme quand j'utilisais également Ajax.ActionLink. Cela n'a pas semblé ralentir quoi que ce soit et j'ai pu garder la même mise en page et le même style.
Blacky Wolf
Je veux juste dire que cela ne fonctionne pas dans .Net Core, ToHtmlString () a été supprimé dans la v2 pas sûr de la v1
Zorkind
12

Utilisez simplement à la Url.Actionplace de Html.ActionLink:

<li id="home_nav"><a href="<%= Url.Action("ActionName") %>"><span>Span text</span></a></li>
Craig Stuntz
la source
@CraigStunz pourquoi devrions-nous utiliser Url.Action au lieu de Html.ActionLink?
Roxy'Pro le
6

Cela a toujours bien fonctionné pour moi. Ce n'est pas salissant et très propre.

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

dbarth
la source
Url.Action n'a pas de constructeur qui prendra htmlAttributes. Pas la même chose que ActionLink.
barrypicker
2

Je me suis retrouvé avec une méthode d'extension personnalisée. Il est intéressant de noter que lorsque vous essayez de placer du HTML à l'intérieur d'un objet Anchor, le texte du lien peut être soit à gauche, soit à droite du HTML interne. Pour cette raison, j'ai choisi de fournir des paramètres pour le HTML interne gauche et droit - le texte du lien est au milieu. Le HTML interne gauche et droit est facultatif.

Méthode d'extension 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;
    }

Exemple d'utilisation:

Voici un exemple d'utilisation. Pour cet exemple, je voulais uniquement le html interne sur le côté droit du texte du lien ...

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

Résultats:

cela donne le HTML suivant ...

<a href="/SomethingOtherThanHome/SomethingOtherThanIndex">Hello World<span class="caret" /></a>
barrypicker
la source
1

J'ai pensé que cela pourrait être utile lors de l'utilisation de bootstrap et de certains 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>

Cela affichera une balise A, avec un lien vers un contrôleur, avec une belle icône en forme de trombone pour représenter un lien de téléchargement, et la sortie html est maintenue propre

Terry Kernan
la source
1

Voici une super extension de la réponse de @ tvanfosson. Je m'en suis inspiré et j'ai décidé de le rendre plus générique.

    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);
        }
    }
william-kid
la source
1
C'est formidable que vous ayez été inspiré et que vous ayez la capacité de le faire. Cependant, je regarde les instructions foreach imbriquées et je veux exécuter. Il n'est tout simplement pas maintenable par la plupart des développeurs. S'il est assez défini dans la méthode d'extension de type boîte noire en pierre, alors peut-être bien, mais il a une odeur de code. Pas facile du tout pour les yeux pour quelque chose d'assez simple. Merci pour vos efforts.
Tom Stickel
Je suis tout à fait d'accord sur les boucles for imbriquées. Par souci de concision, il est là. Du point de vue de l'optimisation, oui, la boucle for imbriquée doit être dans sa propre méthode privée, et les paramètres doivent être affirmés, le code doit être beaucoup plus défensif, etc.
william-kid
0

C'est très simple.

Si vous voulez avoir quelque chose comme une icône de glyphicon, puis "Liste de souhaits",

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

Ma solution utilisant des composants bootstrap:

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

Veuillez essayer ci-dessous le code qui peut vous aider.

 @Html.ActionLink(" SignIn", "Login", "Account", routeValues: null, htmlAttributes: new {  id = "loginLink" ,**@class="glyphicon glyphicon-log-in"** }) 
Ahsanul
la source
un simple ajout, une classe @ et une classe css réelle
m'aident