Adding a hyphen to the html attribute name using MVC3 WebGrid helper - asp.net-mvc

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.

Related

UmbracoTemplatePage and strongly typed view not working together

I don't quite understand why I can't use both strongly typed view and umbraco template in one view.
I have a script importing excel data. My website is in umbraco 7.
I use Import.cshtml view which calls upload.cshtml partial
#inherits UmbracoTemplatePage
#{
Layout = "~/Views/Master.cshtml";
var locations = new List<SelectListItem>
{
new SelectListItem {Selected = false, Text = "location 1", Value = ""},
};
var fileTypes = new List<SelectListItem>
{
new SelectListItem {Selected = false, Text = "type 1", Value = ""},
};
}
<div id="page-bgtop">
<div class="post">
<h1>#Umbraco.Field("title")</h1>
<div class="entry">
#Html.Partial("Upload", new MvcImport.Models.ImportModel { FileTypes = fileTypes, Locations = locations })
</div>
</div>
<div class="clear"> </div>
</div>
Upload.cshtml partial does the job in ImportController. The data are there inserted into nicely into
List<CourseImport> courses = List<CourseImport>
All I want to do with it now is to display them in a view or partial view.
I tried several things:
CASE 1
1.
in ImportController I do:
return View("CoursesList", courses);
2.
The view includes a table which displays the rows and starts with
#inherits UmbracoTemplatePage
#model IEnumerable<MvcImport.Models.CourseImport>
#{
Layout = "~/Views/Master.cshtml";
}
3.
In this case I get:
Parser Error Message: The 'inherits' keyword is not allowed when a 'model' keyword is used.
CASE 2
1.
As 1. in Case 1.
2.
The view starts with (so without #inherits UmbracoTemplatePage)
#model IEnumerable<MvcImport.Models.CourseImport>
#{
Layout = "~/Views/Master.cshtml";
}
3.
I get:
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[MvcImport.Models.CourseImport]', but this dictionary requires a model item of type 'Umbraco.Web.Models.RenderModel'.
CASE 3
1.
In ImportController I do
return PartialView("CoursesList", courses);
2.
I'm now using partial view which it similar to the view in the above points and also is strongly typed eg.
#model IEnumerable<MvcImport.Models.CourseImport>
3.
In this case the data is displayed but without my umbraco template shape, no styling etc.
If in the partial view I include
#{
Layout = "~/Views/Master.cshtml";
}
I get the same error as in Case 2
Changing the starting directive to
#model UmbracoViewPage<MvcImport.Models.CourseImport>
does not work either as the model must be enumerable
Can someone advise me how to do it? I guess there must be a solution but I am very new to MVC so I don't get how things work yet too much.
Thanks.
The solution is provided on umbraco forum website http://our.umbraco.org/forum/developers/razor/55389-UmbracoTemplatePage-and-strongly-typed-view-not-working-together?p=0

getting string values as well in textbox while using Html.TextBoxFor

In my partial view I have passed some list of strings from a method in controller
Here is my partial view
#model IEnumerable<string>
#foreach(var names in Model)
{
<div class="input-block-level">#Html.TextBoxFor(m=>names)</div>
<br/>
}
Here is how it looks in browser
Why am I getting the texts in textbox?
I mean I would want them there but as placeholder not default text.
How can I not have those values and just have a plane textbox?
Use this to change initial value:
#Html.TextBoxFor(m => names, new { Value = "" })

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"
}
})

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>

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/

Resources