Menempatkan HTML di dalam Html.ActionLink (), plus No Link Text?

169

Saya punya dua pertanyaan:

  1. Saya bertanya-tanya bagaimana saya tidak dapat menampilkan teks tautan saat menggunakan Html.ActionLink()dalam tampilan MVC (sebenarnya, ini Site.Master).

Tidak ada versi overload yang tidak memungkinkan teks tautan, dan ketika saya mencoba memasukkan hanya kosong string, kompiler memberitahu saya itu membutuhkan string yang tidak kosong.

Bagaimana saya bisa memperbaikinya?

  1. Saya perlu memasukkan <span>tag ke dalam tag anchor, tetapi tidak berfungsi Html.ActionLink();. Saya ingin melihat output berikut:

    Teks rentang

Bagaimana saya bisa menaruh tag di dalam tag anchor di ASP.NET MVC?

MegaMatt
sumber
Apa tujuan / penggunaan memiliki tautan tindakan kosong?
David
1
Saya menggunakan sprite gambar untuk bilah navigasi, dan yang <li>Anda lihat adalah tombol navigasi tertentu (dengan ukuran, pos latar belakang, dll yang ditentukan dalam css stylesheet). Tapi itu harus terhubung ke sesuatu, jadi saya tidak ingin menampilkan teks. Saya ingin sprite melakukan itu untuk saya.
MegaMatt

Jawaban:

322

Alih-alih menggunakan Html.ActionLink Anda dapat merender url melalui Url.Action

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

Dan untuk melakukan url kosong bisa Anda miliki

<a href="<%= Url.Action("Index", "Home") %>"></a>
<a href="@Url.Action("Index", "Home")"></a>
David
sumber
3
Saya harus menggunakan <a href="@Url.Action("Index", "Home")"> <span> Teks </span> </a>, dev saya tidak ada untuk bertanya mengapa saya harus melakukan ini tetapi mungkin bermanfaat bagi siapa pun yang menggunakan jawaban di atas dan ternyata tidak berhasil.
Dave Haigh
2
@ Url.Action adalah saat menggunakan template silet. Saya telah memperbarui jawabannya sehingga Anda dapat melihat keduanya.
David
<a [email protected]("Create", "Product")><span>Create</span></a>juga berfungsi. Kutipan tidak diperlukan.
David
1
Untuk konten statis mengapa tidak mengetik html secara langsung? Tampaknya kurang jelas dan lebih sederhana
SkeetJon
Bukan opsi nyata di Asp.Net Core 2 lagi jika Anda ingin menggunakan Ajax.
Zorkind
17

Ekstensi HtmlHelper kustom adalah opsi lain. Catatan : ParameterDictionary adalah tipe saya sendiri. Anda bisa mengganti RouteValueDictionary tetapi Anda harus membuatnya secara berbeda.

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

Ini solusi (rendah dan kotor) jika Anda perlu menggunakan ajax atau beberapa fitur yang tidak dapat Anda gunakan saat membuat tautan secara manual (menggunakan tag):

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

Anda dapat menggunakan teks apa saja alih-alih 'LinkTextToken', itu hanya ada untuk diganti, hanya penting bahwa itu tidak terjadi di tempat lain di dalam actionlink.

Goran Obradovic
sumber
6
+1 Ide bagus. Di Razor, Anda harus memperkosa semua itu diHtml.Raw()
Carrie Kendall
Terima kasih :) Sekarang saya melihat apa yang kami gunakan, saya hampir merasa malu, melakukan hal-hal ini di server adalah pemborosan sumber daya server ...
Goran Obradovic
1
Karena saya menggunakan @ Ajax.ActionLink dan tidak merasa seperti mengatur semua date-atribut secara manual , ini adalah solusi terbaik untuk saya. +1
asontu
Terima kasih, bekerja seperti pesona ketika saya juga menggunakan Ajax.ActionLink. Tampaknya tidak memperlambat apa pun dan saya harus menjaga tata letak dan gaya yang sama.
Blacky Wolf
Hanya ingin mengatakan, ini tidak berfungsi di .Net Core, ToHtmlString () telah dihapus di v2 tidak yakin tentang v1
Zorkind
12

Gunakan saja Url.Actionalih-alih Html.ActionLink:

<li id="home_nav"><a href="<%= Url.Action("ActionName") %>"><span>Span text</span></a></li>
Craig Stuntz
sumber
@CraigStunz mengapa kita harus menggunakan Url.Action alih-alih Html.ActionLink?
Roxy'Pro
6

Ini selalu bekerja dengan baik untuk saya. Itu tidak berantakan dan sangat bersih.

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

dbarth
sumber
Url.Action tidak memiliki konstruktor yang akan mengambil htmlAttributes. Tidak sama dengan ActionLink.
barrypicker
2

Saya berakhir dengan metode ekstensi khusus. Perlu dicatat, ketika mencoba menempatkan HTML di dalam objek Anchor, teks tautannya bisa ke kiri, atau ke kanan HTML bagian dalam. Untuk alasan ini, saya memilih untuk memberikan parameter untuk HTML bagian dalam kiri dan kanan - teks tautan ada di tengah. HTML internal kiri dan kanan adalah opsional.

Metode Ekstensi 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;
    }

Contoh Penggunaan:

Berikut adalah contoh penggunaannya. Untuk contoh ini saya hanya ingin html dalam di sebelah kanan teks tautan ...

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

Hasil:

ini menghasilkan HTML berikut ...

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

Saya pikir ini mungkin berguna saat menggunakan bootstrap dan beberapa 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>

Ini akan menunjukkan tag A, dengan tautan ke pengontrol, dengan ikon penjepit kertas yang bagus di atasnya untuk mewakili tautan unduhan, dan output html tetap bersih

Terry Kernan
sumber
1

Berikut ini adalah perluasan jawaban @ tvanfosson. Saya terinspirasi olehnya dan memutuskan untuk membuatnya lebih generik.

    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
sumber
1
Sangat bagus bahwa Anda terinspirasi dan memiliki kemampuan untuk melakukan ini. Namun, saya melihat pernyataan foreach bersarang dan ingin menjalankan. Itu hanya itu tidak dapat dipelihara oleh sebagian besar pengembang. Jika cukup diatur dalam metode ekstensi jenis kotak batu hitam maka mungkin ok, tetapi memiliki bau kode untuk itu. Tidak mudah di mata sama sekali untuk sesuatu yang cukup sederhana. Terima kasih atas upaya Anda.
Tom Stickel
Saya sangat setuju tentang bersarang untuk loop. Demi kesederhanaan itu ada di sana. Dari sudut pandang optimisasi, ya, nested for loop harus dalam metode privatnya sendiri, dan parameter perlu ditegaskan, kode harus jauh lebih defensif, dll.
william-kid
0

Ini sangat sederhana.

Jika Anda ingin memiliki sesuatu seperti ikon glyphicon dan kemudian "Wish List",

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

Solusi saya menggunakan komponen bootstrap:

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

Silakan coba di bawah Kode yang dapat membantu Anda.

 @Html.ActionLink(" SignIn", "Login", "Account", routeValues: null, htmlAttributes: new {  id = "loginLink" ,**@class="glyphicon glyphicon-log-in"** }) 
Ahsanul
sumber
cukup tambahkan, @ class dan kemudian kelas css aktual membantu saya untuk menyelesaikan masalah saya
Ahsanul