JSF action method with variable parameter [duplicate] - variables

This question already has answers here:
Invoke direct methods or methods with arguments / variables / parameters in EL
(2 answers)
Closed 4 years ago.
How do I call method with variable parameters in JSF?
I tried something like this:
<h:commandButton value="Send" action="#{myBean.checkPIN(someOtherBean.PIN)}" />
However, this doesn't work.

If you are using EL 2.2+, it's possible.
If you are using older version ot EL, you can use do the following:
<h:commandButton value="Send" action="#{myBean.checkPIN}" />
<f:param name="parameter" value="123" />
</h:commandButton>
In the managed bean you can retrieve it like:
public void checkPIN() {
...
Map<String, String> parameterMap = (Map<String, String>) externalContext.getRequestParameterMap();
String param = parameterMap.get("parameter");
...
}

Yes it is possible if you are using > EL 2.2 which is part of Servlet 3.0.
See #BalusC's suggetions here Invoke direct methods or methods with arguments / variables / parameters in EL

It does work with EL 2.2. Which is probably the version you're using, since you're using JSF 2 (Even though it might not be the case).
You can do a very simple test. You can have an OtherMB such as this:
#ManagedBean(name = "otherMB")
public class OtherMB{
public String getValue(){
return "Other Managed Bean Value";
}
}
And a method in your MainMB like this:
#ManagedBean(name = "mainMB")
public class MainMB{
public void method(String str){
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(str));
}
}
And in your xhtml you can just invoke the function using a button:
<h:commandButton action="#{mainMB.method(otherMB.value)}" value="Click Me!" />
Just remember that the h:commandButton needs to be inside an h:form, and that you need a component to show the message. Or you can just change the implementation to print the message in the console

Related

Use a #typeparam as component in Blazor

Is it possible to use a #typeparam as Component?
More explicitly, do something like the following MyComponent.razor:
#typeparam TComponent
<TComponent />
Of course, there would also be a MyComponent.razor.cs file whose content would be:
public partial MyComponent<TComponent> : ComponentBase where TComponent : ComponentBase
so that the compiler would know that <TComponent /> is meaningful.
I cannot find any documentation about this in Microsoft docs.
When I try it seems to compile, but display the following warning:
warning RZ10012: Found markup element with unexpected name 'TComponent'. If this is intended to be a component, add a #using directive for its namespace
However it is only a warning and not an error. It does't show anything in the browser though.
I am using ASP.NET 5.
Thanks
Not quite sure what you are trying to do but you can write what I believe you are trying to achieve as a component class like this:
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
namespace BlazorTest.Pages
{
public class ComponentRenderer<TComponent> : ComponentBase where TComponent : IComponent
{
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
builder.OpenComponent<TComponent>(1);
builder.CloseComponent();
}
}
}
So in Index.razor you can do something like the following to render a component of type FetchData:
....
<ComponentRenderer TComponent="FetchData"></ComponentRenderer>
....
If I'm wide of the mark post a little more information.

getter doesn't work when converted from textfield to property in Struts 2

I had a textfield in Struts 2 defined as
<s:textfield key="fName" label="First Name" readonly="true" />
and the getters were working fine, but since it was supposed to be only a display only field, I changed it to
<div> <br /> First Name: <s:property value="fName" /></div>
and now the getter gets a NullPointerException.
Is there a way to circumvent this error? thanks
getter in Person.java:
public String getFName() {
return fName;
}
stacktrace:
test.model.Person.getFName(Person.java:43)
test.service.PersonDAO.update(PersonDAO.java:182)
test.action.UpdatePersonInfo.execute(UpdatePersonInfo.java:46)
You have to be careful choosing class variable name, in you case fName. With new version of struts 2 which uses newer version of OGNL, some of the getter/setter are not working properly. This is because newer OGNL follows Java bean specification. So your getter would be
public String getfName() {
return fName;
}

Create Custom HTML Helper in ASP.Net Core

I want to create my own custom HTML Helper like the ones used in ASP.NET MVC, but I haven't been able to find how to implement them in the correct way.
I have found how to create custom Tag Helpers but not HTML Helpers. How do I create my own custom HTML Helpers?
For me I thought my HTML helpers weren't working until I spotted that the extension method is now on IHtmlHelper not HtmlHelper.
So for .net core:
public static IHtmlContent CheckboxListFor<TModel>(this IHtmlHelper<TModel> html,
Expression<Func<TModel, List<CheckboxListItem>>> expression) ...
Instead of for .net:
public static HtmlString CheckboxListFor<TModel>(this HtmlHelper<TModel> html,
Expression<Func<TModel, List<CheckboxListItem>>> expression) ...
EDIT: I've also updated the return type for .net core to be IHtmlContent as using something like HtmlContentBuilder is a nicer way to compose HTML content and returning that returns IHtmlContent
HTML Helpers look to be supported in ASP.NET Core and are awaiting documentation:
https://learn.microsoft.com/en-au/aspnet/core/mvc/views/html-helpers
[Edit:] Since answering, the above page no longer exists. I'd say HTML Helpers, while they work, are no longer "supported" in ASP.NET Core.
Looking at the ASP.NET Core source they work fairly similarly to older versions of ASP.NET MVC:
https://github.com/aspnet/AspNetCore/blob/master/src/Mvc/Mvc.ViewFeatures/src/Rendering/HtmlHelperDisplayExtensions.cs
Example
MyHTMLHelpers.cs:
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Rendering;
using System;
namespace MyApp.Helpers
{
public static class MyHTMLHelpers
{
public static IHtmlContent HelloWorldHTMLString(this IHtmlHelper htmlHelper)
=> new HtmlString("<strong>Hello World</strong>");
public static String HelloWorldString(this IHtmlHelper htmlHelper)
=> "<strong>Hello World</strong>";
}
}
_ViewImports.cshtml (second line is the important change):
#using MyApp
#using MyApp.Helpers
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
MyView.cshtml:
<div>#Html.HelloWorldHTMLString()</div>
<div>#Html.HelloWorldString()</div>
Outputs:
Hello World
<strong>Hello World</strong>
Here is an example for .Net Core 2 using TagBuilders
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Rendering;
using System.IO;
public static IHtmlContent HelloWorld(this IHtmlHelper html, string name)
{
var span = new TagBuilder("span");
span.InnerHtml.Append("Hello, " + name + "!");
var br = new TagBuilder("br") {TagRenderMode = TagRenderMode.SelfClosing};
string result;
using (var writer = new StringWriter())
{
span.WriteTo(writer, System.Text.Encodings.Web.HtmlEncoder.Default);
br.WriteTo(writer, System.Text.Encodings.Web.HtmlEncoder.Default);
result = writer.ToString();
}
return new HtmlString(result);
}
I was never able to get HtmlHelper extension methods to work, I always recieved:
'IHtmlHelper' does not contain a definition for 'MethodName' and no extension method 'MethodName' accepting a first argument of type 'IHtmlHelper' could be found (are you missing a using directive or an assembly reference?)
Even though I had the proper namespace in my _ViewImports.cshtml file. So I decided to use the ability of Razor pages to now support injecting services that have been registered for dependency injection. As an example I have the need to inject some values from my configuration file into my _Layout.cshtml file. So I did the following:
1) Defined a IConfigurationHelperService interface:
public interface IConfigurationHelperService
{
string GetApiUrl();
}
2) Defined an implementation of that interface in a ConfigurationHelperSerivce class (which itself is using dependency injection to get the regular configuration class):
public class ConfigurationHelperService : IConfigurationHelperService
{
public ConfigurationHelperService(IConfiguration configuration)
{
Configuration = configuration;
}
private IConfiguration Configuration { get; }
public string GetApiUrl()
{
return GetConfigurationValue(ApiUrl);
}
private string GetConfigurationValue(string key)
{
var value = Configuration[key];
if (value.IsNullOrEmpty()) throw new KeyNotFoundException($"Configruation does not contain an instance of {key}");
return value;
}
}
3) Registered the service for injection via ConfigureServices in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IConfigurationHelperService, ConfigurationHelperService>();
services.AddMvc();
}
4) Added the proper namespace as a using statement into my _ViewImports.cshtml file.
5) Used the #inject keyword to define it for use in the _Layout.cshtml file.
#inject IConfigurationHelperService ConfigHelper
<!DOCTYPE html>
<html>
...
#ConfigHelper.GetApiUrl()
...
</html>
It worked great for me, and I can see a lot more uses for this on simpler pages where defining models would be too much work.
Well i guess this answer won't be noticed but here's what i came up with using service registrations:
I hope it helps someone.
Register the service:
services.AddTransient<IHtmlHelperFactory, HtmlHelperFactory>();
Use the service:
var helper = HttpContext.RequestServices.GetRequiredService<IHtmlHelperFactory>().Create();
Interface:
public interface IHtmlHelperFactory
{
IHtmlHelper Create();
}
Implementation:
public class HtmlHelperFactory : IHtmlHelperFactory
{
private readonly IHttpContextAccessor _contextAccessor;
public class FakeView : IView
{
/// <inheritdoc />
public Task RenderAsync(ViewContext context)
{
return Task.CompletedTask;
}
/// <inheritdoc />
public string Path { get; } = "View";
}
public HtmlHelperFactory(IHttpContextAccessor contextAccessor)
{
_contextAccessor = contextAccessor;
}
/// <inheritdoc />
public IHtmlHelper Create()
{
var modelMetadataProvider = _contextAccessor.HttpContext.RequestServices.GetRequiredService<IModelMetadataProvider>();
var tempDataProvider = _contextAccessor.HttpContext.RequestServices.GetRequiredService<ITempDataProvider>();
var htmlHelper = _contextAccessor.HttpContext.RequestServices.GetRequiredService<IHtmlHelper>();
var viewContext = new ViewContext(
new ActionContext(_contextAccessor.HttpContext, _contextAccessor.HttpContext.GetRouteData(), new ControllerActionDescriptor()),
new FakeView(),
new ViewDataDictionary(modelMetadataProvider, new ModelStateDictionary()),
new TempDataDictionary(_contextAccessor.HttpContext, tempDataProvider),
TextWriter.Null,
new HtmlHelperOptions()
);
((IViewContextAware)htmlHelper).Contextualize(viewContext);
return htmlHelper;
}
}
This has been well explained by Danny van der Kraan in his blog post here. The answer below is an extract from this post:
ASP.NET Core 1.0 [MVC 6] comes with a new exciting feature called TagHelpers. In ASP.Net Core 1.0 there is no concept of HTML Helper like in MVC.
What are TagHelpers?
TagHelpers can be seen as the evolution of HTML helpers which were introduced with the launch of the first MVC framework. To provide context you have to imagine that with classic ASP the only way you could automate the generation of HTML is via custom subroutines. After that ASP.NET came with server controls, with view states as biggest plus, to simulate the look and feel of desktop applications and help with the transition for desktop developers. But we all know what happens when we try to jam squares in to round holes. We had to face the fact that web development is nothing like desktop development. To get in line with proper web development the ASP.NET MVC framework was launched with HTML helpers to automate the HTML output. But HTML helpers never really gelled, especially not with front end developers and designers. One of the main pet peeves was that it made you switch a lot from angle brackets (HTML, CSS) to C# (Razor syntax) during work on views, which made the experience unnecessarily uncomfortable. [MVC 6] wants to address this and some smaller issues by introducing TagHelpers. Example
HTML helper:
#Html.ActionLink(”Home”, ”Index”, ”Home”)
With the anchor TagHelper this would look like:
<a asp-action="Index" asp-controller="Home">Home</a>
PS: Please note that asp- is just a convention, but more on that later.
The output rendered in the browser is the same for both:
Home
PS: Provided the default route has not been altered.
For more information about TagHelpers click here
To create a custom HTML helper you have create a static class and static method.
below example is for a custom HTML helper for submit button.
namespace TagHelpers.Helpers
{
public static class CustomHtmlHelpers
{
public static IHtmlContent SubmitButton(this IHtmlHelper htmlHelper, string value, string name )
{
string str = "<input type='submit' value ='"+ value +"'name='"+ name +"' />";
return new HtmlString(str);
}
}
}
Make sure you add below using statements.
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Rendering;
To access the helper everywhere on the page you need to add the namespace in to the viewimports.cshtml file
#using TagHelpers.Helpers
Now, You can now use it on the page where you want to define a button.
<div>
#Html.SubmitButton("Login", "Command")
#Html.SubmitButton("Cancel", "Command")
</div>
Here is an example to get Enum name based on the Enum value in view. Custom HTML Helper for Enum Type
public static IHtmlContent DisplayEnumFor(this IHtmlHelper htmlHelper, string value, Type enumType)
{
if (htmlHelper == null)
throw new ArgumentNullException(nameof(htmlHelper));
if (value == null)
throw new ArgumentNullException(nameof(value));
if (!enumType.IsEnum)
throw new ArgumentException("Type must be an enumerated type");
foreach (var item in Enum.GetValues(enumType))
if (((int)item).ToString().Equals(value.Trim()))
return new HtmlString(item.ToString());
return new HtmlString(value);
}
Kept it simple but renders as expected. Make sure you have the right attributes set for the right elements. Please add suggestions if needs improvement or give your votes if it looks good.
public static class IconExtensions
{
public static IHtmlContent CCIcon(string iconName, string? toolTip = null)
{
return new HtmlString($"<img src=\"/img/{iconName}.png\" alt=\"{iconName}\" class=\"img-ca-annexicons\" title=\"{toolTip??iconName}\" />");
}
}

struts2: select tag doesn't like beans with "parameters" property?

I have a base class ReportElement which has type property:
public abstract class ReportElement {
private ReportElementType type;
public ReportElementType getType() {
return type;
}
public void setType(ReportElementType type) {
this.type = type;
}
}
ReportElementType is just an enum with specified code and i18nKey properties for each element. I have a couple of subclasses of ReportElement, each of them introducing their own properties. One of them is Plot:
public class Plot extends ReportElement {
public Plot() {
setType(ReportElementType.PLOT);
}
private Collection<Parameter> parameters = new ArrayList<Parameter>();
public Collection<Parameter> getParameters() {
return parameters;
}
}
On some page I needed to display a collection of different ReportElement instances, so I just used struts2 select tag:
<s:select list="myElements" listKey="type.code" listValue="type.i18nKey" size="20"/>
This worked like a charm for every element except for Plot instaces. Instead of invoking getType().getCode() or getType().getI18nKey() plain toString() was invoked on every instance of Plot! After several hours of fun debugging I noticed that during tag evaluation Plot's getParameters() method is called! So it seems struts was trying to evaluate type.code and type.i18nKey using getParameters() method! Failing to do that it ignored the existence of the properties, that I have clearly specified for usage!
After renaming getParameters to a kind of odd name like getParamms the problem gone. Also the problem hasn't occured when using iterator tag together with property tag instead of select tag.
Does anyone have an idea WHY struts select tag uses parameters property of my bean, when I have clearly specified what property should be used? Is it some "cool" feature or a bug?
P.S. I use struts 2.2.3.1
The argument used in all the FreeMarker templates representing a tag's parameters is called parameters. By providing a parameters property that takes precedence, S2 was unable to get to the object on the stack containing the tag's parameters.
It's neither a cool feature nor a bug, it's just how the templates are implemented. Checking the template source may have saved the few hours of debugging.
Found corresponding issue in struts JIRA: https://issues.apache.org/jira/browse/WW-3268
2.3 is specified as fix version.

MVC-3 and Dynamic - #Html.Label(View.X) not Rendering

Using MVC-3, Razor:
-- MyController --
public ActionResult Index(String message) // where message = "hello"
{
ViewModel.Test1 = "This is a test";
ViewModel.Test2 = "This is another test. " + message;
}
-- Index.cshtml --
#Html.Label((string)View.Test1)
<br />
#Html.Label((string)View.Test2)
Why will it only render out the following?
<label for="This is a test">This is a test</label>
<br />
It's been driving me absolutely crazy over the past few days and seems to make no sense. There has to be a reason for it.
I can debug this and step through thew view. In the view, I watch as this line is processed and the value of View.Test2 is "This is another test. hello".
I have cases where I am doing the following and it works fine.
(ex)
ViewModel.Something = this.readDataService.GetSomething();
What's the difference?
Thanks,
Rob
Looks like you are using a pre-RC2 version of ASP.NET MVC 3. ViewModel was changed to ViewBag in RC 2 (see the this post by Scott Guthrie).
With earlier previews of ASP.NET MVC 3 we exposed this API using a dynamic property called “ViewModel” on the Controller base class, and with a dynamic property called “View” within view templates. A lot of people found the fact that there were two different names confusing, and several also said that using the name ViewModel was confusing in this context – since often you create strongly-typed ViewModel classes in ASP.NET MVC, and they do not use this API.
With RC2 we are exposing a dynamic property that has the same name – ViewBag – within both Controllers and Views.
And it does look like you are trying to use ViewModel as the strongly typed model for your view. Instead, create a class to use as your model and then use #Html.LabelFor:
public class PersonModel
{
public string Name { get; set; }
}
in the controller:
PersonModel model = new PersonModel { Name = "John" };
return View(model);
in the view:
#Html.LabelFor(model => model.Name): #Html.TextBoxFor(model => model.Name)
which renders:
<label for="Name">Name</label>: <input id="Name" name="Name" type="text" value="John" />
HTH