I have a WebGrid definition and three links in a single column by using Html.ActionLink. But, when I do not use "LinkText" property, the applicantId property is passed as null value to the Controller.
On the other hand, when just using LinkTexts instead of " ", the id parameters can be passed successfully (Types as "My Link Text" below). However, I do not want to display text on the link and I just wanted to display Image.
I think there might be a typing mistake or there would be another ways suitable for MVC4 Razor like #Url.Action, etc. Here is my code in Razor View.
Could you help me please?
Thanks in advance.
View:
//for using multiple Html.ActionLink in a column using Webgrid
grid.Column("Operations", format: (item) =>
new HtmlString(
Html.ActionLink("My Link Text", "Edit", "Admin", new
{
applicantId = item.ApplicantID,
title = "Detail",
#class = "icon-link",
style = "background-image: url('../../Content/icons/detail.png')"
}, null).ToString() +
Html.ActionLink(" ", "Edit", "Admin", new
{
applicantId = item.ApplicantID,
title = "Edit",
#class = "icon-link",
style = "background-image: url('../../Content/icons/edit.png')"
}, null).ToString() +
Html.ActionLink(" ", "Edit", "Admin", new
{
applicantId = item.ApplicantID,
title = "Delete",
#class = "icon-link",
style = "background-image: url('../../Content/icons/delete.png')"
}, null).ToString()
)
)
<style type="text/css">
a.icon-link {
background-color: transparent;
background-repeat: no-repeat;
background-position: 0px 0px;
border: none;
cursor: pointer;
width: 16px;
height: 16px;
margin-right: 8px;
vertical-align: middle;
}
</style>
Your Action Links are not being called correctly. You are adding the Html Attributes to your Route Values. Your Action Links should look like this:
Html.ActionLink("My Link Text", "Detail", "Admin", new
{
applicantId = item.ApplicantID
}, new
{
title = "Detail",
#class = "icon-link"
})
Check this link to see how you can hide the link text, and display an image instead using css: CSS Hide Text But Show Image?
You could use custom HTML Helper method in order to use it easily. To do this:
Create a folder called HtmlHelpers and create a class named MyHelpers in this folder. Then define your class like below (you might improve it by adding some extra properties).
MyHelpers.cs:
using System;
using System.Web.Mvc;
namespace <YourProjectName>.WebUI.HtmlHelpers
{
public static class MyHelpers
{
public static MvcHtmlString ImageLink(this HtmlHelper html, string imagePath, string alt, string cssClass,
string action, string controllerName)
{
return ActionImage(html, imagePath, alt, cssClass, action, controllerName, null);
}
public static MvcHtmlString ImageLink(this HtmlHelper html, string imagePath, string alt, string cssClass,
string action, string controllerName, object routeValues)
{
var currentUrl = new UrlHelper(html.ViewContext.RequestContext);
var imgTagBuilder = new TagBuilder("img"); // build the <img> tag
imgTagBuilder.MergeAttribute("src", currentUrl.Content(imagePath));
imgTagBuilder.MergeAttribute("title", alt);
imgTagBuilder.MergeAttribute("class", cssClass);
string imgHtml = imgTagBuilder.ToString(TagRenderMode.SelfClosing);
var anchorTagBuilder = new TagBuilder("a"); // build the <a> tag
anchorTagBuilder.MergeAttribute("href", currentUrl.Action(action, controllerName, routeValues));
anchorTagBuilder.InnerHtml = imgHtml; // include the <img> tag inside
string anchorHtml = anchorTagBuilder.ToString(TagRenderMode.Normal);
return MvcHtmlString.Create(anchorHtml);
}
}
}
Rebuild your project and then add this line to your Razor View:
#using .WebUI.HtmlHelpers
Then use this Html Helper method in your View like this:
#Html.ImageLink("../../Content/icons/delete.png", "Delete", "your-class", "Delete", "Admin", new { item.ApplicantID })
Smilarly, if you want to use multi image link in the same column you can merge html strings like that:
View:
....
grid.Column("Operations", style: "your-class", format: (item) =>
new HtmlString(
#Html.ActionImage("../../Content/icons/detail.png", "Detail", "your-class", "Detail", "Admin", new { item.ApplicantID }).ToString() +
#Html.ActionImage("../../Content/icons/edit.png", "Edit", "your-class", "Edit", "Admin", new { item.ApplicantID }).ToString() +
#Html.ActionImage("../../Content/icons/delete.png", "Delete", "your-class", "Delete", "Admin", new { item.ApplicantID }).ToString()
)
)
...
Related
Is it possible to pass an hidden field value from Razor View to Controller inside or tag? As the field is hidden, it is really a problem to pass its value to the Controller. On the other hand I think the only way to pass this hidden field is using input field inside hyperlink. How to create a code like below?
<a href="/Admin/Delete?ApplicantID=44">
<img class="myclass" src="../../Content/delete.png" title="Delete" />
<input type="hidden" value= "Delete" /></a>
Updates
View:
...
grid.Column("Actions", format: (item) =>
new HtmlString(
#Html.ActionImage("../../Content/detail.png", "Detail", "icon-link", "Detail", "Admin", new { applicantId = item.ApplicantID }).ToString() +
#Html.ActionImage("../../Content/edit.png", "Edit", "icon-link", "Edit", "Admin", new { applicantId = item.ApplicantID }).ToString() +
#Html.ActionImage("../../Content/delete.png", "Delete", "icon-link", "Delete", "Admin", new { applicantId = item.ApplicantID }).ToString()
)
)
...
Controller:
[HttpPost]
public ActionResult Delete(int applicantId)
{
Applicant deletedApplicant = repository.DeleteApplicant(applicantId);
if (deletedApplicant != null)
{
TempData["message"] = string.Format("{0} was deleted",
deletedApplicant.Name);
}
return RedirectToAction("Index");
}
}
Helper Method:
public static MvcHtmlString ActionImage(this HtmlHelper html, string imagePath, string alt, string cssClass,
string action, string controllerName, object routeValues)
{
var currentUrl = new UrlHelper(html.ViewContext.RequestContext);
var imgTagBuilder = new TagBuilder("img");
imgTagBuilder.MergeAttribute("src", currentUrl.Content(imagePath));
imgTagBuilder.MergeAttribute("title", alt);
imgTagBuilder.MergeAttribute("class", cssClass);
string imgHtml = imgTagBuilder.ToString(TagRenderMode.SelfClosing);
var anchorTagBuilder = new TagBuilder("a");
anchorTagBuilder.MergeAttribute("href", currentUrl.Action(action, controllerName, routeValues));
anchorTagBuilder.InnerHtml = imgHtml;
string anchorHtml = anchorTagBuilder.ToString(TagRenderMode.Normal);
return MvcHtmlString.Create(anchorHtml);
}
<input>, <textarea>, <button> and <select> element values are only passed during a form submission. Moreover, they are only passed on when assigned a name attribute.
Clicking an anchor will not pass these values (unless you interject with some JavaScript and append it to the URL). The easiest method is to turn your link in to a mini form:
#using (Html.BeginForm("Delete", "Admin", FormMethod.POST,
new { ApplicantID = #Model.ApplicantID }))
{
<!-- make sure to give this field a name -->
<input type="hidden" name="???" value="Delete" />
<input type="image" src="#Url.Content("~/Content/delete.png")" title="Delete" />
}
Otherwise, use javascript and bind to the anchor's click event and inject the hidden input's value before proceeding.
Based on discussion below, try this.
#Ajax.ActionLink("Delete",
"Delete", new { applicantid = item.applicantid },
new AjaxOptions
{
Confirm = "Delete?",
HttpMethod = "POST",
}, new { #class = "classname" })
a.classname
{
background: url(~/Content/delete.png) no-repeat top left;
display: block;
width: 150px;
height: 150px;
text-indent: -9999px; /* hides the link text */
}
NOTE: this does not need to be inside a form.
<li class="rtsLI" id="Summary"><span class="rtsTxt">Test</span></li>
Above I am replacing with following actionlink:
<li class="rtsLI" >#Html.ActionLink("test1", "Index", new { Area = "Area1", Controller = "controller1" }, new { #class = "rtsLink rtsTxt"})</li> "
At first css is working fine. But when using Actionlink, css not working. Thanks
The standard ActionLink helper always HTML encodes the link text. This means that you cannot use it if you want to render HTML inside. You have 3 possibilities:
Modify your CSS so that you don't need a span inside the link and so that the rtsTxt class could directly be applied to the link
Write a custom ActionLink helper that doesn't HTML encode the text and which would allow you to generate the same markup:
public static class ActionLinkExtensions
{
public static IHtmlString ActionLinkUnencoded(
this HtmlHelper htmlHelper,
string linkText,
string actionName,
object routeValues,
object htmlAttributes
)
{
var urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext);
var link = new TagBuilder("a");
link.MergeAttributes(new RouteValueDictionary(htmlAttributes));
link.Attributes["href"] = urlHelper.Action(actionName, routeValues);
link.InnerHtml = linkText;
return new HtmlString(link.ToString());
}
}
and then:
<li>
#Html.ActionLinkUnencoded(
"<span class=\"rtsTxt\">User Security</span>",
"index",
new { area = "Tools", controller = "UserSecurity" },
new { #class = "rtsLink" }
)
</li>
Use the Url.Action helper:
<li class="rtsLI">
<a href="#Url.Action("index", new { area = "Tools", controller = "UserSecurity" })" class="rtsLink">
<span class="rtsTxt">User Security</span>
</a>
</li>
Best option will be to use #Url.Action extension method
<li class="rtsLI" id="Summary"><span class="rtsTxt">User Security</span></li>
Write code this way:
<li class="rtsLI" >#Html.ActionLink("<span class='rtsTxt'>User Security</span>", "Index", new { Area = "Tools", Controller = "UserSecurity" }, new { #class = "rtsLink"})</li>`
i have an ajax actionlink like this:
<div style="float:left"> #Ajax.ActionLink("EMPLOYEE", "_PartialEmployeeIndex", "Employee", new AjaxOptions() { UpdateTargetId = "divToUpdate" }) </div>
i usually use bootstrap to style my buttons like this:
<input class="btn btn-info" type="button" value="Input">
or like this
<button class="btn btn-success" type="submit"> </button>
so how can i convert an ajax action link to a bootstrap button?
i dont want to put a class name to the div containing the ajax actionlink because the button is displayed with black color font and with an underline...
i want it to be displayed as an actual button with no underline and with white font
You should be able to use the htmlAttributes parameter to add whatever Bootstrap class you want:
#Ajax.ActionLink("EMPLOYEE", "_PartialEmployeeIndex", "Employee", new AjaxOptions() { UpdateTargetId = "divToUpdate" }, new { #class = "btn" })
If you only want an icon you can do it as:
#Ajax.ActionLink(" ", "Delete", new { id = 1 }, new AjaxOptions
{
Confirm = "Are you sure you wish to delete?",
HttpMethod = "Delete",
InsertionMode = InsertionMode.Replace,
LoadingElementId = "div_loading"
}, new { #class = "glyphicon glyphicon-trash" })
The name ationlink cannot be null or empty, so i recommended an space.
If you want an actual Ajax button element, rather than a styling hack, it is also possible but a little involved. It is a shame that MS has not yet chosen to add an ActionButton to both the Html and Ajax helpers as the differences are actually very minor when you remove the duplication of private support methods (you would only need the ActionButton and GenerateButton methods shown below).
The end result is you can have real buttons that trigger like ajax action links:
e.g.
#Ajax.ActionButton("Delete", "Delete", "document",
new { id = ViewBag.Id },
new AjaxOptions()
{
Confirm="Do you really want to delete this file?",
HttpMethod = "Get",
UpdateTargetId = "documentlist" },
new { id = "RefreshDocuments"
})
1. Create an AjaxHelper extension
The code below is based on a decompile of the AjaxExtensions class as many of the required helper methods are not exposed on HtmlHelper.
public static partial class AjaxExtensions
{
public static MvcHtmlString ActionButton(this AjaxHelper ajaxHelper, string buttonText, string actionName, string controllerName, object routeValuesBlah, AjaxOptions ajaxOptions, object htmlAttributesBlah)
{
// Convert generic objects to specific collections
RouteValueDictionary routeValues = new RouteValueDictionary(routeValuesBlah);
RouteValueDictionary htmlAttributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributesBlah);
if (string.IsNullOrEmpty(buttonText))
throw new ArgumentException("Button text must be provided");
string targetUrl = UrlHelper.GenerateUrl((string)null, actionName, controllerName, routeValues, ajaxHelper.RouteCollection, ajaxHelper.ViewContext.RequestContext, true);
return MvcHtmlString.Create(GenerateButton(ajaxHelper, buttonText, targetUrl, AjaxExtensions.GetAjaxOptions(ajaxOptions), htmlAttributes));
}
public static string GenerateButton(AjaxHelper ajaxHelper, string linkText, string targetUrl, AjaxOptions ajaxOptions, IDictionary<string, object> htmlAttributes)
{
TagBuilder tagBuilder = new TagBuilder("input");
tagBuilder.MergeAttribute("value", linkText);
tagBuilder.MergeAttributes<string, object>(htmlAttributes);
tagBuilder.MergeAttribute("href", targetUrl);
tagBuilder.MergeAttribute("type", "button");
if (ajaxHelper.ViewContext.UnobtrusiveJavaScriptEnabled)
tagBuilder.MergeAttributes<string, object>(ajaxOptions.ToUnobtrusiveHtmlAttributes());
else
tagBuilder.MergeAttribute("onclick", AjaxExtensions.GenerateAjaxScript(ajaxOptions, "Sys.Mvc.AsyncHyperlink.handleClick(this, new Sys.UI.DomEvent(event), {0});"));
return tagBuilder.ToString(TagRenderMode.Normal);
}
private static string GenerateAjaxScript(AjaxOptions ajaxOptions, string scriptFormat)
{
string str = ajaxOptions.ToJavascriptString();
return string.Format((IFormatProvider)CultureInfo.InvariantCulture, scriptFormat, new object[1] { str });
}
private static AjaxOptions GetAjaxOptions(AjaxOptions ajaxOptions)
{
if (ajaxOptions == null)
return new AjaxOptions();
else
return ajaxOptions;
}
public static string ToJavascriptString(this AjaxOptions ajaxOptions)
{
StringBuilder stringBuilder = new StringBuilder("{");
stringBuilder.Append(string.Format((IFormatProvider)CultureInfo.InvariantCulture, " insertionMode: {0},", new object[1]
{
ajaxOptions.InsertionModeString()
}));
stringBuilder.Append(ajaxOptions.PropertyStringIfSpecified("confirm", ajaxOptions.Confirm));
stringBuilder.Append(ajaxOptions.PropertyStringIfSpecified("httpMethod", ajaxOptions.HttpMethod));
stringBuilder.Append(ajaxOptions.PropertyStringIfSpecified("loadingElementId", ajaxOptions.LoadingElementId));
stringBuilder.Append(ajaxOptions.PropertyStringIfSpecified("updateTargetId", ajaxOptions.UpdateTargetId));
stringBuilder.Append(ajaxOptions.PropertyStringIfSpecified("url", ajaxOptions.Url));
stringBuilder.Append(ajaxOptions.EventStringIfSpecified("onBegin", ajaxOptions.OnBegin));
stringBuilder.Append(ajaxOptions.EventStringIfSpecified("onComplete", ajaxOptions.OnComplete));
stringBuilder.Append(ajaxOptions.EventStringIfSpecified("onFailure", ajaxOptions.OnFailure));
stringBuilder.Append(ajaxOptions.EventStringIfSpecified("onSuccess", ajaxOptions.OnSuccess));
--stringBuilder.Length;
stringBuilder.Append(" }");
return ((object)stringBuilder).ToString();
}
public static string InsertionModeString(this AjaxOptions ajaxOptions)
{
switch (ajaxOptions.InsertionMode)
{
case InsertionMode.Replace:
return "Sys.Mvc.InsertionMode.replace";
case InsertionMode.InsertBefore:
return "Sys.Mvc.InsertionMode.insertBefore";
case InsertionMode.InsertAfter:
return "Sys.Mvc.InsertionMode.insertAfter";
default:
return ((int)ajaxOptions.InsertionMode).ToString((IFormatProvider)CultureInfo.InvariantCulture);
}
}
public static string EventStringIfSpecified(this AjaxOptions ajaxOptions, string propertyName, string handler)
{
if (string.IsNullOrEmpty(handler))
return string.Empty;
return string.Format((IFormatProvider)CultureInfo.InvariantCulture, " {0}: Function.createDelegate(this, {1}),",
new object[2]
{
propertyName,
handler
});
}
public static string PropertyStringIfSpecified(this AjaxOptions ajaxOptions, string propertyName, string propertyValue)
{
if (string.IsNullOrEmpty(propertyValue))
return string.Empty;
string str = propertyValue.Replace("'", "\\'");
return string.Format((IFormatProvider)CultureInfo.InvariantCulture, " {0}: '{1}',",
new object[2]
{
propertyName,
str
});
}
}
2. Modify jquery.unobtrusive-ajax.js
Only a small change is required to the JQuery of jquery.unobtrusive-ajax.js to accept the new button object, as it is very close to begin with. First the selector needs to accept buttons as well as links and then the href needs to come from an attribute so than a non-link can provide it (not strictly browser compliant but works for now).
$(document).on("click", "input[data-ajax=true],a[data-ajax=true]", function (evt) {
evt.preventDefault();
asyncRequest(this, {
url: $(this).attr("href"),
type: "GET",
data: []
});
});
*Note: this is using the latest version of everything as at the date of answering (MVC 5)
if you do not want to worry about assigning proper classes to every Bootstrap element, check out TwitterBootstrapMVC
In the example with your ajax link you'd write something like this:
#Ajax.ActionLink("EMPLOYEE", "_PartialEmployeeIndex", "Employee", ).AjaxOptions(new AjaxOptions() { UpdateTargetId = "divToUpdate" })
Adding to Terry answer, if you want to add html to the button, the best way is to use Javascript to append the html code. The linkText parameter of Ajax.Actionlink automatically encodes any text you provide and there is nothing you can do to avoid that (except writing your own helper).
Something like JQuery append or prepend would work.
<div>
#Ajax.ActionLink("EMPLOYEE", "_PartialEmployeeIndex", "Employee", new AjaxOptions() { UpdateTargetId = "divToUpdate" }, new { #class = "btn btn-default my-custom-class" })
</div>
<script>
$(".my-custom-class").prepend("<span class=\"glyphicon glyphicon-pencil\"></span> ");
</script>
An alternative is to use Ajax.BeginForm, which allows you to enter HTML directly. This assumes that you're not already in a form.
#using (Ajax.BeginForm("EMPLOYEE", "_PartialEmployeeIndex", "Employee", new AjaxOptions() { UpdateTargetId = "divToUpdate" }))
{
<button type="submit" id="EmployeeButton" title="Employee" aria-label="Employee Button">
<span class="glyphicon glyphicon-trash"></span>
</button>
}
#Ajax.ActionLink(" ", "EditUser/" + Model.Id, null, new AjaxOptions {
OnSuccess = "userEditGet",
HttpMethod = "post",
LoadingElementId = "ajaxLoader" }
,new { #class = "btn btn-default glyphicon glyphicon-edit" })
Is there anything wrong with this html? I want to have a link in the masterpage to navigate to "CreateParts" view. I have action 'CreateParts' which have a parameter parentPartId in the controller 'PartList'.
<li id="taskAdminPartCreate" runat="server">
<%= Html.ActionLink("Create New Part", "CreateParts", "PartList", new { parentPartId = 0 })%></li>
My controller action is like
public ActionResult CreateParts(int parentPartId)
{
HSPartList objHSPart = new HSPartList();
objHSPart.Id = parentPartId;
return View(objHSPart);
}
When I click on 'Create New Part' in the menu in SiteMaster, I get exception. Please help me out of this.
You are using incorrect overload. You should use this overload
public static MvcHtmlString ActionLink(
this HtmlHelper htmlHelper,
string linkText,
string actionName,
string controllerName,
Object routeValues,
Object htmlAttributes
)
And the correct code would be
<%= Html.ActionLink("Create New Part", "CreateParts", "PartList", new { parentPartId = 0 }, null)%>
Note that extra parameter at the end.
For the other overloads, visit LinkExtensions.ActionLink Method. As you can see there is no string, string, string, object overload that you are trying to use.
You are using the incorrect overload of ActionLink. Try this
<%= Html.ActionLink("Create New Part", "CreateParts", "PartList", new { parentPartId = 0 }, null)%>
Addition to the accepted answer:
if you are going to use
#Html.ActionLink("LinkName", "ActionName", "ControllerName", new { #id = idValue, #secondParam= = 2 },null)
this will create actionlink where you can't create new custom attribute or style for the link.
However, the 4th parameter in ActionLink extension will solve that problem. Use the 4th parameter for customization in your way.
#Html.ActionLink("LinkName", "ActionName", "ControllerName", new { #id = idValue, #secondParam= = 2 }, new { #class = "btn btn-info", #target = "_blank" })
I have this code and would like to add a class to the link. Is it possible to do this in MVC3?
Html.ActionLink("Create New", "Create")
Yes, you can just add another parameter with object representing css class:
Html.ActionLink("Create New", "Create", CONTROLLERNAME, null, new { #class= "yourCSSclass"} )
It can be translated to:
Html.ActionLink(link text, action name, controller name, route values object, html attributes object)
Edit:
To add custom styles, use this:
Html.ActionLink(
"Create New",
"Create",
CONTROLLERNAME,
null,
new { #class= "yourCSSclass", #style= "width:100px; color: red;" }
)
#Html.ActionLink("ClickMe", // link text
"Index", // action name
"Home", // controller
new { id = 2131 }, // (optional) route values
new { #class = "someClass" }) // html attributes
Html.ActionLink("Create New", "Create", null, htmlAttributes: new { #class = "className" })
You can use the ActionLink overload which takes an htmlAttributes parameter to add a class to the generated element:
Html.ActionLink("Create New", "Create", new {}, new { #class = cssClass });
According to the documentation, this should do the trick:
Html.ActionLink("LinkText", "Action", "Controller", new { }, new {#class="css class"})
Edit: Thanks for noticing Dampe, I updated the code sample.