MVC3 Weird behavior of ActionLink with HTML 5 Data- attributes - asp.net-mvc

When I use this helper method to create a link, the data attribute shows up correctly in HTML code:
#Html.ActionLink("Test", "Index", null, new { data_something = "123" })
The HTML is correct:
<a data-something="123" href="/">Test</a>
When I use the following overload of the ActionLink method (I use the T4MVC script, http://mvccontrib.codeplex.com/wikipage?title=T4MVC), the data attribute contains an underscore instead of a dash:
#Html.ActionLink("Test", MVC.Home.Index(), new { data_something = "123" })
The HTML is incorrect:
<a data_something="123" href="/">Test</a>
Is this a know bug or a feature? I searched the bugtracker (http://aspnet.codeplex.com/workitem/list/basic) but was not able to find a corresponding issue.
The following overload is working again, but I don't like to create Dictonaries all the time:
#Html.ActionLink("Test", MVC.Home.Index(), new Dictionary<string, object> {
{ "data-something", "123" }
})

for data attribute use #data_something="123" like
#Html.ActionLink("Test link",
MVC.Home.Index(),
new {controller="Home"}},new {#data_something="123"})
the above code should output
Test Link>

Related

asp.net mvc optional params in razor actionLink

I have 2 links for language switch
<a class="dropdown-item"
href="#Url.Action(ViewContext.RouteData.Values["action"].ToString(), ViewContext.RouteData.Values["controller"].ToString(), new { language = "en" }, null)"
style="color:#333;">English</a>
<a class="dropdown-item"
href="#Url.Action(ViewContext.RouteData.Values["action"].ToString(), ViewContext.RouteData.Values["controller"].ToString(), new { language = "ar" }, null)"
style="color:#333;">Arabic</a>
it works fine there is only controller and action in url
but when there is optional param like id for detail and edit action than it do not work as expected.
I think I have to change null (this last param) with something but I am new and googled a lot but not getting anything worthy, Please help me.
It would be better if the solution work for n number of optional params instead of only one Id, but for now that will also be acceptable.
it would be better if the solution work for n number of optional params instead of only one Id
for getting all passed querystring parameter on MVC controller side better to use
Request.QueryString
Request.QueryString is NameValueCollection and you get value passed in querystring parameter in your actionlink.
i have tried that looks like below
<a class="dropdown-item" href="#Url.Action(ViewContext.RouteData.Values["action"].ToString(), ViewContext.RouteData.Values["controller"].ToString(), new { language = "ar",id="100",studentid = 1,studentName = "abc" }, null)" style="color:#333;">Arabic</a>
and your mvc Controller look like below
public ActionResult About(int id)
{
var querystring = Request.QueryString;
// in querystring you get all value like below screenshot
var studentName = querystring["studentName"]; // access parameter like
ViewBag.Message = "Your application description page.";
return View();
}
you can get all parameter that you passed in your controller.

Post a form with multiple partial views

I'm currently trying to post a form composed of two strongly typed views. This question is similar but it doesn't have an answer:
MVC 3 Razor Form Post w/ Multiple Strongly Typed Partial Views Not Binding
When I submit form the model submitted to the controller is always null. I've spent a couple of hours trying to get this to work. This seems like it should be simple. Am I missing something here? I don't need to do ajax just need to be able to post to the controller and render a new page.
Thanks
Here's my view code:
<div>
#using (Html.BeginForm("TransactionReport", "Reports", FormMethod.Post, new {id="report_request"}))
{
ViewContext.FormContext.ValidationSummaryId = "valSumId";
#Html.ValidationSummary(false, "Please fix these error(s) and try again.", new Dictionary<string, object> { { "id", "valSumId" } });
#Html.Partial("_ReportOptions", Model.ReportOptions);
#Html.Partial("_TransactionSearchFields", new ViewDataDictionary(viewData) { Model = Model.SearchCriteria });
}
Here's the code in the controller:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult TransactionReport(TransactionReportRequest reportRequest)
{
var reportInfo = new List<TransactionReportItem>();
if (ModelState.IsValid)
{
var reportData = _reportDataService.GetReportData(Search.MapToDomainSearchCriteria(reportRequest.SearchCriteria));
if (reportData!=null)
{
reportInfo = reportData.ToList();
}
return View(reportInfo);
}
return View(reportInfo);
}
The partial views themselves are pretty irrelevant since all they are doing is biding and displaying their models.
Partials are not the way to go here. You are looking for EditorTemplates, these are made for what you want. This case, your properties will be nicely bound to your model (that you will submit).
Your main View will have this form (note that you only have to use EditorFor instead of Partial; in this case, you probably will need to put that viewData parameter in the ViewBag or so):
#using (Html.BeginForm("TransactionReport", "Reports", FormMethod.Post, new {id="report_request"}))
{
ViewContext.FormContext.ValidationSummaryId = "valSumId";
#Html.ValidationSummary(false, "Please fix these error(s) and try again.", new Dictionary<string, object> { { "id", "valSumId" } });
#Html.EditorFor(model => model.ReportOptions);
#Html.EditorFor(model = Model.SearchCriteria });
}
Now you only have to drag your partials to the folder ~/Shared/EditorTemplates/ and rename them to match the model name they are the editor templates for.
In the ~/Shared/EditorTemplates/ folder, make a new "view", example "SearchCriteria.cshtml". Inside, put as "model" the type of class you which to create an editor template for. Example (example class has properties Name and OtherCriteria):
#model MyNamespace.SearchCriteria
<ul>
<!-- Note that I also use EditorFor for the properties; this way you can "nest" editor templates or create custom editor templates for system types (like DateTime or String or ...). -->
<li>#Html.LabelFor(m => m.Name): #Html.EditorFor(m => m.Name)</li>
<li>#Html.LabelFor(m => OtherCriteria): #Html.EditorFor(m => m.OtherCriteria</li>
</ul>
Some good reading about them:
https://www.exceptionnotfound.net/asp-net-mvc-demystified-display-and-editor-templates/
https://www.hanselman.com/blog/ASPNETMVCDisplayTemplateAndEditorTemplatesForEntityFrameworkDbGeographySpatialTypes.aspx
You should add prefix to the PartialView's fields. That will let binding data correctly.
So instead:
#Html.Partial("_ReportOptions", Model.ReportOptions);
Use:
#Html.Partial("_ReportOptions", Model.ReportOptions, new ViewDataDictionary { TemplateInfo = new TemplateInfo { HtmlFieldPrefix = "ReportOptions" }})
I agree with #Styxxy and #Tony, Editor Templates are the better solution. However, your problem is that that you are feeding a sub-model to the partial views. Thus, when the partial view renders it doesn't know that it's part of a larger model and does not generate the correct name attributes.
If you insist on using Partials rather than Editor Templates, then I suggest only passing the Model to the partials, then having each partial do Model.Whatever.Foo and it will generate the correct name attributes for binding.
Try using EditorTemplates instead of Partials http://coding-in.net/asp-net-mvc-3-how-to-use-editortemplates/.
#Html.Partial("_ReportOptions", Model.Contact, new ViewDataDictionary()
{
TemplateInfo = new TemplateInfo()
{
HtmlFieldPrefix = "Contact"
}
})
)
#Html.Partial("_TransactionSearchFields", Model.SearchCriteria, new
ViewDataDictionary()
{
TemplateInfo = new TemplateInfo()
{
HtmlFieldPrefix = "SearchCriteria"
}
})

How to render HtmlAttributes with object values using ASP.NET MVC 3 Razor?

I am trying to render the following HTML using an MVC3 Razor View:
<input id="EffectiveDate" name="EffectiveDate" type="date" data-options='{"mode": "flipbox"}' />
I have been unable to get the quotation marks in the data-options attribute to render. No matter what I try, they are rendered as "
Here are a couple of the many approaches I have tried in my View:
#Html.TextBoxFor(model => model.EffectiveDate, new { type = "date", data_options= " { 'mode':'flipbox' }"})
and
#Html.TextBoxFor(model => model.EffectiveDate, new { type = "date", data_options= #Html.Raw("{\"mode\":\"flipbox\"}")})
Any suggestions on how to decode the quotation marks?
You can do this by creating an MVC Editor template. First, create a folder called "EditorTemplates" inside the "Views\Shared" folder. Then put a file called DateTime.cshtml inside the EditorTemplates folder.
Then you can simply use the EditorFor() method against your view model's property like this (provided that the EffectiveDate property of of type DateTime):
#Html.EditorFor(m => m.EffectiveDate)
The complete code for the DateTime.cshtml editor template looks like this:
#model System.DateTime
#{
var id = this.ViewData.TemplateInfo.GetFullHtmlFieldId("");
var name = this.ViewData.TemplateInfo.GetFullHtmlFieldName("");
}
<input id="#id" name="#name" type="date" data-options='{"mode": "flipbox"}' />
This will produce the exact output that you are seeking.
One thing is certain: special symbols will always be encoded when you use any of the default MVC input extensions (i.e. TextBoxFor). That is because TagBuilder itself, which is used to build the tags for the HtmlHelper extensions, HtmlEncodes each attribute value in a tag. You can see this in the TagBuilder source:
private void AppendAttributes(StringBuilder sb)
{
foreach (var attribute in Attributes)
{
string key = attribute.Key;
if (String.Equals(key, "id", StringComparison.Ordinal /* case-sensitive */) && String.IsNullOrEmpty(attribute.Value))
{
continue; // DevDiv Bugs #227595: don't output empty IDs
}
string value = HttpUtility.HtmlAttributeEncode(attribute.Value);
sb.Append(' ')
.Append(key)
.Append("=\"")
.Append(value)
.Append('"');
}
}
Since you have no way to send that value already decoded, you have to decode it yourself in JavaScript. Here is a nice little jQuery trick that will do it:
var value = $('<textarea/>').html(yourElement.data('options')).val();
You might want to make a function for that, of course.
Sources:
http://aspnet.codeplex.com/
http://refresh-sf.com/blog/2009/05/decode-html-entities-with-jquery/

Adding a hyphen to the html attribute name using MVC3 WebGrid helper

I'm having a problem trying to add a custom HTML5 data attribute to the table that is rendered using the WebGrid helper. I want the table tag look as follows:
<table data-test="testdata"><!-- Table Content --></table>
Here is a sample view using the Razor view engine:
#{
var myUser = new
{
Id = 1,
Name = "Test User"
};
var users = new[] { myUser };
var grid = new WebGrid(users);
}
#grid.GetHtml(htmlAttributes: new { data-test = "testdata"})
The last line will produce a "Invalid anonymous type member declarator." error, because of the hyphen in data-test.
With some of the other input HtmlHelpers, you can use an underscore in place of the hyphen and it will be automatically changed to a hyphen when rendered. This does not happen with the WebGrid.
If I pass in a dictionary for htmlAttributes:
#grid.GetHtml(htmlAttributes: new Dictionary<string, object> {{ "data-test", "testdata"}})
the table gets rendered as such:
<table Comparer="System.Collections.Generic.GenericEqualityComparer`1[System.String]" Count="1" Keys="System.Collections.Generic.Dictionary`2+KeyCollection[System.String,System.Object]" Values="System.Collections.Generic.Dictionary`2+ValueCollection[System.String,System.Object]"><!-- Table Content --></table>
What am I doing wrong and what should I do render the attribute as desired?
I am afraid that this is not possible. Unfortunately the WebGrid it doesn't support the same syntax as standard HTML helper such as TextBoxFor where you could:
#Html.TextBoxFor(x => x.SomeProp, new { data_test = "testdata" })
and the underscore would be automatically converted to dash.

ASP.NET MVC HtmlHelper.ActionLink replace %20 with +

If I have a url generated like this
<%=Html.ActionLink("Link name", "MyAction", "MyController", new { SomeParameter = "value with spaces" })%>
is it possible to easily generate the output html like so
<a href="/MyController/MyAction/value+with+spaces">
instead of
<a href="/MyController/MyAction/value%20with%20spaces">
Or am I best looking at overloading the ActionLink method and replacing those characters when returning the string?
Or am I best looking at overloading
the ActionLink method and replacing
those characters when returning the
string?
Yes.
The easier way is to just make a space-dash replacer extension method. Or just call Replace manually.
<%=Html.ActionLink("Link name", "MyAction", "MyController", new { SomeParameter = "value with spaces".Replace(" ", "-" })%>

Resources