73

is there anyway to have an image act as an ajax actionlink? I can only get it to work using text. Thanks for your help!

tereško
  • 58,060
  • 25
  • 98
  • 150

21 Answers21

67

From Stephen Walthe, from his Contact manger project

 public static class ImageActionLinkHelper
{

    public static string ImageActionLink(this AjaxHelper helper, string imageUrl, string altText, string actionName, object routeValues, AjaxOptions ajaxOptions)
    {
        var builder = new TagBuilder("img");
        builder.MergeAttribute("src", imageUrl);
        builder.MergeAttribute("alt", altText);
        var link = helper.ActionLink("[replaceme]", actionName, routeValues, ajaxOptions);
        return link.Replace("[replaceme]", builder.ToString(TagRenderMode.SelfClosing));
    }

}

You can now type in your aspx file :

<%= Ajax.ImageActionLink("../../Content/Delete.png", "Delete", "Delete", new { id = item.Id }, new AjaxOptions { Confirm = "Delete contact?", HttpMethod = "Delete", UpdateTargetId = "divContactList" })%> 
Black Horus
  • 1,043
  • 8
  • 13
  • 2
    Just an FYI, I added an additional parameter to the ImageActionLink method to accept the controller name as the MVC ActionLink method has and it works flawlessly! Thanks – Dustin Laine Jan 04 '10 at 17:55
  • 14
    In addition to this, in the above code sample link will not have the method Replace as an available option on it. You'll need to first call ToString() or ToHtmlString() on it before being able to call Replace(). – mwright Apr 06 '10 at 15:48
  • I feel a little silly, but, I can't work out how to implement this. I don't suppose you can explain a little where the class needs to go? – wil Nov 03 '11 at 10:56
  • 1
    @wil this is a helper class (notice the keyword `this`). Just put it anywhere and reference it via `@using`, and you should be able to consume the new method. – ashes999 Apr 18 '13 at 21:18
  • 1
    The custom helper ImageActionLink will render text and not markup until the return type is changed from string to IHtmlString – rumi Oct 29 '14 at 11:13
  • I used MvcHtmlString instead of string as a return type, it worked as a charm! Thanks All : ) – N0rA Nov 13 '14 at 12:26
35

Here's the easiest solution I've found:

<%= Ajax.ActionLink("[replacethis]", ...).Replace("[replacethis]", "<img src=\"/images/test.gif\" ... />" %>

The Replace() call is used to push the img tag into the action link. You just need to use the "[replaceme]" text (or any other safe text) as a temporary placeholder to create the link.

Neal Stublen
  • 815
  • 11
  • 14
33

This is a Razor/MVC 3 (and later) update to Black Horus' answer:

using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;

public static class ImageActionLinkHelper
{
    public static IHtmlString ImageActionLink(this AjaxHelper helper, string imageUrl, string altText, string actionName, object routeValues, AjaxOptions ajaxOptions, object htmlAttributes = null)
    {
        var builder = new TagBuilder("img");
        builder.MergeAttribute("src", imageUrl);
        builder.MergeAttribute("alt", altText);
        builder.MergeAttributes(new RouteValueDictionary(htmlAttributes));
        var link = helper.ActionLink("[replaceme]", actionName, routeValues, ajaxOptions).ToHtmlString();
        return MvcHtmlString.Create(link.Replace("[replaceme]", builder.ToString(TagRenderMode.SelfClosing)));
    }

}

You can now type in your .cshtml file :

@Ajax.ImageActionLink("../../Content/Delete.png", "Delete", "Delete", new { id = item.Id }, new AjaxOptions { Confirm = "Delete contact?", HttpMethod = "Delete", UpdateTargetId = "divContactList" })

Oct 31. 2013: Updated with an extra parameter to allow for setting additional HTML attributes to the image element. Usage:

@Ajax.ImageActionLink("../../Content/Delete.png", "Delete", "Delete", new { id = item.Id }, new AjaxOptions { Confirm = "Delete contact?", HttpMethod = "Delete", UpdateTargetId = "divContactList" }, new{ style="border: none;" })
Arjan Einbu
  • 13,543
  • 2
  • 56
  • 59
  • thanks for the update. It was quite helpful; however you appear to have 2 extra characters at the end of the .cshtml line. – snumpy Jun 03 '11 at 16:32
  • Thanks, @snumpy! This was a typical copy-paste error... :) It's fixed – Arjan Einbu Jun 06 '11 at 10:38
  • I feel a little silly, but, I can't work out how to implement this. I don't suppose you can explain a little where the class needs to go? – wil Nov 03 '11 at 10:57
  • You can put it anywhere. (At root level of your MVC application will do fine...) (You might need to put in a @using directive at the top of your razor files, pointing at the namespace of the class, if any) – Arjan Einbu Nov 03 '11 at 14:04
  • I would suggest you to add an attribute parameter to set attribute and style in the rendered image. (for example to clear the default image border). An usefull example can be found at this link http://kitsula.com/Article/Html.ImageActionLink-extension – Ghini Antonio Oct 31 '13 at 09:11
  • @GhiniAntonio: Thanks. Just updated the answer to include a parameter for html-attributes. – Arjan Einbu Oct 31 '13 at 20:47
6

Another solution is to create your own extension method:

ActionLink<TController>(this HtmlHelper helper, Expression<Action<TController>> action, string linkText, object htmlAttributes, LinkOptions options)

and as the last parameter is the enumeration LinkOptions

[Flags]
public enum LinkOptions
{
    PlainContent = 0,
    EncodeContent = 1,
}

and then you can use it as follows:

Html.ActionLink<Car>(
     c => c.Delete(item.ID), "<span class=\"redC\">X</span>",
     new { Class = "none left" }, 
     LinkOptions.PlainContent)

I'll post whole description of this solution on my blog: http://fknet.wordpress.com/

frantisek
  • 366
  • 1
  • 4
  • 8
5

The short answer is that is not possible. Your options are to write your own extension method to have an ImageActionLink, not too hard to do. Or add an attribute to the actionLink and replace the innerhtml with the image tag.

MrJavaGuy
  • 676
  • 4
  • 8
5

See version 7 the Contact Manager Tutorial on http://asp.net/mvc. Stephen Walther has an example of creating an Ajax.ActionLink that is an image.

4

General solution: include any Razor you want inside the action link

There's a much better solution using Razor template delegates, which allows to insert any Razor code inside the action link in a very natural way. So you can add an image, or any other code.

This is the extension method:

public static IHtmlString ActionLink<T>(this AjaxHelper ajaxHelper,
    T item, Func<T,HelperResult> template, string action,
    string controller, object routeValues, AjaxOptions options)
{
    string rawContent = template(item).ToHtmlString();
    MvcHtmlString a = ajaxHelper.ActionLink("$$$", action, 
        controller, routeValues, options);
    return MvcHtmlString.Create(a.ToString().Replace("$$$", rawContent));
}

An this is how it can be used:

@Ajax.ActionLink(car, 
    @<div>
        <h1>@car.Maker</h1>
        <p>@car.Description</p>
        <p>Price: @string.Format("{0:C}",car.Price)</p>
    </div>, ...

This allows to write Razor with intellisense, and use any object you want for the template (the ViewModel, or any other object, like the car in my sample). And you can use any helper inside the template to nest images or whatver element you want.

Note for Resharper Users

If you are using R# in your project, you can add R# annotations to improve Intellisense:

public static IHtmlString ActionLink<T>(this AjaxHelper ajaxHelper, T item,
    Func<T, HelperResult> template, 
    [AspMvcAction] string action, [AspMvcController] string controller, 
    object routeValues, AjaxOptions options)
Community
  • 1
  • 1
JotaBe
  • 38,030
  • 8
  • 98
  • 117
4

MVC3, Html.ActionImageLink and Ajax.ActionImageLink

Thank you to all the other answers in helping me with these.

public static MvcHtmlString ActionImageLink(this HtmlHelper helper, string imageUrl, string altText, string actionName, string controller, object routeValues)
{
    var builder = new TagBuilder("img");
    builder.MergeAttribute("src", imageUrl);
    builder.MergeAttribute("alt", altText);
    var link = helper.ActionLink("[replaceme]", actionName, controller, routeValues);
    return new MvcHtmlString(link.ToHtmlString().Replace("[replaceme]", builder.ToString(TagRenderMode.SelfClosing)));
}
public static MvcHtmlString ActionImageLink(this AjaxHelper helper, string imageUrl, string altText, string actionName, string controller, object routeValues, AjaxOptions ajaxOptions)
{
    var builder = new TagBuilder("img");
    builder.MergeAttribute("src", imageUrl);
    builder.MergeAttribute("alt", altText);
    var link = helper.ActionLink("[replaceme]", actionName, controller, routeValues, ajaxOptions);
    return new MvcHtmlString(link.ToHtmlString().Replace("[replaceme]", builder.ToString(TagRenderMode.SelfClosing)));
}
Valamas
  • 24,169
  • 25
  • 107
  • 177
  • Note: You need the following in your code for this to compile (VS 2010 cannot resolve missing references for extension methods): using System.Web.Mvc.Ajax; using System.Web.Mvc.Html; – Eric J. Mar 08 '12 at 20:47
1

Every answer is good but I found the easiest one:

@Html.ActionLink( " ", "Index", "Countries", null, new
{
        style = "background: url('../../Content/Images/icon.png') no-repeat center right;display:block; height:24px; width:24px;margin-top:-2px;text-decoration:none;"
} )

Note that it is using a white space (" ") for the link text. It will not work with an empty text.

Ali Adravi
  • 21,707
  • 9
  • 87
  • 85
0

.li_inbox { background: url(inbox.png) no-repeat; padding-left:40px; /image background wight 40px/ }


<li class="li_inbox" >
          @Ajax.ActionLink("Inbox", "inbox","Home", new {  },
            new AjaxOptions
        {
            UpdateTargetId = "MainContent",
            InsertionMode = InsertionMode.Replace,
            HttpMethod = "GET"
          })

samai
  • 9
  • 1
0

Try this

@Html.Raw(HttpUtility.HtmlDecode(Ajax.ActionLink( "<img src=\"/images/sjt.jpg\" title=\"上一月\" border=\"0\" alt=\"上一月\" />", "CalendarPartial", new { strThisDate = Model.dtCurrentDate.AddMonths(-1).ToString("yyyy-MM-dd") }, new AjaxOptions { @UpdateTargetId = "calendar" }).ToString()))
Thirumalai murugan
  • 5,698
  • 8
  • 32
  • 54
peter
  • 1
0

Nice solutions here, but what if you want to have more then just an image in the actionlink? This is how I do it:

     @using (Ajax.BeginForm("Action", "Controler", ajaxOptions))
     { 
        <button type="submit">
           <img src="image.png" />            
        </button>
     }

The drawback is that I still have to do a bit of styling on the button-element, but you can put all the html you want in there.

0

All are very Nice solutions, but if you dislike having a replace in your solution you can try this:

{
    var url = new UrlHelper(helper.ViewContext.RequestContext);

    // build the <img> tag
    var imgBuilder = new TagBuilder("img");
    imgBuilder.MergeAttribute("src", url.Content(imageUrl));
    imgBuilder.MergeAttribute("alt", altText);
    string imgHtml = imgBuilder.ToString(TagRenderMode.SelfClosing);

    //build the <a> tag
    var anchorBuilder = new TagBuilder("a");
    anchorBuilder.MergeAttribute("href", url.Action(actionName, controller, routeValues));
    anchorBuilder.InnerHtml = imgHtml; // include the <img> tag inside            
    anchorBuilder.MergeAttributes<string, object>(ajaxOptions.ToUnobtrusiveHtmlAttributes());
    string anchorHtml = anchorBuilder.ToString(TagRenderMode.Normal);

    return MvcHtmlString.Create(anchorHtml);
}

Furthermore, in my case, if I don't use url.Content(imageUrl), the image doesn't display.

Vlad Schnakovszki
  • 8,434
  • 6
  • 80
  • 114
Silvio
  • 21
  • 3
0

I have found that far and away the best solution to this is to use the input tag with type="image"

@using (Ajax.BeginForm( "LoadTest","Home" , new System.Web.Mvc.Ajax.AjaxOptions { UpdateTargetId = "[insert your target tag's id here]" }))
                {
                    <input type="image" class="[css style class here]" src="[insert image link here]">
                }

It's easy and it's fast.

I've used it in combination with other controls libraries that interfere with AjaxOptions, so I tend to type out the whole System.Web.Mvc.Ajax.AjaxOptions just in case I end up trying a different set in the future.

NOTE: I have noticed that this does appear to have issues within MVC3 (something to do with type="image"), it does work for MVC 4 though

0

Use this Extension to generate ajax link with glifyphicon:

    /// <summary>
    /// Create an Ajax.ActionLink with an associated glyphicon
    /// </summary>
    /// <param name="ajaxHelper"></param>
    /// <param name="linkText"></param>
    /// <param name="actionName"></param>
    /// <param name="controllerName"></param>
    /// <param name="glyphicon"></param>
    /// <param name="ajaxOptions"></param>
    /// <param name="routeValues"></param>
    /// <param name="htmlAttributes"></param>
    /// <returns></returns>
    public static MvcHtmlString ImageActionLink(this AjaxHelper ajaxHelper, string linkText, string actionName, string controllerName, string glyphicon, AjaxOptions ajaxOptions, RouteValueDictionary routeValues = null, object htmlAttributes = null)
    {
        //Example of result:          
        //<a id="btnShow" href="/Customers/ShowArtworks?customerId=1" data-ajax-update="#pnlArtworks" data-ajax-success="jsSuccess"
        //data-ajax-mode="replace" data-ajax-method="POST" data-ajax-failure="jsFailure" data-ajax-confirm="confirm" data-ajax-complete="jsComplete"
        //data-ajax-begin="jsBegin" data-ajax="true">
        //  <i class="glyphicon glyphicon-pencil"></i>
        //  <span>Edit</span>
        //</a>

        var builderI = new TagBuilder("i");
        builderI.MergeAttribute("class", "glyphicon " + glyphicon);
        string iTag = builderI.ToString(TagRenderMode.Normal);

        string spanTag = "";
        if (!string.IsNullOrEmpty(linkText))
        {
            var builderSpan = new TagBuilder("span") { InnerHtml = " " + linkText };
            spanTag = builderSpan.ToString(TagRenderMode.Normal);
        }

        //Create the "a" tag that wraps
        var builderA = new TagBuilder("a");

        var requestContext = HttpContext.Current.Request.RequestContext;
        var uh = new UrlHelper(requestContext);

        builderA.MergeAttribute("href", uh.Action(actionName, controllerName, routeValues));

        builderA.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
        builderA.MergeAttributes((ajaxOptions).ToUnobtrusiveHtmlAttributes());

        builderA.InnerHtml = iTag + spanTag;

        return new MvcHtmlString(builderA.ToString(TagRenderMode.Normal));
    }
TotPeRo
  • 6,561
  • 4
  • 47
  • 60
0

Use Html data- attributes

<a data-ajax="true" data-ajax-begin="..." data-ajax-success="..." href="@Url.Action("Delete")">
<i class="halflings-icon remove"></i>
</a>
              

Replace the

<i class="halflings-icon remove"></i>

with your own image

0

The first solution is to use a helper static method DecodeLinkContent like the following:

DecodeLinkContent(Html.ActionLink<Home>(c => c.Delete(item.ID), "<span class=\"redC\">X</span>",new { Class = "none left"})) 

DecodeLinkContent has to find first '>' and last '<' and has to replace the content with HttpUtility.Decode(content).

This solution is little bit a hack but I think it's the most easy.

frantisek
  • 366
  • 1
  • 4
  • 8
0

Others didn't work for me as the .ToHtmlString() spat out a string in MVC 4.

the below passes an id to the edit control and displays an edit image instead of the text spag:

@MvcHtmlString.Create(Ajax.ActionLink("Spag", "Edit", new { id = item.x0101EmployeeID }, new AjaxOptions() { UpdateTargetId = "selectDiv", InsertionMode = InsertionMode.Replace, HttpMethod = "GET" }).ToHtmlString().Replace("Spag", "<img src=\"" + Url.Content("../../Images/edit.png") + "\" />"))
Jplum
  • 1
0

Update for MVC3 using Templated Razor Delegates relies on T4Mvc,but brings so much power.

Based on various other answers on this page.

        public static HelperResult WrapInActionLink(this AjaxHelper helper,ActionResult result, Func<object,HelperResult> template,AjaxOptions options)
    {
        var link=helper.ActionLink("[replaceme]",result,options);
        var asString=link.ToString();
        var replaced=asString.Replace("[replaceme]",template(null).ToString());

        return new HelperResult(writer =>
        {
            writer.Write(replaced);
        });
    }

Allows:

@Ajax.WrapInActionLink(MVC.Deal.Details(deal.ID.Value),@<img alt='Edit deal details' src='@Links.Content.Images.edit_16_gif'/>, new AjaxOptions() { UpdateTargetId="indexDetails" })
Maslow
  • 18,464
  • 20
  • 106
  • 193
-1
actionName+"/"+routeValues Proje/ControlName/ActionName/Id




    using System.Web;
    using System.Web.Mvc;
    using System.Web.Mvc.Ajax;

    namespace MithatCanMvc.AjaxHelpers
{

    public static class ImageActionLinkHelper
    {
        public static IHtmlString ImageActionLink(this AjaxHelper helper, string imageUrl, string altText, string actionName, string routeValues, AjaxOptions ajaxOptions)
        {
            var builder = new TagBuilder("img");
            builder.MergeAttribute("src", imageUrl);
            builder.MergeAttribute("alt", altText);
            var link = helper.ActionLink("[replaceme]", actionName+"/"+routeValues, ajaxOptions).ToHtmlString();
            return MvcHtmlString.Create(link.Replace("[replaceme]", builder.ToString(TagRenderMode.SelfClosing)));

        }

    }

}
Liam
  • 27,717
  • 28
  • 128
  • 190
-2

I don't know, this seems easier to me:

    <a href="@Url.Action("index", "home")">
        <img src="~/Images/rocket.png" width="25" height="25" title="Launcher" />
    </a>