Tapestry: How to write HTML from java page - html

I need to write HTML from my .java page. Here is what I have tried
This is my tml code fragment
${testFunction()}
This is my java code fragment
public String testFunction()
{
return "<input type='checkbox' name='leaf' id='leaf' value='leaf'/>"
}
The result I want is a checkbox. What I get is a string "input type='checkbox' name='leaf' id='leaf' value='leaf'".
Any help would be appreciated Thanks.

If you want to render string as html you need to use MarkupWriter#writeRaw() method:
void beginRender(MarkupWriter writer) {
writer.writeRaw("<input type='checkbox' name='leaf' id='leaf' value='leaf'/>");
}
Or you can use OutputRaw component:
<t:outputraw value="testFunction()"/>
Or you can use Renderable to write markup:
#Property(write = false)
private final Renderable checkbox = new Renderable() {
public void render(MarkupWriter writer) {
writer.element("input",
"type", "checkbox",
"id", "leaf",
"name", "leaf",
"value", "leaf");
writer.end();
// if you need checked attribute
// writer.getElement().attribute("checked", "checked");
}
};
And on template:
<t:delegate to="checkbox"/>

Related

How to include CSS style inside HTML style (code generated via ASP.Net MVC Razor page)

I'm still at my early beginning with ASP.Net MVC. So, I'm not sure if I'm following good practices or not.
I want to generate HTML code based on CSS style
Razor page:
#foreach (p in ...)
{
<td style="#Helper.CustomBackground(p) #Helper.CustomComplexStyle(p)">...</td>
}
CSS classes:
.complexStyleA {
// ...
}
.complexStyleB { }
C# helper method:
// None of the styling method has the "style" attribute, so I can concatenate several custom-styles
public static class Helper
{
// Basic direct styling
public static string CustomBackground(object p) => "{ background: red; }";
// More complex styling based on CSS ones
public static string CustomComplexStyle(object p) => "{ // complexStyleA, complexStyleB, etc. based on p; }"
}
I don't really mind generated all the code inside the HTML tags, but generate a table with several thousand lines and can obviously reduce the file size!
Thanks for any insights :-)
UPDATE
I think that I will do something as follow :
<td #Html.Raw(#Hepers.ConcatenateCSSClasses(#CustomComplexStyle(p),
#OtherCustomComplexStyle(p),
...))>
...
</td>
where #concatenateCSSClasses() removes all " class=" ans #...Syle(p) returns "class=\"...StyleXYZ\"", unless I can have duplicated tag attributes.. Any better ideas?
UPDATE with cleaner methods
public static string HTMLTagAttribute(FieldType fieldType, Field field = null)
{
string output = "";
// Makes distinction between hearder and body
if (field == null)
{
output += HTMLHeaderTagClassAttributes(fieldType);
output += HTMLHeaderTagStyleAttributes(fieldType);
}
else
{
output += HTMLBodyTagClassAttributes(fieldType, field);
output += HTMLBodyTagStyleAttributes(fieldType, field);
}
return output;
}
Body only shown with clear distinction between classes and (inline styles). I don't detail the samll method HTMLWidth(), HTMLBackground(), etc. which are self explanatory.
#region HTML Body Tag Attribute Methods
private static string HTMLBodyTagStyleAttributes(FieldType fieldType, Field field)
{
AttributeValues style = new AttributeValues("style");
style += HTMLWidth(fieldType);
style += HTMLBackground(fieldType, field);
style += HTMLAlign(fieldType);
return style.ToString();
}
private static string HTMLBodyTagClassAttributes(FieldType fieldType, Field field)
{
AttributeValues cls = new AttributeValues("class");
cls += HTMLTopBorder(fieldType, field);
cls += HTMLSideBorder(fieldType);
return cls.ToString();
}
#endregion
Class which helps concatenate class and style attribute values (with no extra space).
/// <summary>Class to help format HMTL class and style attribute values</summary>
class AttributeValues
{
private readonly string _attribute = "";
private readonly List<string> _values = new List<string>();
// TODO - Make distinction bewteen class and styles
#region Constructors
public AttributeValues(string attribute)
{
_attribute = attribute;
}
#endregion
public static AttributeValues operator +(AttributeValues values, string value)
{
if (value != "") values._values.Add(value);
return values;
}
public static bool operator ==(AttributeValues values, string value) => values == value;
public static bool operator !=(AttributeValues values, string value) => values != value;
#region Public Overridden Methods
public override string ToString()
{
string values = "";
foreach (string value in _values)
{
if (values != "") values += " ";
values += value;
}
return values != "" ? $"{ _attribute }=\"{ values }\"" :"" ;
}
public override bool Equals(object obj) => base.Equals(obj);
public override int GetHashCode() => base.GetHashCode();
#endregion
}
And finally in the Razor page (apparently, I have to wrap it in HTML.Raw() because of the " (I agree that it could be refractor within the th, but doesn't make the code easier):
<td Html.Raw(Helpers.HTMLTagAttribute(Enums.FieldType.Account))>..</td>

Razor syntax - how to conditionally wrap some inner HTML

In Razor, there's a curious rule about only allowing closed HTML within an if block.
See:
Razor doesn't understand unclosed html tags
But I have a situation where I want to exclude some outer, wrapping elements under certain conditions. I don't want to repeat all the inner HTML, which is a fair amount of HTML and logic.
Is the only way around the problem to make yet another partial view for the inner stuff to keep it DRY?
Without any other re-use for this new partial, it feels really awkward, bloaty. I wonder if the rule is a limitation of Razor or simply a nannying (annoying) feature.
You can use Html.Raw(mystring). In myString you can write whatever you want, for example a tag opening or closing, without getting any errors at all. I.e.
if (condition) {
#Html.Raw("<div>")
}
if (condition) {
#Html.Raw("</div>")
}
NOTE: the #Html.Raw("<div>") can be written in a shorter, alternative form, like this: #:<div>
You can also create your own html helpers for simplifying the razor syntax. These helpers could receive the condition parameter, so that you can do something like this:
#Html.DivOpen(condition)
#Html.DivClose(condition)
or more complicated helpers that allow to specify attributes, tag name, and so on.
Nor the Raw, neither the html helpers will be detected as "tags" so you can use them freely.
The Best Way to do it
It would be much safer to implement something like the BeginForm html helper. You can look at the source code. It's easy to implement: you simply have to write the opening tag in the constructor, and the closing tag in the Dispose method. The adavantage of this technique is that you will not forget to close a conditionally opened tag.
You need to implement this html helper (an extension method declared in a static class):
public static ConditionalDiv BeginConditionalDiv(this HtmlHelper html,
bool condition)
{
ConditionalDiv cd = new ConditionalDiv(html, condition);
if (condition) { cd.WriteStart(); }
return cd; // The disposing will conditionally call the WriteEnd()
}
Which uses a class like this:
public class ConditionalDiv : IDisposable
{
private HtmlHelper Html;
private bool _disposed;
private TagBuilder Div;
private bool Condition;
public ConditionalDiv(HtmlHelper html, bool condition)
{
Html = html;
Condition = condition;
Div = new TagBuilder("div");
}
public void Dispose()
{
Dispose(true /* disposing */);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
_disposed = true;
if (Condition) { WriteEnd(); }
}
}
public void WriteStart()
{
Html.ViewContext.Writer.Write(Div.ToString(TagRenderMode.StartTag));
}
private void WriteEnd()
{
Html.ViewContext.Writer.Write(Div.ToString(TagRenderMode.EndTag));
}
}
You can use this with the same pattern as BeginForm. (Disclaimer: this code is not fully tested, but gives an idea of how it works. You can accept extra parameters for attributes, tag names and so on).
Declare razor helper using #helper HeplerName(), call by #HeplerName() anywhere. And you can add params if you want.
#if (condition)
{
<div class="wrapper">
#MyContent()
</div>
}
else
{
#MyContent()
}
#helper MyContent()
{
<img src="/img1.jpg" />
}
Edit (thanks to #Kolazomai for bringing up the point in comments):
ASP.NET Core 3.0 no longer supports #helper but supports HTML markup in method body. New case will look like this:
#if (condition)
{
<div class="wrapper">
#{ MyContent(); }
</div>
}
else
{
#{ MyContent(); }
}
#{
void MyContent()
{
<img src="/img1.jpg" />
}
}
The following code is based on the answer of #JotaBe, but simplified and extendable:
public static class HtmlHelperExtensions
{
public static IDisposable BeginTag(this HtmlHelper htmlHelper, string tagName, bool condition = true, object htmlAttributes = null)
{
return condition ? new DisposableTagBuilder(tagName, htmlHelper.ViewContext, htmlAttributes) : null;
}
}
public class DisposableTagBuilder : TagBuilder, IDisposable
{
protected readonly ViewContext viewContext;
private bool disposed;
public DisposableTagBuilder(string tagName, ViewContext viewContext, object htmlAttributes = null) : base(tagName)
{
this.viewContext = viewContext;
if (htmlAttributes != null)
{
this.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
}
this.Begin();
}
protected virtual void Begin()
{
this.viewContext.Writer.Write(this.ToString(TagRenderMode.StartTag));
}
protected virtual void End()
{
this.viewContext.Writer.Write(this.ToString(TagRenderMode.EndTag));
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
this.disposed = true;
this.End();
}
}
}
This can be used the following way within Razor views:
#using (Html.BeginTag("div"))
{
<p>This paragraph is rendered within a div</p>
}
#using (Html.BeginTag("div", false))
{
<p>This paragraph is rendered without the div</p>
}
#using (Html.BeginTag("a", htmlAttributes: new { href = "#", #class = "button" }))
{
<span>And a lot more is possible!</span>
}
This is IMO the most convenient way to achieve this:
[HtmlTargetElement(Attributes = RenderAttributeName)]
public class RenderTagHelper : TagHelper
{
private const string RenderAttributeName = "render";
private const string IncludeContentAttributeName = "include-content";
[HtmlAttributeName(RenderAttributeName)]
public bool Render { get; set; }
[HtmlAttributeName(IncludeContentAttributeName)]
public bool IncludeContent { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (!Render)
{
if (IncludeContent)
output.SuppressOutput();
else
output.TagName = null;
}
output.Attributes.RemoveAll(RenderAttributeName);
output.Attributes.RemoveAll(IncludeContentAttributeName);
}
}
Then, you just use it like this:
<div render="[bool-value]" include-content="[bool-value]">
...
</div>

Using a ViewBag with an Extension Method in RAZOR with ASP.NET MVC

I'm trudging my way through learning ASP.NET MVC. I've recently written an extension method that helps me decide if a item in a drop down list should be selected. I know about the HTML helper methods. I'm simply trying to learn how things work here. Anyways, I currently have the following code:
<select id="Gender">
<option value="-1" #Html.IsSelected(Convert.ToString(ViewBag.Gender), "-1")>Unspecified</option>
<option value="0" #Html.IsSelected(Convert.ToString(ViewBag.Gender), "0")>Male</option>
<option value="1" #Html.IsSelected(Convert.ToString(ViewBag.Gender), "1")>Female</option>
</select>
When I execute this, I get a compilation error on the view that says:
CS1973: 'System.Web.Mvc.HtmlHelper<dynamic>' has no applicable method named 'IsSelected' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax.
My question is, how do I execute an extension method with a value from ViewBag? If I replace ViewBag.Gender with a hard-coded value it works. Which makes me think that the problem is with the fact that ViewBag is a dynamic type. But, what other option do I have?
I'd the same problem.
Use a ViewData instead..
for example, replace
#using (Html.BeginSection(tag:"header", htmlAttributes:#ViewBag.HeaderAttributes)) {}
with
#using (Html.BeginSection(tag:"header", htmlAttributes:#ViewData["HeaderAttributes"])) {}
it works fine ;)
Here is something that may help:
public static class HtmlHelperExtensions
{
public static MvcHtmlString GenderDropDownList(this HtmlHelper html, string name, int selectedValue, object htmlAttributes = null)
{
var dictionary = new Dictionary<sbyte, string>
{
{ -1, "Unspecified" },
{ 0, "Male" },
{ 1, "Female" },
};
var selectList = new SelectList(dictionary, "Key", "Value", selectedValue);
return html.DropDownList(name, selectList, htmlAttributes);
}
public static MvcHtmlString GenderDropDownListFor<TModel>(this HtmlHelper<TModel> html, Expression<Func<TModel, bool?>> expression, object htmlAttributes = null)
{
var dictionary = new Dictionary<sbyte, string>
{
{ -1, "Unspecified" },
{ 0, "Male" },
{ 1, "Female" },
};
var selectedValue = ModelMetadata.FromLambdaExpression(
expression, html.ViewData
).Model;
var selectList = new SelectList(dictionary, "Key", "Value", selectedValue);
return html.DropDownListFor(expression, selectList, htmlAttributes);
}
}
Use it like this:
#Html.GenderDropDownList("Gender", 0)
or:
#Html.GenderDropDownListFor(m => m.Gender)

How to serialize an anonymous type to JSON, when JSON *needs* properties with characters like dashes '-' e.t.c

I am building an app that uses Open Flash Chart 2. This chart is a flash object that accepts JSON with a specific structure.
"elements": [
{
"type": "bar_stack",
"colours": [
"#F19899",
"#A6CEE3"
],
"alpha": 1,
"on-show": {
"type": "grow-up",
"cascade": 1,
"delay": 0
},
...
I am using a simple anonymous type to return the JSON like so:
return Json(new
{
elements = new [] {
new
{
type = "bar_stack",
colours = colours.Take(variables.Count()),
alpha = 1,
on_show = new
{
type = "grow-up",
cascade = 1,
delay = 0
},
...
}
}
The problem is that several properties (like "on-show") use a dash and obviously I cannot use a dash when naming a property in C# code.
Is there a way to overcome this? Preferably without the need to declare a whole bunch of classes.
You can use a dictionary:
return Json(new {
elements = new [] {
new Dictionary<string, object>
{
{ "type", "bar_stack" },
{ "colours", new [] { "#F19899", "#A6CEE3" } },
{ "alpha", 1 },
{ "on-show", new
{
type = "grow-up",
cascade = 1,
delay = 0
} },
}
}
});
(Written in SO editor; I may have made some syntax errors, but you get the idea....)
Craig's solution is propably better, but in the meantime I implemented this:
public class UnderscoreToDashAttribute : ActionFilterAttribute
{
private readonly string[] _fixes;
public UnderscoreToDashAttribute(params string[] fixes)
{
_fixes = fixes;
}
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
filterContext.HttpContext.Response.Filter = new ReplaceFilter(filterContext, s => _fixes.Aggregate(s, (current, fix) => current.Replace(fix, fix.Replace('_', '-'))));
}
public class ReplaceFilter : MemoryStream
{
private readonly Stream _stream;
private readonly Func<string, string> _filter;
public ReplaceFilter(ControllerContext filterContext, Func<string, string> filter)
{
_stream = filterContext.HttpContext.Response.Filter;
_filter = filter;
}
public override void Write(byte[] buffer, int offset, int count)
{
// capture the data and convert to string
var data = new byte[count];
Buffer.BlockCopy(buffer, offset, data, 0, count);
var s = _filter(Encoding.Default.GetString(buffer));
// write the data to stream
var outdata = Encoding.Default.GetBytes(s);
_stream.Write(outdata, 0, outdata.GetLength(0));
}
}
}
Then, if you decorate your action like so:
[UnderscoreToDash("on_show", "grid_colour")]
public JsonResult GetData()
It makes the appropriate "fixes".
P.S. That awesome moment when Resharper changes your code to Linq...
_fixes.Aggregate(s, (current, fix) => current.Replace(fix, fix.Replace('_', '-')))

Set optional disabled attribute

I want to disable all fields in my form, which have values when page is loaded.
For example in this
<td>#Html.TextBoxFor(m => m.PracticeName, new { style = "width:100%", disabled = Model.PracticeName == String.Empty ? "Something Here" : "disabled" })</td>
I want to write inline something like this. I don't want to use if-else and make my code larger.
Using javascript/jquery doesn't welcome too.
I tried to write false/true, but 1.It maybe isn't cross-browser 2.Mvc parsed it to string like "True" and "False".
So how can I do it?
P.S. I use ASP.NET MVC 3 :)
Seems like a good candidate for a custom helper:
public static class HtmlExtensions
{
public static IHtmlString TextBoxFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> ex,
object htmlAttributes,
bool disabled
)
{
var attributes = new RouteValueDictionary(htmlAttributes);
if (disabled)
{
attributes["disabled"] = "disabled";
}
return htmlHelper.TextBoxFor(ex, attributes);
}
}
which could be used like this:
#Html.TextBoxFor(
m => m.PracticeName,
new { style = "width:100%" },
Model.PracticeName != String.Empty
)
The helper could obviously be taken a step further so that you don't need to pass an additional boolean value but it automatically determines whether the value of the expression is equal to default(TProperty) and it applies the disabled attribute.
Another possibility is an extension method like this:
public static class AttributesExtensions
{
public static RouteValueDictionary DisabledIf(
this object htmlAttributes,
bool disabled
)
{
var attributes = new RouteValueDictionary(htmlAttributes);
if (disabled)
{
attributes["disabled"] = "disabled";
}
return attributes;
}
}
which you would use with the standard TextBoxFor helper:
#Html.TextBoxFor(
m => m.PracticeName,
new { style = "width:100%" }.DisabledIf(Model.PracticeName != string.Empty)
)
I used Darin's answer. However, when it came to data_my_custom_attribute, they were not rendered as data-my-custom-attribute. So I changed Darin's code to handle this.
public static RouteValueDictionary DisabledIf(
this object htmlAttributes,
bool disabled
)
{
RouteValueDictionary htmlAttributesDictionary
= HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
if (disabled)
{
htmlAttributesDictionary["disabled"] = "disabled";
}
return new RouteValueDictionary(htmlAttributesDictionary);
}