Custom validation error message location - asp.net-mvc

I've been struggling with how to change the following to fit my needs. This is for a form I have with simple inputs. The way the code is now it simply displays a label, the field and a validation message vertically, but I want to make it horizontal (using a <table>).
Currently I have this code:
var wrapper = new TagBuilder("div");
wrapper.AddCssClass("field-wrapper");
var table = new TagBuilder("table");//This is my test to insert a table
var label = new TagBuilder("div");
label.AddCssClass("field-label");
if (metadata.IsRequired && !metadata.IsReadOnly)
{
if (metadata.ModelType != typeof (bool))
{
label.InnerHtml += "* ";
wrapper.AddCssClass("required");
}
}
label.InnerHtml += html.LabelFor(expression);
wrapper.InnerHtml += label;
var input = new TagBuilder("div");
input.AddCssClass("field-input");
input.InnerHtml += html.EditorFor(expression);
if (!string.IsNullOrEmpty(metadata.Description))
{
input.InnerHtml += html.TooltipFor(expression);//declared elsewhere to show a tooltip
}
input.InnerHtml += html.ValidationMessageFor(expression);
wrapper.InnerHtml += input;
wrapper.InnerHtml += table;//This is my test to insert a table
return MvcHtmlString.Create(wrapper + "\r\n");
I tried inserting a <table> but this is the structure of the HTML with that code:
<div class="field-wrapper">
<div class="field-label">
<label for="Name">Name</label>
</div>
<div class="field-input">
* <input class="text-box single-line input-validation-error" data-val="true" data-val-required="The Name field is required." id="Name" name="Name" type="text" value="">
<!--tooltip would ordinarily show up here-->
<span class="field-validation-error" data-valmsg-for="Name" data-valmsg-replace="true">
<span for="Name" generated="true" class="">The Name field is required.</span>
</span>
</div>
<table></table><!--This is my table-->
</div>
This is what it looks like after validation-error:
What I am going for is this structure:
<div class="field-wrapper">
<table border="0">
<tbody>
<tr>
<td width="40%">
<div class="field-label">
<label class="mylabelstyle" for="FirstName" title="Enter first name.">First Name:</label>
</div>
</td>
<td width="60%">
<div class="field-input">
<input data-val="true" data-val-required="First Name required." id="FirstName" name="FirstName" type="text" value="" />
<!--tooltip here as necessary-->
<span class="field-validation-valid" data-valmsg-for="FirstName" data-valmsg-replace="true"></span>
</div>
</td>
</tr>
</tbody>
</table>
</div>
Visually, this is what I am after:
A couple of things to note:
The "*" (required code) and tooltip are shown under certain conditions.
Styling will not be a problem - I am focused on structure here.
I used different helpers for the inputs, so the code inside each (and the name, i.e., Name v. FirstName) is different and not the problem.
The <table> is inside a <div> that's floated left. I have some static content on the right which is not the problem (it shows up under the validation in the second image), so that's also not important.
I am not good with the TagBuilder and have just been making a mess of everything. Any help is greatly appreciated. Thanks!

There you go:
public static IHtmlString MyEditorFor<TModel, TProperty>(
this HtmlHelper<TModel> html,
Expression<Func<TModel, TProperty>> expression
)
{
var metadata = ModelMetadata.FromLambdaExpression<TModel, TProperty>(expression, html.ViewData);
var wrapper = new TagBuilder("div");
wrapper.AddCssClass("field-wrapper");
var table = new TagBuilder("table");
table.Attributes["border"] = "0";
var tbody = new TagBuilder("tbody");
var tr = new TagBuilder("tr");
var td1 = new TagBuilder("td");
td1.Attributes["width"] = "40%";
var label = new TagBuilder("div");
label.AddCssClass("field-label");
if (metadata.IsRequired && !metadata.IsReadOnly)
{
if (metadata.ModelType != typeof(bool))
{
label.InnerHtml += "* ";
wrapper.AddCssClass("required");
}
}
label.InnerHtml += html.LabelFor(expression);
td1.InnerHtml = label.ToString();
var td2 = new TagBuilder("td");
td2.Attributes["width"] = "60%";
var input = new TagBuilder("div");
input.AddCssClass("field-input");
input.InnerHtml += html.EditorFor(expression);
if (!string.IsNullOrEmpty(metadata.Description))
{
input.InnerHtml += html.TooltipFor(expression);
}
input.InnerHtml += html.ValidationMessageFor(expression);
td2.InnerHtml = input.ToString();
tr.InnerHtml = td1.ToString() + td2.ToString();
tbody.InnerHtml = tr.ToString();
table.InnerHtml = tbody.ToString();
wrapper.InnerHtml = table.ToString();
return new HtmlString(wrapper + Environment.NewLine);
}

Related

After using IEnumerable in view and controller getting null value in controller(model)

I am using asp.net mvc5 in which i am using Ienumerable in View and also in Controller to pass the mutiple values for which i need to use Foreach loop.
After using all this i am getting NULL values in controller from Model
For controller:
public ActionResult ManageTimeExpense(IEnumerable<TimeExpense> Timemodel, IEnumerable<ExpenseBook> Expensemodel)
{
var get = Request.Files.Count;
try
{
{
//for(var i = Timemodel)
foreach(var r in Timemodel)
for view:
#model IEnumerable<Tuple<TimeSheet.Models.TimeExpense , TimeSheet.Models.ExpenseBook>>
#{
Layout = null;
}
#using (Html.BeginForm("ManageTimeExpense", "TimeExpense", FormMethod.Post,new { enctype = "multipart/form-data" }))
{ <div class="col-lg-3 col-md-3 col-sm-12 col-xs-12">
<label>Hours:</label>
<input id="Hours" name="Hours" type="number" class="form-control hours" placeholder="24 Hours" />
#* #Html.TextBoxFor(h => h.Hours, new {#type="number",#class = "form-control",#placeholder="24 Hours", Required = "required" })*#
</div>
<div class="col-md-3 col-sm-12 col-xs-12">
<label></label>
<input type="submit" value="Save" class="form-control btn btn-primary">
</div>
$("#Save").click(function () {
var TimeExpense = [];
var ExpenseBook = [];
var Date = $("#Date").val();
var TimeExpenseMasterId = $("#TimeExpenseMasterId").val();
$('.invoicerow1').each(function () {
var TaskMasterId = $(this).closest('tr').find('.task').val();
var Hours = $(this).closest('tr').find('.hours').val();
var TimeDescription = $(this).closest('tr').find('. timedes').val();
TimeExpense.push({
TimeExpenseMasterId: TimeExpenseMasterId,
Date: Date,
TaskMasterId: TaskMasterId,
Hours: Hours,
TimeDescription: TimeDescription,
});
});
$('.invoicerow').each(function () {
var ExpenseDescription = $(this).closest('tr').find('.exp').val();
var Amount = $(this).closest('tr').find('.amt').val();
var Currency = $(this).closest('tr').find('.currency').val();
var BillStatus = $(this).closest('tr').find('.bill').val();
ExpenseBook.push({
ExpenseDescription: ExpenseDescription,
Amount: Amount,
Currency: Currency,
BillStatus: BillStatus,
});
});
var data = {
TimeExpense: TimeExpense,
ExpenseBook: ExpenseBook
};
});
</script>

Editor Template for Enum with RadioButton not working

I updated a Enum Editor I found online to generate kendo radio controls instead of regular but the first radio button is generated with correct attributes and the remaining are wrong and at runtime, the whole set of radio buttons are not clickable
Here is the .cshtml for the editor:
#model Enum
#{
Func<Enum, string> getDescription = en =>
{
Type type = en.GetType();
System.Reflection.MemberInfo[] memInfo = type.GetMember(en.ToString());
if (memInfo != null && memInfo.Length > 0)
{
object[] attrs = memInfo[0].GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.DisplayAttribute), false);
if (attrs != null && attrs.Length > 0)
{
return ((System.ComponentModel.DataAnnotations.DisplayAttribute)attrs[0]).GetName();
}
}
return en.ToString();
};
var listItems = Enum.GetValues(Model.GetType()).OfType<Enum>().Select(e =>
new SelectListItem()
{
Text = getDescription(e),
Value = e.ToString(),
Selected = e.Equals(Model)
});
string prefix = ViewData.TemplateInfo.HtmlFieldPrefix;
int index = 0;
ViewData.TemplateInfo.HtmlFieldPrefix = string.Empty;
foreach (var li in listItems)
{
string fieldName = string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}_{1}", prefix, index++);
<div >
#(Html.Kendo().RadioButton()
.Label(li.Text)
.Name(prefix)
.Value(li.Value)
.Checked(li.Selected)
.HtmlAttributes(new { #id = fieldName })
)
#*
This works properly
#Html.RadioButton(prefix, li.Value, li.Selected, new { #id = fieldName, #class = "k-radio" })
#Html.Label(fieldName, li.Text, new { #class = "k-radio-label" })
*#
</div>
}
ViewData.TemplateInfo.HtmlFieldPrefix = prefix;
}
Here is the first radio on the form:
<div>
<input name="StaffType" class="k-radio k-radio" id="StaffType_0" type="radio" checked="checked" value="DACStaff" data-val-required="The StaffTypeEnum field is required." data-val="true">
<label class="k-radio-label" for="StaffType_0_DACStaff">DAC Staff</label>
</div>
And here is the next one:
<div>
<input name="StaffType" class="k-radio k-radio" id="StaffType_1" type="radio" value="AirportStaff">
<label class="k-radio-label" for="StaffType_1_AirportStaff">Airport Staff</label>
</div>
I see that the class tag k-radio is applied twice and except the first element has the data-* attributes but second radio button and onwards, the generated code is missing attributes.
Can someone point out why the generated code is not functioning?
Usage:
<div class="form-group">
#Html.LabelFor(m => m.StaffType, new { #class = "col-sm-3 control-label" })
<div class="col-sm-6">
#Html.EditorFor(m => m.StaffType, "RadioButtonListEnum")
</div>
</div>

JQuery Multiple datepickers from and to booking form

Hi I found the following code from this page JQuery UI DatePicker using 2 date fields trying to get date difference
However I don't understand the datepicker ui enough to be able to stop the first datepicker from letting you only select from todays date. Im sure its simple but can someone please help!
<script type="text/javascript">
var DatePicked = function() {
var departure = $("#CheckIn");
var arrival = $("#CheckOut");
var nights = $("#Nights");
var triggeringElement = $(this);
var minArrivalDate = new Date();
var departureDate = departure.datepicker("getDate");
if (departureDate != null) {
minArrivalDate.setDate(departureDate.getDate() + 1);
} else {
minArrivalDate.setDate(minArrivalDate.getDate() + 1);
}
arrival.datepicker('option', 'minDate', minArrivalDate);
var arrivalDate = arrival.datepicker("getDate");
if (departureDate != null && arrivalDate != null && triggeringElement.attr("id") != "Nights") {
var oneDay = 1000*60*60*24;
var difference = Math.ceil((arrivalDate.getTime() - departureDate.getTime()) / oneDay);
nights.val(difference);
} else if (departureDate != null && triggeringElement.attr("id") == "Nights") {
var nightsEntered = parseInt(nights.val());
if (nightsEntered >= 1) {
var newArrivalDate = new Date();
newArrivalDate.setDate(departureDate.getDate() + nightsEntered);
arrival.datepicker("setDate", newArrivalDate);
} else {
alert("Nights must be greater than 1.");
}
}
}
$(function() {
$("#CheckIn, #CheckOut").datepicker({
onSelect: DatePicked
});
$("#Nights").change(DatePicked);
DatePicked();
});
</script>
Form:
<form class="enquiry" action="assets/scripts/booking.php" method="get" name="Booking">
<div class="Widget_Form_Spacer">
<label for="CheckIn">Check-In</label>
<input id="CheckIn" name="CheckIn" type="text" class="tF bL" value="<?php echo date("m/d/Y"); ?>" />
</div>
<div class="Widget_Form_Spacer Right">
<label for="CheckOut">Check-Out</label>
<input id="CheckOut" name="CheckOut" type="text" class="tF bL" value="" />
</div>
<div class="Widget_Form_Spacer Short">
<label for="Nights">Nights</label>
<input id="Nights" name="Nights" type="text" class="tF nL" value="1" onclick="clickclear(this, '1')" onblur="clickrecall(this,'1')" />
</div>
<div class="Widget_Form_Spacer Short">
<label for="Adults">Adults</label>
<input name="Adults" type="text" class="tF nL" value="1" onclick="clickclear(this, '1')" onblur="clickrecall(this,'1')" />
</div>
<div class="Widget_Form_Spacer Long">
<input name="Check" type="submit" value="Check Availability" />
</div>
</form>
You can use the minDate jquery UI datepicker option:
$("#date").datepicker({ minDate: new Date() });
Live DEMO

Enable/Disable Validation of certain hidden textboxes in mvc 2

I have got [hide] and [unhide] input buttons , the hide button shows some text boxes while the hidden button hide some text boxes, What I want to do is to enable validation only for those boxes which are visible and disable validation for the boxes which are not visible to client. Currently I am validating on all the boxes, the post action also validates the text boxes which are hidden through jquery , below is the code :
View
<script type="text/javascript">
$(document).ready(function () {
var $startdates = $('#startDates');
var $endDates = $('#endDates');
var $showEvents = $('#showEvents');
$startdates.hide();
$endDates.hide();
$showEvents.hide();
$('#all').click(function () {
$startdates.show();
$endDates.show();
$('#showEvents').show();
$('#eventdids').hide();
$(this).hide();
return false;
});
$('#showEvents').click(function () {
$startdates.hide();
$endDates.hide();
$('#eventdids').show();
$('#all').show();
$(this).hide();
return false;
});
});
</script>
<tr id="startDates">
<td>
<div class="editor-label">
<%: Html.LabelFor(model => model.StartDate) %>
</div>
</td>
<td>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.StartDate) %>
<%: Html.ValidationMessageFor(model => model.StartDate) %>
</div>
</td>
</tr>
<tr id="endDates">
<td>
<div class="editor-label">
<%: Html.LabelFor(model => model.EndDate) %>
</div>
</td>
<td>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.EndDate) %>
<%: Html.ValidationMessageFor(model => model.EndDate) %>
</div>
</td>
</tr>
<tr id="eventdids">
<td>
<label>Events</label>
</td>
<td>
<% foreach (var item in (SelectList)ViewData["events"]) { %>
<input type="checkbox" name="Name" value="<%=item.Value %>" />
<label for="<%=item.Value%>"><%=item.Text%></label>
<br />
<% } %>
</td>
<td><input type="button" name="Select" id="all" style="width:auto" value="Hide" /></td>
</tr>
</table>
<input type="button" name="show" id="showEvents" style="width:auto" value="Show" />
<p>
<input type="submit" value="Create" />
</p>
Controller:
[HttpPost]
public ActionResult Create(FormCollection collection, int[] Name)
{
IVoucherRepository voucherResp = new VoucherRepository();
string empty = "";
if (Name != null)
{
for (int i = 0; i < Name.Length; i++)
{
empty += Convert.ToString(Name[i]) + ",";
}
}
else
{
ModelState.AddModelError("Venue", "Required");
}
if (Convert.ToBoolean(collection["pound"].ToLower().StartsWith("false")) && Convert.ToBoolean(collection["percentage"].ToLower().StartsWith("false")))
{
ModelState.AddModelError("","Please Select £ or % for discount");
}
if (collection["UsageQtyAvailable"] == null) { ModelState.AddModelError("UsageQtyLeft", "Required "); }
Voucher voucher = new Voucher();
if (TryUpdateModel(voucher) && ModelState.IsValid)
{
voucher.Status = true;
voucher.DateAdded = DateTime.Now;
voucher.DateModified = DateTime.Now;
if(Convert.ToBoolean(collection["pound"].ToLower().StartsWith("true")))
{
voucher.DiscountType = 1;
}
else if (Convert.ToBoolean(collection["percentage"].ToLower().StartsWith("true")))
{
voucher.DiscountType = 2;
}
voucher.VoucherType = 1; //Discount Code
voucher.UsageQtyLeft = Convert.ToInt32(collection["UsageQtyAvailable"]);
string removeComma = empty.Remove(empty.Length - 1,1);
voucher.EventIDs = removeComma;
voucherResp.Add(voucher);
voucherResp.Save();
return RedirectToAction("Index");
}
ITrackdayRepository trackdayResp = new TrackdayRepository();
IQueryable<Object> getAllEvents = trackdayResp.GetEventsSelectlist();
ViewData["events"] = new SelectList(getAllEvents.ToList(), "EventID", "Name");
return View();
}
You could check via jquery if the text boxes are hidden and remove them before submitting the form and subsequently only validate submitted form elements.
...
<input type="submit" value="Create" id="create" />
...
$("#create").click(function() {
$('#eventdids:hidden').remove();
$('#all:hidden').remove();
$("#formID").submit();
});
You can also remove validation for all hidden fields in a form with this little plugin:
(function($) {
$.fn.refreshValidator = function() {
var form = this;
// Get validation settings object
var settings = form.validate().settings;
// Remove validation for hidden elements
$(this).find(':hidden').each(function(){
var id = $(this).attr('id');
delete settings.rules[id];
delete settings.messages[id];
});
};
})(jQuery);
You can call it like this:
$('#yourFormId').refreshValidator();
It's more reusable this way.

How To avoid that an ascx template overwrites the original style, class, maxlength, etc. attributes?

Main issue: Adding to all(!) textboxes in a MVC2 solution/project a js/jquery method.
Basics: How to call an ascx template?
Solved, see here
(Thanks to Darin Dimitrov!)
BUT...
Means the ascx template "Test.ascx" will be called like here shown:
<%: Html.EditorFor(model => model.Firstname, "Test", new { style = "float: left; width: 4.1em;", maxlength = "4" })%>
The "Test.ascx" template adds the js/jquery function.
Works fine, np so fare.
But: The "original" attributes style="..." maxlength="..." will be lost/overwritten.
My current solution / my "Test.ascx" file:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<input type="text"
id="<%: ViewData.TemplateInfo.GetFullHtmlFieldId(string.Empty) %>"
name="<%: ViewData.TemplateInfo.HtmlFieldPrefix %>"
value="<%: ViewData.TemplateInfo.FormattedModelValue %>"
style="<%: ViewData["style"] %>"
class="<%: ViewData["class"] %>"
maxlength="<%: ViewData["maxlength"] %>"
onkeyup="Foo(this); return false;"/>
This works really fine and returns / renders it perfectly:
<input type="text"
id="Firstname"
name="Firstname"
value=""
style="float: left; width: 4.1em;"
class=""
maxlength="4"
onkeyup="Foo(this); return false;"/>
Note that here are the style="..." and maxlength="..." attributes are well handled!
I use currently the "standard" < input ... /> tag because I didnt get this to work:
<%
String tmpConfig = " new {onkeyup=\"Foo(this); return false;\"";
String style = this.ViewData["style"] as String;
if (!String.IsNullOrEmpty(style))
tmpConfig += ", style=\"" + style + "\"";
String #class = this.ViewData["class"] as String;
if (!String.IsNullOrEmpty(#class))
tmpConfig += ", class=\"" + #class + "\"";
String maxlength = this.ViewData["maxlength"] as String;
if (!String.IsNullOrEmpty(maxlength))
tmpConfig += ", maxlength=\"" + maxlength + "\"";
tmpConfig += " } ";
%>
<!-- doesnt work: -->
<%: Html.TextBox( string.Empty,
ViewData.TemplateInfo.FormattedModelValue,
// new { onkeyup = "Foo(this); return false;" } // the style, class, maxlength attributes will be lost / not rendered!
// new { tmpConfig } // result would be the attribut: tempConfig=" onkeyup..."
// new tmpConfig // result: error, tmpConfig isnt object
Html.Encode(tmpConfig) // doesnt work ...
)%>
This renders finally the same but WITHOUT the style="..." and maxlength="..." attributes!
But I want to use the <%: Html.TextBox(...) %> instead of the < input ... /> tag!
Because this would give me the possibility to avoid an empty attribute like class="" and like before shown.
Where is my mistake?
You have to supply the Html.TextBox with a dictionary of String,Object to hold all attributes
<%
var dict = new Dictionary<string, object>();
String style = this.ViewData["style"] as String;
if (!String.IsNullOrEmpty(style))
dict.Add("style", style);
String #class = this.ViewData["class"] as String;
if (!String.IsNullOrEmpty(#class))
dict.Add("class", #class);
String maxlength = this.ViewData["maxlength"] as String;
if (!String.IsNullOrEmpty(maxlength))
dict.Add("maxlength", maxlength);
dict.Add("onkeyup", "Foo(this); return false;");
%>
<%: Html.TextBox( string.Empty,
ViewData.TemplateInfo.FormattedModelValue,
dict
)%>

Resources