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.
Related
I want to upload image using Ajax.BeginForm in my application.
Currently HttpPostedFileBase file is getting value 0. Anyone Please guide me here.
I have tried this code but file is not uploading.
Appreciated, if anyone can provide some solutions for this. If I use #Html.BeginForm then It works but I want to use #Ajax.BeginForm.
Model
public class ClsUpload
{
public string FilePath { get; set; }
}
Controller
public ActionResult Edit(ClsUpload model,HttpPostedFileBase file)
{
if (Request.Files.Count > 0)
{
file = Request.Files[0];
if (file != null && file.ContentLength > 0)
{
string fileName = Path.GetFileName(file.FileName);
string path = Path.Combine(Server.MapPath("/Content/Images/"), fileName);
file.SaveAs(path);
model.FilePath = path;
}
}
try
{
UploadDetials details = new UploadDetials();
details.UpdateDetails(model);
return RedirectToAction("Index");
}
catch
{
return RedirectToAction("Index");
}
}
Partial View
#model XX.X.Models.File.ClsUpload
#using (Ajax.BeginForm(new AjaxOptions { UpdateTargetId = "partial", InsertionMode = InsertionMode.Replace }))
{
#Html.HiddenFor(model => model.FilePath)
<input type="file" name="file" />
<img src=#Model.FilePath alt="Image" />
<input type="submit" value="Save" />
}
You can update your code with FormMethod.Post, new { enctype = "multipart/form-data" }) and [AcceptVerbs(HttpVerbs.Post)] as follow
In Partial View
#using (Html.BeginForm("ActionMethod1", "Controller", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
}
In Controller
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ActionMethod1(HttpPostedFileBase pic)
{
}
This is old, but I want to show how I have accomplished uploading a file using Ajax.BeginForm(). Basically, the overloads will tell you what is possible. I use the overload for: "string actionName, string controllerName, object routeValues, AjaxOptions ajaxOptions, object htmlAttributes". Note: I use null for "routeValues".
Here is a code example:
#using (Ajax.BeginForm("UploadFile", "Home", null, new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "MyIDToUpdate", OnSuccess = "EditSuccessClearForm('IDToClear', '')", OnFailure = String.Format("NewGenericFailure(xhr, '{0}')", "#IDToPassThisFunction"), InsertionMode = InsertionMode.ReplaceWith }, new { enctype = "multipart/form-data", #id = "NewFileFormID" }))
{
#Html.AntiForgeryToken()
<div class="row">
<div class="col-sm-8 col-sm-offset-1">
#Html.TextBox("file", "", new { type = "file", accept = ".jpg, .jpeg, .png, .pdf", #id = fileID, onchange = VerifySizeOfFile })
</div>
<div class="col-sm-2">
<button type="submit" id="FileSubmitButton" class="btn btn-primary">Upload</button>
</div>
</div>
}
How can I pass NextPrevious value to controller?
Now NextPrevious is getting always null
[HttpPost]
public ActionResult PremiumUserRegistration(PartnersVM partnersVM, string NextPrevious)
{
if (NextPrevious != null)
{
}
}
View And .js file,
$('.btnActionNext').click(function () {
$(this).closest('form')[0].submit();
});
#Html.ActionLink("Next >>", "PremiumUserRegistration", new { controller = "UserRegister" }, new { NextPrevious = "value", #class = "btnActionNext" , onclick = "return false;" })
Please help me...
Add a hidden:
<input type="hidden" name="Action" />
Make sure it's on your form. Next, on your click handler, do:
$('.btnActionNext').click(function () {
$("#Action").val("NEXT");
$(this).closest('form')[0].submit();
});
In your post action, add string Action:
[HttpPost]
public ActionResult PremiumUserRegistration(string Action, PartnersVM partnersVM)
{
if (Action == "NEXT")
{
}
}
If you are submitting a form, then add it as a hidden field
#Html.Hidden("NextPrevious", value)
Otherwise, you entered the "NextPrevious" value in the wrong spot in the ActionLink method. It should be within routeValues, not htmlAttributes.
The correct way would be:
#Html.ActionLink("Next >>", "PremiumUserRegistration", new { controller = "UserRegister", NextPrevious = "value" }, new { #class = "btnActionNext", onclick = "return false;" })
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()
)
)
...
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" })
I am trying to use HTML5 data- attributes in my ASP.NET MVC 1 project. (I am a C# and ASP.NET MVC newbie.)
<%= Html.ActionLink("« Previous", "Search",
new { keyword = Model.Keyword, page = Model.currPage - 1},
new { #class = "prev", data-details = "Some Details" })%>
The "data-details" in the above htmlAttributes give the following error:
CS0746: Invalid anonymous type member declarator. Anonymous type members
must be declared with a member assignment, simple name or member access.
It works when I use data_details, but I guess it need to be starting with "data-" as per the spec.
My questions:
Is there any way to get this working and use HTML5 data attributes with Html.ActionLink or similar Html helpers ?
Is there any other alternative mechanism to attach custom data to an element? This data is to be processed later by JS.
This problem has been addressed in ASP.Net MVC 3. They now automatically convert underscores in html attribute properties to dashes. They got lucky on this one, as underscores are not legal in html attributes, so MVC can confidently imply that you'd like a dash when you use an underscore.
For example:
#Html.TextBoxFor(vm => vm.City, new { data_bind = "foo" })
will render this in MVC 3:
<input data-bind="foo" id="City" name="City" type="text" value="" />
If you're still using an older version of MVC, you can mimic what MVC 3 is doing by creating this static method that I borrowed from MVC3's source code:
public class Foo {
public static RouteValueDictionary AnonymousObjectToHtmlAttributes(object htmlAttributes) {
RouteValueDictionary result = new RouteValueDictionary();
if (htmlAttributes != null) {
foreach (System.ComponentModel.PropertyDescriptor property in System.ComponentModel.TypeDescriptor.GetProperties(htmlAttributes)) {
result.Add(property.Name.Replace('_', '-'), property.GetValue(htmlAttributes));
}
}
return result;
}
}
And then you can use it like this:
<%: Html.TextBoxFor(vm => vm.City, Foo.AnonymousObjectToHtmlAttributes(new { data_bind = "foo" })) %>
and this will render the correct data-* attribute:
<input data-bind="foo" id="City" name="City" type="text" value="" />
Update: MVC 3 and newer versions have built-in support for this. See JohnnyO's highly upvoted answer below for recommended solutions.
I do not think there are any immediate helpers for achieving this, but I do have two ideas for you to try:
// 1: pass dictionary instead of anonymous object
<%= Html.ActionLink( "back", "Search",
new { keyword = Model.Keyword, page = Model.currPage - 1},
new Dictionary<string,Object> { {"class","prev"}, {"data-details","yada"} } )%>
// 2: pass custom type decorated with descriptor attributes
public class CustomArgs
{
public CustomArgs( string className, string dataDetails ) { ... }
[DisplayName("class")]
public string Class { get; set; }
[DisplayName("data-details")]
public string DataDetails { get; set; }
}
<%= Html.ActionLink( "back", "Search",
new { keyword = Model.Keyword, page = Model.currPage - 1},
new CustomArgs( "prev", "yada" ) )%>
Just ideas, haven't tested it.
It's even easier than everything suggested above.
Data attributes in MVC which include dashes (-) are catered for with the use of underscore (_).
<%= Html.ActionLink("« Previous", "Search",
new { keyword = Model.Keyword, page = Model.currPage - 1},
new { #class = "prev", data_details = "Some Details" })%>
I see JohnnyO already mentioned this.
In mvc 4 Could be rendered with Underscore(" _ ")
Razor:
#Html.ActionLink("Vote", "#", new { id = item.FileId, }, new { #class = "votes", data_fid = item.FileId, data_jid = item.JudgeID, })
Rendered Html
<a class="votes" data-fid="18587" data-jid="9" href="/Home/%23/18587">Vote</a>
You can implement this with a new Html helper extension function which will then be used similarly to the existing ActionLinks.
public static MvcHtmlString ActionLinkHtml5Data(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes, object htmlDataAttributes)
{
if (string.IsNullOrEmpty(linkText))
{
throw new ArgumentException(string.Empty, "linkText");
}
var html = new RouteValueDictionary(htmlAttributes);
var data = new RouteValueDictionary(htmlDataAttributes);
foreach (var attributes in data)
{
html.Add(string.Format("data-{0}", attributes.Key), attributes.Value);
}
return MvcHtmlString.Create(HtmlHelper.GenerateLink(htmlHelper.ViewContext.RequestContext, htmlHelper.RouteCollection, linkText, null, actionName, controllerName, new RouteValueDictionary(routeValues), html));
}
And you call it like so ...
<%: Html.ActionLinkHtml5Data("link display", "Action", "Controller", new { id = Model.Id }, new { #class="link" }, new { extra = "some extra info" }) %>
Simples :-)
edit
bit more of a write up here
I ended up using a normal hyperlink along with Url.Action, as in:
<a href='<%= Url.Action("Show", new { controller = "Browse", id = node.Id }) %>'
data-nodeId='<%= node.Id %>'>
<%: node.Name %>
</a>
It's uglier, but you've got a little more control over the a tag, which is sometimes useful in heavily AJAXified sites.
HTH
I do not like use pure "a" tag, too much typing. So I come with solution.
In view it look
<%: Html.ActionLink(node.Name, "Show", "Browse",
Dic.Route("id", node.Id), Dic.New("data-nodeId", node.Id)) %>
Implementation of Dic class
public static class Dic
{
public static Dictionary<string, object> New(params object[] attrs)
{
var res = new Dictionary<string, object>();
for (var i = 0; i < attrs.Length; i = i + 2)
res.Add(attrs[i].ToString(), attrs[i + 1]);
return res;
}
public static RouteValueDictionary Route(params object[] attrs)
{
return new RouteValueDictionary(Dic.New(attrs));
}
}
You can use it like this:
In Mvc:
#Html.TextBoxFor(x=>x.Id,new{#data_val_number="10"});
In Html:
<input type="text" name="Id" data_val_number="10"/>