Is there a way in ASP.NET MVC3 to customize the result of the Html.ValidationMessageFor(...) method? For example add an image next to the error text or similar...
But I want to be able to change the image whether the validation is successful or not...
You can see that the error is wrapped with a Css Class, all you need to do is use that Css Class at your own will.
The default MVC3 contains in the styles.css
/* Styles for validation helpers
-----------------------------------------------------------*/
.field-validation-error
{
color: #ff0000;
}
.field-validation-valid
{
display: none;
}
.input-validation-error
{
border: 1px solid #ff0000;
background-color: #ffeeee;
}
.validation-summary-errors
{
font-weight: bold;
color: #ff0000;
}
.validation-summary-valid
{
display: none;
}
just add your images there.
Yup
U can write ur own extension to do so
public static MvcHtmlString ValidationMessageFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
{
TagBuilder div = new TagBuilder("div");
div.AddCssClass("aside");
string modelName = ExpressionHelper.GetExpressionText(expression);
ModelState state = htmlHelper.ViewData.ModelState[modelName];
if (state != null)
if ((state.Errors != null) && (state.Errors.Count > 0))
div.AddCssClass("invalid");
else
div.AddCssClass("valid");
div.InnerHtml = htmlHelper.ValidationMessageFor(expression).ToString();
return MvcHtmlString.Create(div.ToString());
}
Then use something like this
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
And lastly u need to define ur css for invalid and aside class to customize how the error looks.
Related
Until recently, whenever I've needed a custom attribute in my HTML, I've always used an HTML5 data-* custom attribute.
Having recently started experimenting with WebComponents and, specifically, Custom Elements, I have started thinking in terms of custom attributes which are not HTML5 data-* custom attributes.
Before inadvertently adopting any non-recommended practices, I would like to clarify the following...
In the list below we have 4 elements:
Element i is a standard element with a data-* attribute
Element ii is a standard element with a custom attribute
Element iii is a custom element with a data-* attribute
Element iv is a custom element with a custom attribute
const toggleDataAttribute = (e) => {
e.target.dataset.inverted = (e.target.dataset.inverted === 'true') ? 'false' : 'true';
}
const toggleCustomAttribute = (e) => {
if (e.target.getAttribute('inverted') === 'true') {
e.target.setAttribute('inverted', 'false');
}
else {
e.target.setAttribute('inverted', 'true');
}
}
const toggleInvert = (e) => {
if (e.target.dataset.inverted) {
toggleDataAttribute(e);
}
else {
toggleCustomAttribute(e);
}
}
// Attach click event TO <div> elements
let divs = [...document.getElementsByTagName('div')];
divs.forEach((div) => div.addEventListener('click', toggleInvert, false));
// Attach click event TO <my-circle> elements
let myCircles = [...document.getElementsByTagName('my-circle')];
myCircles.forEach((myCircle) => myCircle.addEventListener('click', toggleInvert, false));
// Define <my-circle> element
class myCircle extends HTMLElement {
constructor() {
super();
this.root = this.attachShadow({mode: "open"});
}
connectedCallback() {
this.root.appendChild(document.createElement('slot'));
}
}
customElements.define('my-circle', myCircle);
aside {
position: absolute;
top: 0;
right: 0;
width: 280px;
line-height: 24px;
}
div {
float: left;
margin: 0 12px 12px 0;
width: 80px;
height: 80px;
line-height: 80px;
text-align: center;
font-size: 36px;
border-radius: 50%;
cursor: pointer;
}
my-circle {
display: block;
float: left;
margin: 0 12px 12px 0;
width: 80px;
height: 80px;
line-height: 80px;
text-align: center;
font-size: 36px;
background: radial-gradient(#fff, #000);
border-radius: 50%;
cursor: pointer;
}
my-circle:first-of-type {
clear: left;
}
div:nth-of-type(1) {
background: radial-gradient(rgb(255, 255, 0), rgb(255, 0, 0));
}
div:nth-of-type(2) {
background: radial-gradient(rgb(255, 255, 0), rgb(0, 163, 0));
}
my-circle:nth-of-type(1) {
background: radial-gradient(rgb(255, 255, 0), rgb(223, 163, 0));
}
my-circle:nth-of-type(2) {
background: radial-gradient(rgb(255, 127, 127), rgb(255, 0, 0));
}
div[data-inverted="true"],
div[inverted="true"],
my-circle[data-inverted="true"],
my-circle[inverted="true"] {
filter: hue-rotate(180deg);
}
<div data-inverted="false">i</div>
<div inverted="false">ii</div>
<my-circle data-inverted="false">iii</my-circle>
<my-circle inverted="false">iv</my-circle>
<aside>
<p><strong>Click</strong> on each of the circles on the left to invert their backgrounds.</p>
</aside>
Although the set up above works technically, which of the following is true:
A) Custom attributes may be used universally, in standard elements and custom elements.
Conclusion: Elements i, ii, iii & iv are all valid
B) Custom attributes may only be used in custom elements. They are invalid elsewhere.
Conclusion: Elements i, iii & iv are valid, while ii is invalid
C) Data-* attributes are for standard elements, custom attributes are for custom elements.
Conclusion: Elements i & iv are valid, while ii & iii are invalid
D) Custom attributes are not even a thing. Where did you get this idea from?
Conclusion: Elements i & iii are valid, while ii & iv are invalid
Added:
To illustrate my question above, I'd like to give an example of where custom attributes appear not to be valid:
Go to: https://validator.w3.org/nu/#textarea
Select text input
Enter:
<!DOCTYPE html>
<html lang="">
<head>
<title>Test</title>
</head>
<body>
<div data-inverted="false">i</div>
<div inverted="false">ii</div>
</body>
</html>
Check the markup
The validator returns the error:
Error: Attribute inverted not allowed on element div at this point.
From line 10, column 1; to line 10, column 22
i</div>↩↩<div inverted="false">ii</di
Though... I'm not sure if the tool at https://validator.w3.org/nu/ is outdated and / or abandoned and the Error returned should no longer be regarded as an error in 2020 (?)
All 4 usages work, so why should they be invalid?
data- prefix gives the added bonus they are available in element.dataset.
-- Attributes are Attributes -- , nothing special in the Custom Elements API,
apart from observedAttributes(). Yes, you can use data-* attributes there to.
note
class myCircle extends HTMLElement {
constructor() {
super();
this.root = this.attachShadow({mode: "open"});
}
connectedCallback() {
this.root.appendChild(document.createElement('slot'));
}
}
can be written as:
class myCircle extends HTMLElement {
constructor() {
super()
.attachShadow({mode: "open"})
.append(document.createElement('slot'));
}
}
because super() returns 'this'
and attachShadow both sets and returns this.shadowRoot for free
you are not doing anything with appendChild() return value, so append() (which can take multiple parameters) is enough.
Also note there is a toggleAttribute method.
https://developer.mozilla.org/en-US/docs/Web/API/ParentNode/append
https://developer.mozilla.org/en-US/docs/Web/API/Element/toggleAttribute
I am making a simple component to test newest Lit-element a checkbox.
Upon testing static get styles only the first element I style is shown, I have seen in the documentation what I am trying should be correct, may I have some help?.
this is my component:
import {LitElement, html, css} from 'lit-element';
class CheckboxMJ extends LitElement {
static get properties(){
return{
check:{type:Boolean},
name:{type:String},
}
}
static get styles() {
return css`
.checkWrapper{
font-family: Roboto;
background-color: red;
font-weight: 500;
font-size:14px;
color:#283D3B;
border:none;
outline:none;
height: 150px;
width: 300px;
border-radius: 3px;
overflow:hidden;
padding:3px;
}
input[checkbox i]{
background-color:red;
}
`;
}
constructor(){
super();
this.check=false;
this.name="";
}
render() {
return html`
<div class="checkWrapper">
<input class="checkbox-mj" type="checkbox" name="${this.name}" value="${this.check}"> ${this.name}
</div>
`
}
}
customElements.define('checkbox-mj', CheckboxMJ);
I have been encountering this issue several times with other components, kept changing order, and names of classes until it worked but I feel so lost about how this should be done right, please somebody enlighten me on how to use this feature correctly.
You have to keep in mind that checkboxes are very difficult to stylize. Many properties simply have no effect on this input. On the other hand you have to use a standard css selector to stylize the checkbox input[type="checkbox"].
If you want the check property to be reflected in your checkbox you must do it this way:
?checked="${this.check}"
Look at this guides for more information https://lit-element.polymer-project.org/guide/templates (Bind properties to templated elements).
import {
LitElement,
html,
css
} from 'lit-element';
class CheckboxMJ extends LitElement {
static get properties() {
return {
check: {
type: Boolean
},
name: {
type: String
},
}
}
static get styles() {
return css `
.checkWrapper{
font-family: Roboto;
background-color: red;
font-weight: 500;
font-size:14px;
color:#283D3B;
border:none;
outline:none;
height: 150px;
width: 300px;
border-radius: 3px;
overflow:hidden;
padding:3px;
}
input[type="checkbox"]{
margin:1rem
}
`;
}
constructor() {
super();
this.check = true;
this.name = "Check";
}
render() {
return html `
<div class="checkWrapper">
<input class="checkbox-mj" type="checkbox" name="${this.name}" ?checked="${this.check}"> ${this.name}
</div>
`
}
}
customElements.define('checkbox-mj', CheckboxMJ);
In my application the user must select Product Categories from a DropDownList. So what I want to do is, if he doesen't select a category and tries to send his order, the DropDownList should be highlighted so he sees, that he has to select a category. My problem now is, not one the attempts I tried to style this DropDownList, did work yet. So I hope you can help me out or tell me where the problem is:
CSS-File:
.field-validation-error {color: #ffb3b3;}
.field-validation-valid {display: none;}
.input-validation-error {border: 1px solid #f00; background-color: #ffb3b3;}
.select.input-validation-valid { display: none;}
.select.input-validation-error { color: #ffb3b3; }
.validation-summary-error {font-weight: bold; color: #ffb3b3;}
.validation-summary-valid {display: none}
DropdownListFor in the view:
#if (Request.Form["SendOrder"] != null && String.IsNullOrEmpty(ProductCategory))
{
#Html.DropDownListFor(m => m.PC,
new SelectList(Model.ProductCategory.OrderBy(m => m.PCNumber),
"", "CategoryName",
new {#class = "field-validation-error, input-validation-error,
select.input-validation-error" }), "Select a Category")
}
else
{
#Html.DropDownListFor(m => m.PC,
new SelectList(Model.ProductCategory.OrderBy(m => m.PCNumber),
"", "CategoryName"), "Select a category")
}
For anyone interested in this, the problem is solved and the solution can be found here
I am trying to create a menu that highlights the current page. I have found a few answers here, but the problem is I can't see that anyone handles submenus.
There is an answer here that looks enticingly simple: active menu item - asp.net mvc3 master page
But as far as I can tell, that one will highlight only the sub menu item if you click on a submenu. I want the submenu item to be highlighted, as well as its parent in the top menu.
E.g. if someone clicks Services, and then Consulting, I would want both of these to be highlighted - Services in the top menu, and Consulting in the submenu. How can I do this?
BTW, I would like to be able to render the submenu both as a dropdown using CSS, and also as a sidebar. How can I take the submenu ul and render it as a sidebar?
Here is a simple thing, you can modify it according to your needs but basics are here.
http://developerstyle.posterous.com/highlighting-current-page-in-mvc-3-slick-tric
This above link might be down soon as posterous is closing, here is an update link
http://bhavinsurela.com/highlighting-current-page-in-mvc-3-slick-tric/
I have a solution which I in part also found here in SO and modified, but still as to be improved in order to handle any number of submenus... right now it works for a submenu.
namespace PhotoBuss.Web.Back.Controllers
{
public class NavigationController : BaseAdministrationController
{
//
// GET: /Common/
[ChildActionOnly]
public ActionResult HeaderMenu()
{
// http://stackoverflow.com/questions/4653226/asp-net-mvc-menu-selected-item
var items = new List<MenuItemViewModel>
{
new MenuItemViewModel{ Text = "home", Action="Index", Controller="Administration", Selected=false},
new MenuItemViewModel{Text = "manage", Action="Index", Controller="Manage", Selected=false,
SubMenu =
new List<MenuItemViewModel>
{
new MenuItemViewModel{ Text= "photos", Action="Index", Controller="Photos", Selected = false },
new MenuItemViewModel { Text = "collections", Action="Index", Controller="Collections", Selected=false},
new MenuItemViewModel { Text = "keywords", Action="Index", Controller="Keywords", Selected=false},
new MenuItemViewModel { Text = "users", Action="Index", Controller="Users", Selected=false},
new MenuItemViewModel { Text = "user groups", Action="Index", Controller="Roles", Selected=false}
}
},
new MenuItemViewModel{Text="cms", Action="Index", Controller="CMS", Selected=false}
};
string action = ControllerContext.ParentActionViewContext.RouteData.Values["action"].ToString();
string controller = ControllerContext.ParentActionViewContext.RouteData.Values["controller"].ToString();
foreach (var item in items)
{
if (item.Controller == controller && item.Action == action)
{
item.Selected = true;
}
foreach(var subItem in item.SubMenu)
if (subItem.Controller == controller && subItem.Action == action)
{
item.Selected =
subItem.Selected = true;
}
}
return PartialView(items);
}
}
The ViewModel
public class MenuItemViewModel
{
public MenuItemViewModel()
{
SubMenu = new List<MenuItemViewModel>();
}
public string Text { get; set; }
public string Controller { get; set; }
public string Action { get; set; }
public bool Selected { get; set; }
public List<MenuItemViewModel> SubMenu { get; set; }
}
}
The View
#model List<PhotoBuss.Web.Back.Models.Navigation.MenuItemViewModel>
<link href="#Url.Content("~/Areas/Admin/Content/CSS/menu.css")" rel="stylesheet" type="text/css" />
<div class="headerMenu">
<ul>
#foreach (var menuItem in Model)
{
<li>#Html.ActionLink(menuItem.Text, menuItem.Action, menuItem.Controller, null,
new { #class = menuItem.Selected ? "selected" : "" })
#if (menuItem.SubMenu.Count >0)
{
<ul class="#(menuItem.Selected ? "selected" : "")">
#foreach (var subMenu in menuItem.SubMenu)
{
<li>#Html.ActionLink(subMenu.Text, subMenu.Action, subMenu.Controller, null,
new { #class = subMenu.Selected ? "selected" : "" })</li>
}
</ul>
}
</li>
}
</ul>
</div>
The CSS I'm using with this at the moment:
.headerMenu *
{
padding: 0;
margin: 0;
}
.headerMenu
{
position: relative;
background-color: #78C8FA;
width: 100%;
text-align: center;
color: #FFFFFF;
clear: both;
float: left;
margin-top: 10px;
}
.headerMenu ul
{
display: block;
list-style: none;
line-height: 3em;
height: 3em;
}
.headerMenu ul li
{
display: inline-block;
margin-left: 15px;
margin-right: 15px;
}
.headerMenu ul li a
{
display: block;
text-decoration: none;
color: white;
font-size: 1.5em;
padding-left:2em;
padding-right:2em;
}
.headerMenu ul li a:visited
{
color: white;
}
.headerMenu ul li a:hover, .menu ul li
{
color: #333333;
}
.selected
{
color: #333333 !important;
display:block !important;
background-color: #999999;
}
.headerMenu ul ul
{
display: none;
position: absolute;
width: 100%;
right: 50%;
left: 0;
background-color: #999999;
}
.headerMenu li:hover > ul, .selected
{
display: block;
}
It's fairly simple to determine which menu element to highlight by simply using the ViewContext.RouteData.Values dictionary, specifically the Action and Controller keys.
Here's a quick helper method :
public static string IsSelected(this RouteValueDictionary dictionary, string controller, string action)
{
string cssClass = "selected";
string routeValueController = dictionary["Controller"] as string;
string routeValueAction = dictionary["Action"] as string;
return string.IsNullOrEmpty(action) ?
routeValueController == controller ? cssClass : string.Empty :
routeValueController == controller && routeValueAction == action ? cssClass : string.Empty;
}
And can be used from the view as such :
<ul id="menu">
<li class="#this.ViewContext.RouteData.Values.IsSelected("Default", "Index")">
Accueil
</li>
</ul>
It's hard to get into a more specific solution as I'm not familiar with your application structure, but this should give you an idea to get started.
Here is a example where they handle the submenus and highlight it.
http://users.tpg.com.au/j_birch/plugins/superfish/#sample4
It uses superfish-navbar.css where you can see how it is done.
It is a very good plugin for menus.
CSS is defaulting to input[type="text"] style. How can I make the .wideTextBox take precedence?
#Html.TextBoxFor(model => model.ConsumerBatchInVM.OptInSmsMessage, new { #class = "wideTextBox" })
.wideTextBox
{
width: 400px;
}
input[type="text"]
{
width: 300px;
border: 1px solid #CCC;
}
You could do:
input[type="text"] {
..
}
input.wideTextBox {
..
}
That is, swap the order and change .wideTextBox to input.wideTextBox.
Swapping the order alone won't work, and neither will input.wideTextBox alone.
More information on CSS specificity: http://css-tricks.com/855-specifics-on-css-specificity/
A specificity calculator: http://www.suzyit.com/tools/specificity.php