.NET Tag Helper to replicate #Html.DisplayFor - html-helper

I'm discovering .Net Core Tag Helpers and I was just curious to know if there are any tag helpers that replicate the #Html.DisplayFor. I think that the label tag helper replicates #Html.DisplayNameFor since it shows the property name on a model passed to the page, but is there an equivalent for #Html.DisplayFor for displaying a property value?
I'm assuming there isn't because in the microsoft .net core tutorials, razor pages that need to display the property value rather than the property name use the HTML helpers.

First, the tag helper is actually the "label asp-for". You can create a new tag helper that is a "label asp-text" helper.
Another option is to use another tag such as span and create a custom "span asp-for" tag helper.
Here is a simple span implementation:
[HtmlTargetElement("span", Attributes = FOR_ATTRIBUTE_NAME, TagStructure = TagStructure.NormalOrSelfClosing)]
public class CustomSpanTagHelper : InputTagHelper
{
private const string FOR_ATTRIBUTE_NAME = "asp-for";
public CustomSpanTagHelper(IHtmlGenerator generator) : base(generator)
{
}
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
var metadata = base.For.Metadata;
if (metadata == null)
{
throw new InvalidOperationException(string.Format("No provided metadata " + FOR_ATTRIBUTE_NAME));
}
if (!string.IsNullOrWhiteSpace(metadata.Description))
{
output.Content.Append(metadata.Description);
}
if (metadata.IsEnum)
{
var description = (this.For.Model as Enum).GetDescription();
output.Content.Append(description);
}
base.Process(context, output);
}
}
You will need to register your custom tag helper in your _ViewImports.cshtml like this: (don't forget to rebuild)
#namespace MyProject.Web.Pages
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
#addTagHelper MyProject.Web.TagHelpers.CustomSpanTagHelper, MyProject.Web <-- custom import

Related

Add another ViewModelLocator convention in Prism (not override)

The project (WPF) has these folders:
Views
ViewModels
SubViews
SubViewModels
How to get the Prism's ViewModelLocator working with them (Views> ViewModels & SubViews> SubViewModels), the solution I found only works with one convention:
protected override void ConfigureViewModelLocator()
{
base.ConfigureViewModelLocator();
ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType) =>
{
var viewName = viewType.FullName.Replace(".ViewModels.", ".CustomNamespace.");
var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
var viewModelName = $"{viewName}ViewModel, {viewAssemblyName}";
return Type.GetType(viewModelName);
});
}
You could opt for registration of the pairs (not as bad as it sounds because you have to register for navigation anyway).
Alternatively, you implement both conventions one after the other - take the view's name, subtract "Views" and add "ViewModels" and try to get the view model's type. If that fails, subtract "SubViews" and add "SubViewModels" and try again. You could even check for cross combinations (e.g. "SubViews.ViewA" and "ViewModels.ViewAViewModel")...
I solved it by checking the viewType and based on it, I return the appropriate ViewModel type:
protected override void ConfigureViewModelLocator()
{
base.ConfigureViewModelLocator();
ViewModelLocationProvider.SetDefaultViewTypeToViewModelTypeResolver((viewType) =>
{
string prefix;
if (viewType.FullName.Contains(".SubViews."))
{
prefix = viewType.FullName.Replace(".SubViews.", ".SubViewModels.");
}
else
{
prefix = viewType.FullName.Replace(".Views.", ".ViewModels.");
}
var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;
var viewModelName = $"{prefix}ViewModel, {viewAssemblyName}";
return Type.GetType(viewModelName);
});
}

Custom attributes are removed when using custom blots

I created a custom blot for links that requires to be able to set rel and target manually. However when loading content that has those attributes, quill strips them. I'm not sure why.
I created a codepen to illustrate the issue.
This is my custom blot:
const Inline = Quill.import('blots/inline')
class CustomLink extends Inline {
static create(options) {
const node = super.create()
node.setAttribute('href', options.url)
if (options.target) { node.setAttribute('target', '_blank') }
if (options.follow === 'nofollow') { node.setAttribute('rel', 'nofollow') }
return node
}
static formats(node) {
return node.getAttribute('href')
}
}
CustomLink.blotName = 'custom_link'
CustomLink.tagName = 'A'
Quill.register({'formats/custom_link': CustomLink})
Do I have to tell Quill to allow certain atttributes?
Upon initialization from existing HTML, Quill will try to construct the data model from it, which is the symmetry between create(), value() for leaf blots, and formats() for inline blots. Given how create() is implemented, you would need formats() to be something like this:
static formats(node) {
let ret = {
url: node.getAttribute('href'),
};
if (node.getAttribute('target') == '_blank') {
ret.target = true;
}
if (node.getAttribute('rel') == 'nofollow') {
ret.follow = 'nofollow';
}
return ret;
}
Working fork with this change: https://codepen.io/quill/pen/xPxGgw
I would recommend overwriting the default link as well though instead of creating another one, unless there's some reason you need both types.

How to customize YUI calendar themes in Java Wicket

Is there a way to customize YUI calendar Design, in Wicket7?
As far as i can see it comes with one css set and it really is not a burner.
The only way i could think about is to override the used css but i wonder if there are some more elegant solutions to, like themes.
The skin is hardcoded in class DatePicker, if you want to change it, there is some workaround in changing classes to get it working.
First think first, you should create your own Behavior derived from DatePicker, see the source code https://github.com/apache/wicket/blob/build/wicket-7.1.0/wicket-datetime/src/main/java/org/apache/wicket/extensions/yui/calendar/DatePicker.java
Replacing afterRender(Component) is enough, but you should copy-paste the code from the Wicket class and just replace the skin.
IMPORTNANT: DO NOT CALL super.afterRender(component); because it renders
the HTML you want to replace!
public class SkinnedDatePicker extends DatePicker
{
/**
* {#inheritDoc}
*/
#Override
public void afterRender(final Component component)
{
// NEVER CALL THIS: super.afterRender(component);
// Append the span and img icon right after the rendering of the
// component. Not as pretty as working with a panel etc, but works
// for behaviors and is more efficient
Response response = component.getResponse();
response.write("\n<span class=\"yui-skin-MYSKIN\"> <span style=\"");
if (renderOnLoad())
{
response.write("display:block;");
}
else
{
response.write("display:none;");
response.write("position:absolute;");
}
response.write("z-index: 99999;\" id=\"");
response.write(getEscapedComponentMarkupId());
response.write("Dp\"></span><img style=\"");
response.write(getIconStyle());
response.write("\" id=\"");
response.write(getIconId());
response.write("\" src=\"");
CharSequence iconUrl = getIconUrl();
response.write(Strings.escapeMarkup(iconUrl != null ? iconUrl.toString() : ""));
response.write("\" alt=\"");
CharSequence alt = getIconAltText();
response.write(Strings.escapeMarkup((alt != null) ? alt.toString() : ""));
response.write("\" title=\"");
CharSequence title = getIconTitle();
response.write(Strings.escapeMarkup((title != null) ? title.toString() : ""));
response.write("\"/>");
if (renderOnLoad())
{
response.write("<br style=\"clear:left;\"/>");
}
response.write("</span>");
}
}
The second place is, when you want to use it with DateTimeField you have to override the factory method newDatePicker(), copy-paste Wicket code is in place again, see https://github.com/apache/wicket/blob/build/wicket-7.1.0/wicket-datetime/src/main/java/org/apache/wicket/extensions/yui/calendar/DateTimeField.java
public class SkinnedDateTimeField extends DateTimeField
{
/**
* The DatePicker that gets added to the DateTimeField component. Users may override this method
* with a DatePicker of their choice.
*
* #return a new {#link DatePicker} instance
*/
#Override
protected DatePicker newDatePicker()
{
return new SkinnedDatePicker()
{
private static final long serialVersionUID = 1L;
#Override
protected void configure(final Map<String, Object> widgetProperties,
final IHeaderResponse response, final Map<String, Object> initVariables)
{
super.configure(widgetProperties, response, initVariables);
DateTimeField.this.configure(widgetProperties);
}
};
}
}
Than use your SkinnedDateTimeField component instead of DateTimeField

Localizing buttons of a FacesContext.addMessage in adf

Hi i want to localize the buttons eg: OK, Cancel in ADF,
I am using the following code
FacesContext fctx = FacesContext.getCurrentInstance();
fctx.addMessage(VALIDATIONERROR,new FacesMessage(FacesMessage.SEVERITY_ERROR, errorMessage, errorMessage));
fctx.renderResponse();
I get the pop and the error message is localized, My question is how to localize the buttons which are on the pop up, ex: OK,CANCEL
I suppose you are talking about a af:dialog component. In that case i can think about two ways of doing so:
The af:dialog component has two properties: cancelTextAndAccessKey and affermativeTextAndAccessKey. They can take an EL which can take the key of a specific record into a .properties file (which is loaded as a resource bundle into the project. An example: cancelTextAndAccessKey="#{lang['popUp.dialog.button.cancel']}" (where lang is the name of the declared bundle in my case)
You can override the default component label, by creating a ListResourceBundle (which should be also loaded as a resource bundle into faces-config.xml, Application tab).
The code should be something like:
public class CTSResourceBundle extends ListResourceBundle {
public CTSResourceBundle() {
super();
}
#Override
protected Object[][] getContents() {
return new Object[][] {
{ "af_dialog.LABEL_YES", "Po" },
{ "af_dialog.LABEL_NO", "Jo" },
{ "af_dialog.LABEL_OK", "Ok" },
{ "af_dialog.LABEL_CANCEL", "Anullo" }
};
}
}

Create UI components on page load

I am currently working on oracle adf task flows and regions and I want to create and update some UI components on page load and for this I am using method call activity as default.The problem is that I am getting null values following is my code in the bean that executes on the method call.
package view;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import oracle.adf.view.rich.component.rich.output.RichOutputText;
public class testBean {
public testBean() {
}
public String testMethod() {
// Add event code here...
FacesContext facesContext = FacesContext.getCurrentInstance();
UIViewRoot root = facesContext.getViewRoot();
RichOutputText text = ( RichOutputText )root.findComponent( "r1:ot1" );
text.setValue( "Adding text on run time" );
return "product";
}
}
The set value method returning me null may be it is because the fragment product.jsff which is the view activity is not initiated and the output text with ot1 returning null.
The better approach to achieve the setting of value is to have a property in your bean say: textValue and then bind the value attribute of your ot1 with the property of the bean.
class TestBean{
private String textValue;
public String testMethod() {
textValue = "Adding text on run time";
}
public String getTextValue(){
return textValue;
}
}
Your JSPX would be:
<af:outputText id="ot1" value=#{beanName.textValue}" />

Resources