How do you add a RouteValueDictionary to a T4MVC ActionLink - asp.net-mvc

There seems to be no extension method to include some arbitrary route values that normally I would expect to go into the querystring.
Old code:
<%: Html.ActionLink(Model.ParentMessage.Category.Text, "index", null, new { category = Model.ParentMessage.CategoryID }, new { })%>
I want to change it to this but it takes the category as an HTML attribute.
<%: Html.ActionLink(Model.ParentMessage.Category.Text, MVC.Feedback.Index(), new { category = Model.ParentMessage.CategoryID })%>
Just checking this isn't already possible before I write my own extension method as surely this was already accounted for?

Yes, it's there! :) See the doc (http://mvccontrib.codeplex.com/wikipage?title=T4MVC_doc). Look for "Adding additional route parameters".
e.g. either:
<%: Html.ActionLink(Model.ParentMessage.Category.Text, MVC.Feedback.Index().AddRouteValue(category, Model.ParentMessage.CategoryID))%>
or
<%: Html.ActionLink(Model.ParentMessage.Category.Text, MVC.Feedback.Index().AddRouteValues(new { category = Model.ParentMessage.CategoryID }))%>

Related

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 do I append a variable to a string in an ActionLink?

I keep getting a Compilation Error and can't find matching overloaded method. I've tried a couple ways (variable, variable.toString). Below is the latest try.
When I click on the day (ex: 2) on the calendar the ActionLink should send the querystring: "Index?day=2".
#{ string dayAsString = startCount.ToString();}
<div><span>#Html.ActionLink(#startCount.ToString, "Index?day=" + dayAsString , "Event")</span></div>
Do this
<div>
<span>
#Html.ActionLink(startCount.ToString(), "Index", new { day = startCount })
</span>
</div>
The last parameter creates an anonymous object with the property day and value startCount. ActionLink knows to convert that into a querystring using the property name and the property value.
More details here http://msdn.microsoft.com/en-us/library/dd492936.aspx
Edit:
If you want to target a specific controller, do this
#Html.ActionLink(startCount.ToString(), "Index", new { controller = "Event", day = startCount })
You can also do this
#Html.ActionLink(startCount.ToString(), "Index", "Event", new { day = startCount }, null)
but I don't like passing null as a parameter.
Here's a list of all the overloads: http://msdn.microsoft.com/en-us/library/dd505040.aspx
You can also just cycle in the intellisense.
This should work
#Html.ActionLink(#startCount.ToString,"Index","Yourcontroller",new { day=#startCount.ToString()} , null)
replace Yourcontroller with your controller name

MVC3 Weird behavior of ActionLink with HTML 5 Data- attributes

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>

EditorFor ignores tabindex. How do you set a tabindex?

The use of tabindex seems to only work for htmlhelpers like Textboxfor and not EditorFor
For example;
<%: Html.TextBoxFor(model => Model.MyItem, new { #tabindex = "3" })%>
Produces a tabindex value.
However, if you use;
<%: Html.EditorFor(model => Model.MyItem, new { #tabindex = "3" })%>
Then the result is that the control is created as expected, but the tabindex is missing.
So...... How is it possible to set the tabindex for a given EditorFor control?
The main problem I was having is that I needed to create a EditorFor type mechanism in order to format the decimal like a currency (our system has multiple currencies so "C" would not have been appropriate), get a tab index working AND allow the system to maintain the standard validation.
I've managed to achieve that using the following. By creating my own custom editor control.
Create a file (mine is called decimal.ascx) within the Views/Shared/EditorTemplates directory of your project.
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<decimal?>" %>
<% int intTabindex = 0;
decimal myVal = 0;
string strModelValue = "";
if (Model != null)
{
myVal = (decimal)Model;
strModelValue = myVal.ToString("#.00");
}
else
strModelValue = "";
if (ViewData["tabindex"] != null)
{
intTabindex = (int)ViewData["tabindex"];
}
%>
<%: Html.TextBox("", strModelValue, new { #tabindex = intTabindex })%>
Essentially, this code just overrides what would normally be presented in a "decimal" EditorFor method with the;
<%: Html.TextBox("", Model.ToString("#.00"), new { #tabindex = intTabindex }) %>
template.
My calling code now reads;
<%: Html.EditorFor(model => Model.MyItem, new { tabindex = 5 })%>
The result is the following code on the page.
<input id="Model_MyItem" name="Model.MyItem" tabindex="5" type="text" value="12.33" />
Which is exactly what I required.
Whilst this is only true for my particular circumstances, I would encourage anybody looking to solve this issue to attempt a custom control first for the task as it might save you a considerable amount of time.
If would of course be possible in the code to create a specific type of control required and adjust the results around that.
For example; we could simple add another item in the call to determine the text format.
new {tabindex = 12, numberformat=2}
Then simply create a handler for all the formats.
Since the EditorFor is just a template for a DataType it's only expecting a datatype as it's Model. There are a couple of ways of going about this I am guessing. You could possibly add the tabindex to an anonymous object that will be merged into the ViewData for the EditorTemplate like so.
Code in your View:
Html.EditorFor(m => m.Username, "test", new { tabindex = 3, style = "width: 400px;" })
EditorForModel Template Check for ViewData:
<%: Html.TextBoxFor(m => m.Username, ViewData)%>
This should render an text input with a tabindex of 3 and style="width: 400px;"
Happy coding.
Edited:
Here is exactly the markup I have inside of my test page:
<%: Html.EditorFor(m => m.DollarsAmount, "NullableDecimal", new { tabindex = 99 }) %>
I'm telling the EditorFor template to select the "NullableDecimal" EditorTemplate that I have created. (You could place a UiHint attribute on the property inside of the model also to tell it what editortemplate to use)
"NullableDecimal" EditorTemplate located in ~/Views/Shared/EditorTemplates:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<decimal?>" %>
<%: Html.TextBox(string.Empty, (Model.HasValue ? Model.Value.ToString("#.00") : null), ViewData) %>
What's more extensible about my implementation is the extra ViewData that I pass in via my anonymous object is merged into the ViewData dictionary to be used by the EditorTemplate. So if you don't pass any ViewData in to the EditorTemplate then it wont render your text inputs tabindex to 0 as your implementation currently will do. Plus your implementation will only account for tabindexes and not for any other input attributes. i.e. maxlength or style

ASP.NET MVC/C#: Can I create valid custom HTML attributes using Html.ActionLink()?

I have the need to put a custom attribute on an anchor which I am constructing using Html.ActionLink()
<%: Html.ActionLink("Delete", "Delete", new { id = Model.ID }, new { data-icon = "ui-icon-trash" })%>
Using the proper "data-" prefix, as per http://www.w3.org/TR/html5/elements.html#attr-data, I get the following error from Visual Studio.
Invalid anonymous type member declarator. Anonymous type members must be declared with a member assignment, simple name or member access.
Since I can't use a hyphen in the anonymous type, what would be the best way to go about adding my custom HTML attribute?
data-icon is not a valid C# variable name. The closest you could get is this:
<%: Html.ActionLink(
"Delete",
"Delete",
new { id = Model.ID },
new Dictionary<string, string> { { "data-icon", "ui-icon-trash" } }
) %>
Of course this issue has been addressed in ASP.NET MVC 3 and you no longer need to write spaghetti code. So:
<%: Html.ActionLink(
"Delete",
"Delete",
new { id = Model.ID },
new { data_icon, "ui-icon-trash" }
) %>
And the underscore will be automatically converted to a hyphen.

Resources