Ok.. here we go.. the weirdest and most confusing question of the month :)
I would like to create a HtmlHelper that some how renders html, but uses a partial view for its template of how the html should be rendered, so to put it more simple.. I would like to do exactly the same as a "normal" Controller and view does.. get some data, pass it to the view and then render the html, but in this case I would like to pass some data to a partial view, and then get the returned html as a string and then return that html from a HtmlHelper method...
In this way I would like to be able to write for instance #Html.HeadMenu, that then would return the html for the headmenu, but I would also be able to at anytime without recompiling be able to change the html.. since its all in a partial view.. and I wont have to worry about any server-side things.. and I will also get the benefit of the intellisense since my method will show up in #Html.
I hope you will understand this..since its kind of hard to explain..
Thanks in advance!
How about the Partial HTML-extension method, it sounds like what you are trying to achive right?
#{
var htmlString = Html.Partial("YourPartialViewName").ToString();
}
It also has an overload so that you can pass a model to the partial view:
#{
var htmlString = Html.Partial("YourPartialViewName", partialViewModel).ToString();
}
You could be looking for the Html.RenderAction(actionName, controllerName, routeValues) method.
I would do it this way
Define data that you imagine to pass to your htmlhelper
public class HeadMenuViewModel
{
public string SomeProperty {get;set;}
}
Define view named HeadMenuViewModel.cshtml in Views/Shared/DisplayTemplates
#model HeadMenuViewModel
<div>
////
</div>
From now, you can display your data using
#Html.DisplayFor(model => model.HeadMenu)
And you could write named shortcut-extension for it
using System.Web.Mvc.Html;
...
public static MvcHtmlString HeadMenu<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression)
{
return helper.DisplayFor(expression);
}
Now, change your HeadMenuViewModel.cshtml everytime you need to
Related
I have strongly typed list view
I have custom html helper which must get IEnumerable<object>
does it possible to pass my model(#model IEnumerable<MvcApplication2.Models.UserViewModel>) to my html helper?
If your helper is defined like this:
public static IHtmlString SomeHelper(this HtmlHelper<IEnumerable<object>> html)
then it is not possible to call it like this:
#model IEnumerable<MvcApplication2.Models.UserViewModel>
#Html.SomeHelper()
If on the other hand it is defined like this:
public static IHtmlString SomeHelper(this HtmlHelper html, IEnumerable<object> model)
you could call it from your view and pass the model:
#model IEnumerable<MvcApplication2.Models.UserViewModel>
#Html.SomeHelper(Model)
Does anyone have a simple way of adding a css class to a html label when validation fails, preferably from within the model, in the public IEnumerable Validate(ValidationContext context) override, not with jQuery or in the Controller.
I have my validationsummary giving me the error message I just want to put * next to the failed input and make its label text bold and red.
#Html.LabelFor(model => model.Name)
<div class="editor-field">
#Html.EditorFor(model => model.Name)<br/><br />
</div>
If you have not yet found a solution, look at http://weblogs.asp.net/imranbaloch/archive/2010/07/03/asp-net-mvc-labelfor-helper-with-htmlattributes.aspx
It codes an HTML Helper extension to LabelFor that supports html attributes. You could use this code as a template to modify for your needs. One option would be to detect whether a validation error has occured. A few days ago I wrote something similar:
public static string IsInvalidFor<TModel, TValue>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TValue>> expression,
string cssErrorClass)
{
if (ValidationExtensions.ValidationMessageFor(htmlHelper, expression) != null)
return cssErrorClass;
else return "";
}
if you want to do it in .cs file Model in this case just append this
string name = //ur name property//;
oppdesc = "";
oppdesc += "<span class ="error"+ "\">" + name+ "</span>";
and u define class error as bold and red in ur css.
In my application I have a lot of UI elements (particuarly buttons) where I am repeating the same code over and over.
For example in multiple views I might have an edit button that is created with the following code:
#Html.ActionLink("Edit", "Edit", "SomeController", null, new { #class="button large blue" });
The problem here is that I am hard coding the label and styling, so if I want to make changes to the button styling or label, I would have to make them in multiple views. This would be tedious to do, as I would have to track down every button.
So now I am looking at creating a templating mechanism, where I can define a button template in a central area and bring it in to any view I want to use it in.
I have considered two options, which I have tried to sketch out in semi-real world code below.
My question is, am I on the right track here? Which option would be better and for which reasons? Is there already something out there I could consider using, or is there another way which I haven't thought of?
Thanks for your help.
Web.Config Templates
Create a custom class that can bring in template configuration from web.config file. For example:
<ui.HtmlTemplates>
<add templateKey="FormCancel" tag="a" class="form-button large black" />
<add templateKey="FormSave" tag="input" type="submit" class="form-button large green" />
</ui.HtmlTemplates>
And then could call them in with syntax such as this (method signature is contrived)
#HtmlTemplates.Build("FormCancel", Url.Action("Index", "Home"))
Partial View Templates
Create strongly typed partial views with the template I want.
ViewModel
public class UiButtonModel
{
public string Url{ get; set; }
}
Partial View
// Assume the file is called "_Button_FormCancel"
#Model path.to.model.directoy.UiButtonModel
Cancel
Use
#Html.Partial("_Button_FormCancel", new UiButtonModel(){Url = Url.Action("Index", "Home"));
Another option is to create extension methods off of HtmlHelper to create prepackaged HTML output using code:
using System.Web.Mvc;
using System.Web.Routing;
public static class MyHtmlExtensions
{
public static string SaveButton(this HtmlHelper helper, string title = "Save", IDictionary<string, object> htmlAttributes = null)
{
var builder = new TagBuilder("button");
builder.Attributes.Add("type", "button");
builder.AddCssClass("form-button");
builder.AddCssClass("large");
builder.AddCssClass("green");
if (htmlAttributes != null) builder.MergeAttributes(htmlAttributes);
builder.SetInnerText(helper.Encode(title));
return builder.ToString();
}
public static string CancelButton(this HtmlHelper helper, string title = "Cancel", string actionName, string controllerName, RouteValueDictionary routeValues = null, IDictionary<string, object> htmlAttributes = null)
{
var urlHelper = new UrlHelper(helper.ViewContext.RequestContext, helper.RouteCollection);
var builder = new TagBuilder("a");
builder.Attributes.Add("href", urlHelper.Action(actionName, controllerName, routeValues));
builder.AddCssClass("form-button");
builder.AddCssClass("large");
builder.AddCssClass("green");
if (htmlAttributes != null) builder.MergeAttributes(htmlAttributes);
builder.SetInnerText(helper.Encode(title));
return builder.ToString();
}
}
Then just make sure the namespace of MyHtmlExtensions is either added to your page directly, or included in all pages via web.config, and use it like this in your view (razor syntax):
<div class="form-buttons">
#Html.CancelButton("Index", "Home")
#Html.SaveButton()
</div>
This method is particularly well suited for creating output consistently across several solutions, as all you need to do is reference the containing assembly and import the namespace.
I create these kinds of templates and put them in my Views/Shared folder.
I have templates like:
AddButton.cshtml
DeleteButton.cshtml
SaveButton.cshtml
...
Then, when I need to call one of them in whatever View, I just call this for example:
#Html.Partial("SaveButton");
Using T4MVC, it gets even better with compile time checking (no more literal strings):
#Html.Partial(MVC.Shared.Views.SaveButton)
Doing so I have a common/central place to change a specific button config. No need to go view after view to change something.
This is the problem that css was designed to handle. I fail to understand the problem. If you want to make changes, you change the CSS and it affects all the buttons that have that styling.
Part of your problem is that you're using style like "blue". If you want to change it to red, you have to change it everywhere.
Instead, you should have a class for the button, then you can simply change the button style and you don't have to worry about redefining blue to red.
I wrote a custom DataAnnotation that works perfectly fine unless I use a ViewModel rather then the actual Model itself.
With a Model, the data annotation renders something to the effect of:
<label class="tooltip" for="title">Enter a title.</label>
When I use a ViewModel, the data annotation is still rendering the same thing. The problem here is the "for" should be something like "Product_title" instead of "title".
Here's the HTMLHelper I wrote that renders the label from the data annotation:
(Taken from asp.net MVC extending DataAnnotions)
public static MvcHtmlString TooltipFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression) {
var exp = (MemberExpression)expression.Body;
foreach (Attribute attribute in exp.Expression.Type.GetProperty(exp.Member.Name).GetCustomAttributes(false)) {
if (typeof(Tooltip) == attribute.GetType()) {
return MvcHtmlString.Create("<label class=\"tooltip\" for=\"" + exp.Member.Name + "\">" + ((Tooltip)attribute).Description + "</label>");
}
}
return MvcHtmlString.Create("");
}
I dug around in the expression object to figure out which property holds the model property name which would end up being the input ID; "exp.Member.Name".
Now that I'm using a ViewModel, I apparently need something different, because "exp.Member.Name" is still returning "title" instead of "Product_title", which ends up being the ID of the input field.
So, is there a property I can get at that I can use instead of "Member.Name" that will always return the proper ID, or will I have to get around this issue with JavaScript (which I can do if everything else fails)?
I recently implemented something similar, taking the "Description" attribute of the Display annotation and outputting it to the screen:
public static MvcHtmlString DescriptionFor<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression) {
var metadata = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
var description = metadata.Description;
return MvcHtmlString.Create(description);
}
I output these helpers to tooltip type controls. I considered implementing my own tooltip attribute, but it seemed to be more than I needed...
So, I am having a hard time getting this to work. I am trying to add some typographic HTML codes to some labels I have strongly typed to my model.
<%: Html.LabelFor(m => m.Name) %>
I am using data annotations to customize the DisplayName of the property.
[DisplayName("Your friend’s name")]
public string Name { get; set; }
However the actual code is being displayed for the label:
Your friend’s name
I have also tried just using the old write method:
<%= Html.LabelFor(m => m.Name) %>
Any help is appreciated.
LabelFor will always encode the string to Html. You may wish to create an override for this helper, to output the string not encoded. Such as Html.HtmlLabelFor()
Source code for MVC is available too if you need to look at the innards of the original helper.
http://www.codeplex.com/aspnet
If you are using MVC3 and Razor then all strings are encoded to HTML when rendered on the page. Then you should to look into the HtmlString class if you return this to a helper class then it will render as HTML.
http://davidhayden.com/blog/dave/archive/2010/12/27/HtmlRawRazorViewEngine.aspx
There seems to be no way to do this. I simple used the actual rendered codes and it displayed fine.
[DisplayName("Your friend’s name")]
public string Name { get; set; }