Colocando HTML dentro de Html.ActionLink (), além de Texto sem Link?

169

Eu tenho duas perguntas:

  1. Eu estou querendo saber como eu não posso exibir nenhum texto de link ao usar Html.ActionLink()em uma exibição MVC (na verdade, isso é Site.Master).

Não há uma versão sobrecarregada que não permita o texto do link e, quando tento passar apenas um espaço em branco string, o compilador diz que precisa de uma string não vazia.

Como posso consertar isso?

  1. Preciso colocar <span>tags dentro da tag anchor, mas não está funcionando Html.ActionLink();. Eu gostaria de ver a seguinte saída:

    Texto de extensão

Como posso colocar marcas dentro da marca âncora no ASP.NET MVC?

MegaMatt
fonte
Qual seria o objetivo / uso de ter um link de ação em branco?
David
1
Estou usando um sprite de imagem para uma barra de navegação, e o que <li>você vê é um botão de navegação específico (com tamanho, posição do plano de fundo, etc. especificados na folha de estilo css). Mas ele deve estar vinculado a algo, então não quero exibir o texto. Eu quero que o sprite faça isso por mim.
MegaMatt 29/09/09

Respostas:

322

Em vez de usar Html.ActionLink, você pode renderizar um URL via Url.Action

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

E para criar um URL em branco, você poderia ter

<a href="<%= Url.Action("Index", "Home") %>"></a>
<a href="@Url.Action("Index", "Home")"></a>
David
fonte
3
Eu tive que usar <a href="@Url.Action("Index", "Home")"> <span> Texto </span> </a>, meu desenvolvedor não está por perto para perguntar por que eu tinha que fazer isso, mas pode ser útil para qualquer pessoa usar a resposta acima e descobrir que ela não funcionou.
Dave Haigh
2
@ Url.Action é ao usar o modelo de barbear. Atualizei a resposta para que você possa ver as duas.
David
<a [email protected]("Create", "Product")><span>Create</span></a>também funciona. As cotações não são necessárias.
David
1
Para conteúdo estático, por que não digitar o html diretamente? Parece menos detalhado e mais simples
SkeetJon
Não é mais uma opção real no Asp.Net Core 2, se você deseja usar o Ajax.
Zorkind 9/08/18
17

Uma extensão HtmlHelper personalizada é outra opção. Nota : ParameterDictionary é meu próprio tipo. Você pode substituir um RouteValueDictionary, mas precisará construí-lo de maneira diferente.

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
fonte
14

Aqui está uma solução alternativa (baixa e suja), caso você precise usar ajax ou algum recurso que não possa ser usado ao criar um link manualmente (usando a tag):

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

Você pode usar qualquer texto em vez de 'LinkTextToken', ele existe apenas para ser substituído, é importante que não ocorra em nenhum outro lugar do actionlink.

Goran Obradovic
fonte
6
+1 Boa ideia. No Razor, você terá que fazer tudo isso emHtml.Raw()
Carrie Kendall
Obrigado :) Agora que eu vejo que estamos acostumados, eu quase se sentir envergonhado, fazendo essas coisas no servidor é tal desperdício de recursos do servidor ...
Goran Obradovic
1
Como estou usando o @ Ajax.ActionLink e não tenho vontade de definir manualmente todos os date-atributos, esta é a melhor solução para mim. 1
asontu 15/03
Obrigado, funcionou como um encanto quando eu também estava usando Ajax.ActionLink. Não pareceu desacelerar nada e eu tenho que manter o mesmo layout e estilo.
Blacky Wolf 23/03
Só quero dizer, isso não funciona em .Net Core, ToHtmlString () foi removido em v2 não tem certeza sobre v1
Zorkind
12

Basta usar em Url.Actionvez de Html.ActionLink:

<li id="home_nav"><a href="<%= Url.Action("ActionName") %>"><span>Span text</span></a></li>
Craig Stuntz
fonte
@CraigStunz, por que devemos usar Url.Action em vez de Html.ActionLink?
Roxy'Pro
6

Isso sempre funcionou bem para mim. Não é bagunçado e muito limpo.

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

dbarth
fonte
Url.Action não possui um construtor que aceite htmlAttributes. Não é o mesmo que ActionLink.
barrypicker
2

Acabei com um método de extensão personalizado. É importante notar que, ao tentar colocar o HTML dentro de um objeto Anchor, o texto do link pode estar à esquerda ou à direita do HTML interno. Por esse motivo, optei por fornecer parâmetros para o HTML interno esquerdo e direito - o texto do link está no meio. O HTML interno esquerdo e direito são opcionais.

Método de extensão 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;
    }

Exemplo de uso:

Aqui está um exemplo de uso. Para este exemplo, eu queria apenas o html interno no lado direito do texto do link ...

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

Resultados:

isso resulta no seguinte HTML ...

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

Eu pensei que isso poderia ser útil ao usar o bootstrap e alguns 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>

Isso mostrará uma tag A, com um link para um controlador, com um belo ícone de clipe de papel para representar um link de download, e a saída html será mantida limpa

Terry Kernan
fonte
1

Aqui está uma super expansão da resposta de @ tvanfosson. Fui inspirado por ele e decidi torná-lo mais genérico.

    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
fonte
1
É ótimo que você tenha se inspirado e tenha a capacidade de fazer isso. No entanto, eu olho para instruções foreach aninhadas e quero executar. Simplesmente não é sustentável pela maioria dos desenvolvedores. Se estiver bem definido no método de extensão do tipo caixa preta de pedra, possivelmente está ok, mas tem um cheiro de código. Não é nada fácil para os olhos por algo que é bastante simples. Obrigado por seus esforços embora.
precisa saber é o seguinte
Eu concordo muito sobre aninhados para loops. Por uma questão de sucessão, está lá. De um ponto de vista de otimização sim o aninhadas para loop deve estar em seu próprio método particular e parâmetros precisam ser afirmado, as necessidades de código a ser muito mais defensivo, etc.
william-kid
0

É muito simples.

Se você deseja ter algo como um ícone de glifo e, em seguida, "Lista de desejos",

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

Minha solução usando componentes de autoinicialização:

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

Tente abaixo o código que pode ajudá-lo.

 @Html.ActionLink(" SignIn", "Login", "Account", routeValues: null, htmlAttributes: new {  id = "loginLink" ,**@class="glyphicon glyphicon-log-in"** }) 
Ahsanul
fonte
apenas simples add, classe @ e, em seguida, ajuda classe css real me para resolver o meu problema
Ahsanul