MVCContrib Grid MVC 3 Razor .RowStart - asp.net-mvc-3

Having trouble with the examples for the .RowStart method.
Comparing the 2 syntaxes: http://www.jeremyskinner.co.uk/2009/03/01/mvccontrib-grid-part-5-the-action-syntax/
In this
.RowStart(row => string.Format("<tr{0}>", row.IsAlternate ? "style=\"background-color:#CCDDCC\"" : ""))
row.IsAlternate throws an error as row isnt the GridRow, its actually your model (well the row's data item).
The second syntax (ActionSyntax) :
.RowStart((p,row) => {
if (row.IsAlternate) { %>
<tr style="background-color:#CCDDCC">
<% } else { %>
<tr>
<% }
}).Render(); %>
doesnt seem to translate to Razor
.RowStart((x, row) => string.Format("<tr class='{0}'>", row.IsAlternate ? "grid-row" : "grid-row-alt"))
Passes ok, but doesn't emit any row changes.
Any had this working?

I've just noticed some convention stuff that Html.Grid is putting in for you...
Given the Following
Html.Grid(Model.Results).Attributes(#class => "grid")
results in a table with class = "grid",
even rows with a class = "gridrow",
and odd rows with a class = "gridrow_alternate"

Not sure if this will help but one thing I've been doing lately is using:
.RowAttributes(x => new Dictionary<string, object> { { "class", x.value == myValue ? "highlight" : "" } })
This allows me to do a lot with css values for the attributes. then for supporting "Zebra striping" I use pure css (browser compatibility could be an issue here, but it's graceful just doesn't render on old browsers) looks something like
tr:nth-child(odd) {
background-color: #eee;}
Gives u great control over the table. More info on the selectors Sitepoint child selectors
Other wise you could try the google groups for mvccontib Jeremy is usually sharp of the mark to help out.
Hope this helped.

Related

ASP.Net MVC 3 - DropDownListFor fails to select the value form the model if HtmlFieldPrefix is set on the partial view

when using
<%= Html.DropDownListFor(model => model.FeeTypeId, Model.GetFeeTypes(), new { })%>
in this case the right option is selected according to Model.FeeTypeId when the select is rendered.
BUT
if you render the form using a partial view, passing it a specific HtmlFieldPrefix (you will need it if,for example, you want to render two identical views and want different ids the elements)
<% Html.RenderPartial("path-to-partial-view", Model, new ViewDataDictionary() { TemplateInfo = new TemplateInfo() { HtmlFieldPrefix = "myPrefix" } }); %>
then the value will not be selected.
looks similar to the problem at DropDownListFor in EditorTemplate not selecting value but from different cause.
looked in the MVC 3 source and seems like the problem is at the SelectInternal method
it uses the htmlHelper.ViewData.Eval(fullName);
which fails to get the value by the full name when it contains the prefix,
TextBoxFor doesn't fail as it passes the value of the expression to InputHelper so it doesn't get to use the ViewData.Eval
just to be sure tested it at the partial view:
in the partial view the following will print "myPrefix.FeeTypeId"
<%= Html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName("FeeTypeId") %>
and the following will print "by property name: [value] by full name: [empty string]"
<%="by property name: " + Html.ViewData.Eval("FeeTypeId")%><br />
<%= "by full name: " + Html.ViewData.Eval(Html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName("FeeTypeId"))%>
The only solution i found is to generate a List at Model.GetFeeTypes() and mark the option i want as selected:
<%= Html.DropDownListFor(model => model.FeeTypeId, Model.GetFeeTypes(Model.FeeTypeId), new { })%>
don't really like this solution + i know i can create the List in the partial view which is also ugly,
is there another solution to this?
I have discovered that this is a bug in MVC. It's not fixed, though there is a work around.
See my question answered by myself (I had the same problem before finding your post).
MVC4 binding drop down list in a list (bug)
Regards
Craig

How to properly disable an Html Helper Textbox or TextBoxFor?

I have a razor display that is being used for entry. In one case, I would like the user to be able to populate the text box, in the other case, I would like to prevent the user from populating it. I am using code like:
#Html.TextBoxFor(model => model.Goop, new { #class = "text-box", maxlength = 2, onfocus = "javascript:this.select();" })
if (Model.Review.ReviewType.Equals("M"))
{
<script type="text/javascript">
$(function () {
$("#Goop").prop("disabled", true);
});
</script>
}
I have tried to do this several ways, jQuery (above), CSS attribs, javascript, ASP.NET... but all have the same issue: When the form is submitted, if the Goop textbox is disabled, the value for Goop in the model is Null. Ideas?
Thanks in advance!
Maybe it's not as cool without jQuery, but when I do this in my apps I do something along the lines of
if (Model.Review.ReviewType.Equals("M"))
{
#Html.DisplayFor(model => model.Goop)
#Html.HiddenFor(model => model.Goop)
}
else
{
#Html.TextBoxFor(model => model.Goop)
}
If a form element is disabled, it does not post a value. That's how it's supposed to work.
To work around this, you will need to do one of several things. You can enable the fields just before posting by intercepting the submit method. You can use a hidden field to store the data in addition to the disabled control. Or you can just assume the values on the controller side.
by the way, it should be .prop("disabled", "disabled"), which renders as disabled="disabled", that's standards compliant.

Editing a collection in a partial view

I was having problems updating child collections of my object ( Foreign key constraint, EF with collection of childobjects ) which was solved using this guide: http://www.codetuning.net/blog/post/Binding-Model-Graphs-with-ASPNETMVC.aspx
When cleaning up my code, I moved the collection editing to a partial view.
#Html.Partial("_AttendeeInformationFields", Model.CaptureAttendeeInformationFields)
The partial view looks like this
#model ICollection<EventModel.Models.AttendeeInformationField>
<table id="CaptureAttendeeInformationFields">
<tr>
<th>#Html.GetDisplayName(model => model.FirstOrDefault().Name)</th>
<th>#Html.GetDisplayName(model => model.FirstOrDefault().Required)</th>
<th>#Html.GetDisplayName(model => model.FirstOrDefault().FieldType)</th>
#*<th>#Html.GetDisplayName(model => model.FirstOrDefault().InputType)</th>*#
</tr>
#Html.EditorForModel()
</table>
#Html.LinkToAddNestedForm("Lägg till", "#CaptureAttendeeInformationFields", ".AttendeeInformationField", "CaptureAttendeeInformationFields", typeof(EventModel.Models.AttendeeInformationField))
#Html.ValidationMessageFor(model => model)
Then I have a EditorTemplate for AttendeeInformationField that looks like this
#model EventModel.Models.AttendeeInformationField
<tr class="AttendeeInformationField">
#using (Html.BeginCollectionItem("CaptureAttendeeInformationFields"))
{
<td>#Html.TextBoxFor(model => model.Name) #Html.HiddenFor(model => model.MagnetEventId) #Html.HiddenFor(model => model.Id)</td>
<td>#Html.CheckBoxFor(model => model.Required)</td>
<td>#Html.DropDownListFor(model => model.FieldType, new SelectList(Enum.GetValues(typeof(EventModel.Models.FieldType)), Model.FieldType))</td>
#*<td>#Html.TextBoxFor(model => model.InputType)</td>*#
}
</tr>
The BeginCollectionItem is from this guide: http://ivanz.com/2011/06/16/editing-variable-length-reorderable-collections-in-asp-net-mvc-part-1/
This helps me with two things
1. The index is no longer a sequential 0-based integer series, and I can reorder my items, as well as add/delete without worrying about breaking the sequence.
2. The partial seems to loose the context, and my controls get names like "[0].Required" where it should be "CaptureAttendeeInformationField[0].Required". The BeginCollectionItem takes care of this.
The current problem is that these fixes doesn't seem to be compatible. I suppose it might have something to do with this disclaimer in the first article:
within this implementation we assume that the index is an integer starting at 0
I'm hoping that someone can point me in the right direction.
Adding items in this solution works.
Ugly solution
I sure hope this is not the only way to do this, but for now I've solved the problem like this:
foreach (var attendeeInformationField in viewModel.AttendeeInformationFields)
{
var attendeeInformationFieldId = attendeeInformationField.Id;
var originalAttendeeInformationField = original.CaptureAttendeeInformationFields.FirstOrDefault(aif => aif.Id == attendeeInformationFieldId);
if (originalAttendeeInformationField==null)
{
original.CaptureAttendeeInformationFields.Add(attendeeInformationField);
}
else
{
if (originalAttendeeInformationField != attendeeInformationField)
{
originalAttendeeInformationField = attendeeInformationField;
originalAttendeeInformationField.FieldType = attendeeInformationField.FieldType;
//originalAttendeeInformationField.InputType = attendeeInformationField.InputType;
originalAttendeeInformationField.Name = attendeeInformationField.Name;
originalAttendeeInformationField.Required = attendeeInformationField.Required;
}
}
}
I don't like it at all, but it works. There must be a better way of doing this.

MVC3 HTML Helper for large Text area

I have an html helper:
#Html.EditorFor(model => model.Description)
But it is too small for the data in that property of my Model. Descriptino is a 1000 character string. I need the user to be able to enter several lines of text and have it wrap in the HTML object. How do I do this?
Try
Html.TextAreaFor(model => model.Description, new {#cols="80" , #rows="4" })
Use:
#Html.TextAreaFor(model => model.Description)
// or a full option-list is:
#Html.TextAreaFor(model => model.Description,
rows, // the rows attribute of textarea for example: 4
columns, // the cols attribute of textarea for example: 40
new { }) // htmlAttributes to add to textarea for example: #class = "my-css-class"
Notice: you can use null instead of new { } for htmlAttributes but it is not recommended! It's strongly recommended that use a blank new { } -that represents a new object-
You can use EditorFor, but in that case it's better to define your own EditorTemplate for rendering your TextArea, using TextAreaFor or whatever it's needed.
The main difference between the TextAreaFor and EditorFor is that, if I've understood well how everything works, when using EditorFor, Templates are taken into account, while when using TextAreaFor you choose the HTML Input used for rendering.
Templates seems interesting, I'm just starting digging into writing my own.
Sounds like you're after Html.TextAreaFor.

Syntax for ASP.Net MVC Phil Haack's Repeater syntax using Razor (MVC 3)?

I have recently started using ASP.Net MVC 3 RC 2 and have attempted to migrate an existing website in MVC 2 across using the Razor syntax. In the MVC 2 application I am using the code base repeater that Phil Haack kindly provided in the following:
Phil Haack's Code Based Repeater
My question is around the syntax for Razor. I dont understand how the template in the following block can be rewritten in Razor and cannot find any documentation to help out (early days for documentation or my simplicity...):
<% Html.Repeater<ObjectToUse>(Model, "", "alt", (item, css) =>
{ %>
<tr class="<%= item.Enabled ? css : "disabled" %>">
<td><%= item.Name%></td>
<td><%= item.Description%></td>
<td><%= Html.RouteLink("Edit", item.ObjectToUseRouteValues("Edit"))%></td>
<td></td>
<td><%= Html.RouteLink("Select", item.ObjectToUseRouteValues())%></td>
</tr>
<% }); %>
The problem comes when applying the template between the braces (the tr's). I have attempted using the WebGrid control, however it doesnt provide the functionality I require for setting a "disabled" row (I think).
I wrote #helper version.
#helper do not use Generic method.
#helper ForEach(IEnumerable<int> items, Func<object, HelperResult> template){
foreach(var item in items){
Write(template(item));
}
}
<div>
<ul>
#ForEach(Enumerable.Range(1,5),
#<li>#item</li>
)
</ul>
</div>
hope this code.
Actually, now that I think about it some more I don't think you can use Action parameters like that in Razor. I recall running into this before.
Updated
With answer from Andrew Nurse:
"Unfortunately this is by design in the current parser, though I should note that we'd like to improve upon it. The issue is that markup is only valid at the start of a statement (which technically is where you've put it), but our C# "parser" is not intelligent enough to detect lambdas at the moment."
Though that might be out dated :)
#Html.Repeater(Model, "row", "row-alt",
#<tr class="#item.ClassType : "disabled"">
<td>#item.Name</td>
<td>#item.Description</td>
<td>#Html.RouteLink("Edit", item.ObjectToUseRouteValues("Edit"))</td>
<td></td>
<td>#Html.RouteLink("Select", item.ObjectToUseRouteValues())</td>
</tr>
)
public static IHtmlString Repeater<T>(this HtmlHelper html, IEnumerable<T> items,
string className, string classNameAlt, Func<T, HelperResult> render) {
if (items == null)
return new HtmlString("");
int i = 0;
StringBuilder sb = new StringBuilder();
foreach (var item in items) {
item.ClassType = item.Enabled ? (i++ % 2 == 0 ? className : classNameAlt) : "disabled";
sb.Append(render(item).ToHtmlString());
}
return new HtmlString(sb.ToString());
}
}

Resources