Umieszczasz HTML wewnątrz Html.ActionLink (), plus brak tekstu linku?

169

Mam dwa pytania:

  1. Zastanawiam się, jak mogę wyświetlać brak tekstu łącza podczas używania Html.ActionLink()w widoku MVC (w rzeczywistości jest to Site.Master).

Nie ma przeciążonej wersji, która nie zezwala na tekst linku, a kiedy próbuję przekazać tylko puste miejsce string, kompilator mówi mi, że potrzebuje niepustego ciągu.

Jak mogę to naprawić?

  1. Muszę umieścić <span>tagi w tagu kotwicy, ale to nie działa Html.ActionLink();. Chciałbym zobaczyć następujące dane wyjściowe:

    Tekst obejmujący

Jak mogę umieścić tagi wewnątrz tagu kotwicy w ASP.NET MVC?

MegaMatt
źródło
Jaki byłby cel / zastosowanie posiadania pustego linku do działania?
David
1
Używam obrazka dla paska nawigacji, a <li>widzisz konkretny przycisk nawigacyjny (z rozmiarem, pozycją w tle itp. Określonymi w arkuszu stylów CSS). Ale musi do czegoś prowadzić, więc nie chcę wyświetlać tekstu. Chcę, żeby duszek zrobił to za mnie.
MegaMatt

Odpowiedzi:

322

Zamiast używać Html.ActionLink, możesz wyrenderować adres URL za pomocą Url.Action

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

I zrobić pusty adres URL, który możesz mieć

<a href="<%= Url.Action("Index", "Home") %>"></a>
<a href="@Url.Action("Index", "Home")"></a>
David
źródło
3
Musiałem użyć <a href="@Url.Action("Index", "Home")"> <span> SMS-a </span> </a>, mojego programisty nie ma w pobliżu, aby zapytać, dlaczego muszę to zrobić to, ale może być pomocne dla każdego, kto próbuje użyć powyższej odpowiedzi i okazuje się, że nie działa.
Dave Haigh,
2
@ Url.Action dotyczy szablonu maszynki do golenia. Zaktualizowałem odpowiedź, abyś mógł zobaczyć oba.
David,
<a [email protected]("Create", "Product")><span>Create</span></a>również działa. Cytaty nie są wymagane.
David
1
W przypadku treści statycznych dlaczego nie wpisać bezpośrednio kodu HTML? Wydaje się mniej
rozwlekłe
Nie jest to już prawdziwa opcja w Asp.Net Core 2, jeśli chcesz używać Ajax.
Zorkind
17

Inną opcją jest niestandardowe rozszerzenie HtmlHelper. Uwaga : ParameterDictionary to mój własny typ. Możesz zastąpić RouteValueDictionary, ale musisz to skonstruować inaczej.

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
źródło
14

Oto (słabe i brudne) obejście na wypadek, gdybyś musiał użyć Ajax lub jakiejś funkcji, której nie możesz użyć podczas tworzenia linku ręcznie (przy użyciu tagu):

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

Możesz użyć dowolnego tekstu zamiast „LinkTextToken”, jest on tylko do zastąpienia, ważne jest tylko, aby nie pojawiał się nigdzie indziej wewnątrz actionlink.

Goran Obradovic
źródło
6
+1 Niezły pomysł. W Razor będziesz musiał to wszystko rapowaćHtml.Raw()
Carrie Kendall,
Dzięki :) Teraz, gdy widzę, czego użyliśmy, prawie się wstydzę, robienie tych rzeczy na serwerze to takie marnowanie zasobów serwera ...
Goran Obradovic
1
Ponieważ używam @ Ajax.ActionLink i nie chciałem ręcznie ustawiać wszystkich date-atrybutów, jest to dla mnie najlepsze rozwiązanie. +1
asontu
Dzięki, działało jak urok, gdy używałem również Ajax.ActionLink. Wydawało się, że niczego nie spowolniło i musiałem zachować ten sam układ i stylistykę.
Blacky Wolf
Chcę tylko powiedzieć, że to nie działa w .Net Core, ToHtmlString () zostało usunięte w wersji 2 nie jestem pewien co do wersji 1
Zorkind
12

Po prostu użyj Url.Actionzamiast Html.ActionLink:

<li id="home_nav"><a href="<%= Url.Action("ActionName") %>"><span>Span text</span></a></li>
Craig Stuntz
źródło
@CraigStunz dlaczego powinniśmy używać Url.Action zamiast Html.ActionLink?
Roxy'Pro,
6

To zawsze działało dobrze dla mnie. Nie jest brudny i bardzo czysty.

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

dbarth
źródło
Url.Action nie ma konstruktora, który będzie pobierał htmlAttributes. Nie to samo, co ActionLink.
barrypicker
2

Skończyło się na niestandardowej metodzie rozszerzenia. Warto zauważyć, że podczas próby umieszczenia kodu HTML wewnątrz obiektu Anchor tekst linku może znajdować się po lewej lub po prawej stronie wewnętrznego kodu HTML. Z tego powodu zdecydowałem się podać parametry dla lewego i prawego wewnętrznego kodu HTML - tekst linku znajduje się pośrodku. Zarówno lewy, jak i prawy wewnętrzny kod HTML są opcjonalne.

Metoda rozszerzenia 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;
    }

Przykład użycia:

Oto przykład użycia. W tym przykładzie chciałem, aby wewnętrzny kod HTML znajdował się po prawej stronie tekstu linku ...

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

Wyniki:

skutkuje to następującym kodem HTML ...

<a href="/SomethingOtherThanHome/SomethingOtherThanIndex">Hello World<span class="caret" /></a>
barrypicker
źródło
1

Pomyślałem, że może to być przydatne podczas korzystania z bootstrapa i niektórych glypiconów:

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

Spowoduje to wyświetlenie tagu A z linkiem do kontrolera, z ładną ikoną spinacza, która reprezentuje łącze pobierania, a wyjście html jest utrzymywane w czystości

Terry Kernan
źródło
1

Oto dodatkowe rozszerzenie odpowiedzi @ tvanfosson. Zainspirował mnie to i postanowiłem uczynić go bardziej ogólnym.

    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
źródło
1
To wspaniale, że jesteś zainspirowany i masz taką możliwość. Jednak patrzę na zagnieżdżone instrukcje foreach i chcę uruchomić. Większość programistów nie może go po prostu utrzymać. Jeśli jest dość ustawiona w metodzie rozszerzenia typu kamiennej czarnej skrzynki, to prawdopodobnie w porządku, ale ma w sobie zapach kodu. Nie jest to łatwe dla oczu, jak na coś, co jest dość proste. Dziękuję jednak za twoje wysiłki.
Tom Stickel,
Bardzo zgadzam się z zagnieżdżonymi pętlami for. Ze względu na zwięzłość tam jest. Z punktu widzenia optymalizacji tak, zagnieżdżona pętla for powinna znajdować się we własnej, prywatnej metodzie, a parametry muszą zostać potwierdzone, kod musi być znacznie bardziej defensywny itp.
william-kid
0

To jest bardzo proste.

Jeśli chcesz mieć coś w rodzaju ikony glifu, a następnie „Lista życzeń”,

<span class="glyphicon-heart"></span> @Html.ActionLink("Wish List (0)", "Index", "Home")
DanKodi
źródło
0

Moje rozwiązanie wykorzystujące komponenty bootstrap:

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

Wypróbuj poniższy kod, który może ci pomóc.

 @Html.ActionLink(" SignIn", "Login", "Account", routeValues: null, htmlAttributes: new {  id = "loginLink" ,**@class="glyphicon glyphicon-log-in"** }) 
Ahsanul
źródło
po prostu dodaj, @ class, a potem aktualna klasa css pomoże mi rozwiązać mój problem
Ahsanul