I would like to initialize my textfield at runtime. For example, I have primefaces inputtext like this:
<p:inputText value="#{myBean.value}" id="inputText" />
And a bean class:
#PostConstruct
public void onPageLoad() {
....
....
inputText.setMaxlength(15);
inputText.setStyle(".....");
}
Is it possible to do this with jsf 2.0?
You could do so by binding the component to the bean:
<p:inputText binding="#{bean.input}" ... />
with
private InputText input; // +getter+setter
#PostConstruct
public void init() {
input = new InputText();
input.setMaxlength(15);
input.setStyle("background: pink;");
}
// ...
This is however not the recommended approach. You should rather bind the individual attributes to a bean property instead.
<p:inputText ... maxlength="#{bean.maxlength}" style="#{bean.style}" />
with
private Integer maxlength;
private String style;
#PostConstruct
public void init() {
maxlength = 15;
style = "background: pink;";
}
// ...
Even more, if your app is well designed, then you should already have such a bean object for this (why/how else would you like to be able to specify it during runtime?). Make it a property of the managed bean instead so that you can do something like:
<p:inputText ... maxlength="#{bean.attributes.maxlength}" style="#{bean.attributes.style}" />
For this you can fetch component object from jsf framework using below code
UIComponent componentObj = FacesContext.getCurrentInstance().getViewRoot().findComponent(id)
then you can type cast component object in your tag component type like if you are using inputText
HtmlInputText inputTextObj = (HtmlInputText) componentObj;
and HtmlInputText class have all the getter setter for all available attribute in tag
so you can set values like
inputTextObj.setMaxlength(15);
inputTextObj.setStyle(....);
inputTextObj.setDisabled();
inputTextObj.setReadonly();
Related
I try to set the values of a selectManyCheckbox to my testBean backing bean.
If I use a property of type List<String> instead of Attributed<List<String>> it works perfectly. It is the workaround I'm using currently.
But on my backing bean I have a generic object which contains the List.
The javax.el.BeanELResolver resolve this to an Object. Which is correct due to Type erasure.
I tried to implement a custom ElResolver. But I should know to which type to convert the object to. It isn't obviously always a List. I have the information in the xhtml pages. So I hoped I could pass some child element which would contain the information, but could not find a way to access the child element from the ElResolver.
A Custom converted does not work either as it converts selectItems, not the List.
Here is the simplest form
<h:form>
<p:selectManyCheckbox value="#{testBean.attributed.value}" >
<f:selectItems value="#{testBean.selection}" />
</p:selectManyCheckbox>
<p:commandButton action="#{testBean.execute}" value="do it" />
</h:form>
and the bean
private Attributed<List<String>> attributed = new Attributed<>();
public Map<String, String> getSelection() {
return ImmutableMap.<String, String> of("key1", "value1", "key2", "value2");
}
public static class Attributed<T> {
private T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
public Attributed<List<String>> getAttributed() {
return attributed;
}
public void setAttributed(Attributed<List<String>> attributed) {
this.attributed = attributed;
}
So the question is:
Is there a way to set the value to testBean.attributed.value directly and with the correct type.
Is it possible by defining a custom ElResolver, or are there other way to do it?
I am trying to do some "custom lightweight" JSF component binding. In my bean (controlling some JSF page) i'm declaring a HahsMap where keys ranging over my h:inputText ids (appearing in the page) map these ids to custom HInputText<T> objects (T in the example given below is Long). Then i am using HInputText<T> objects to hold a subset of corresponding h:inputText attributes : value supposed to be of type T, rendered, required, etc. In this direction fields from the HInputText<T> objects give values to the h:inputText attributes.
My problem is that when using such an h:inputText inside a h:form, JSF validation does not take place : i can type alphanumeric chars in the h:inputText (supposed to hold a Long value) and my form submits without showing any errors. Note that required and rendered attributes are managed correctly (since required is set to true, i have an error when i leave the h:inputText field empty) and that when i try to display back the value of the h:inputText in the page using some h:outputText the alphanumeric chars are displayed.
Is there some trick to make JSF validation work without having to explicitly define a custom Validator for each h:inputText?
HInputText.class:
public class HInputText<T>
{
private String id;
private boolean rendered;
private boolean required;
private T value;
private Class<T> myClass;
// getters and setters for all fields
public HInputText(Class<T> myClass, String id)
{
this.myClass = myClass;
this.id = id;
this.rendered = true;
this.required = true;
}
}
Code snippet from my Managed Bean :
#ManagedBean(name="saisieController")
#SessionScoped
public class SaisieController
{
...
private HashMap<String,HInputText<Long>> htagLongInputTexts;
public HashMap<String, HInputText<Long>> getHtagLongInputTexts()
{
return htagLongInputTexts;
}
public void setHtagLongInputTexts(HashMap<String, HInputText<Long>> hLongInputTexts)
{
this.htagLongInputTexts = hLongInputTexts;
}
public void addHtagLongInputText(HInputText<Long> hLongInputText)
{
getHtagLongInputTexts().put(hLongInputText.getId(), hLongInputText);
}
public HInputText<Long> getHtagLongInputText(String hLongInputTextId)
{
return(getHtagLongInputTexts().get(hLongInputTextId));
}
#PostConstruct
public void init()
{
setHtagLongInputTexts(new HashMap<String, HInputText<Long>>());
addHtagLongInputText(new HInputText<Long>(Long.class, "HIT_LongTestHIT"));
}
public String doNothing()
{
return null;
}
}
and finally a snippet from my jsf page:
<h:form>
<h:inputText
id = "HIT_LongTestHIT"
value = "#{saisieController.htagLongInputTexts['HIT_LongTestHIT'].value}"
rendered = "#{saisieController.htagLongInputTexts['HIT_LongTestHIT'].rendered}"
required = "#{saisieController.htagLongInputTexts['HIT_LongTestHIT'].required}"
/>
<h:message for = "HIT_LongTestHIT" styleClass = "error-text" />
<h:commandButton value = "submit" action = "#{saisieController.doNothing()}" />
<h:outputText value = "#{saisieController.htagLongInputTexts['HIT_LongTestHIT'].value}" />
</h:form>
Is there some trick to make JSF validation work without having to explicitly define a custom Validator for each h:inputText?
No, that's not possible. Due to type erasure the generic type information is not available during runtime. JSF/EL has no idea that T is actually a Long, let alone that there's actually some T. You really need to explicitly specify a converter which is in this particular example the LongConverter with a converter ID of javax.faces.Long.
<h:inputText ... converter="javax.faces.Long">
or, dynamically so you want
<h:inputText ...>
<f:converter converterId="#{saisieController.htagLongInputTexts['HIT_LongTestHIT'].converterId}" />
</h:inputText>
You can find an overview of all available standard JSF converters in the javax.faces.convert package summary. You can find out their converter IDs by navigating to the Constant field values link on the public constant CONVERTER_ID.
I need to render an html table having precise control over rows, columns, headers, styles etc.
I'm using a primeFaces panelGrid this way:
<p:panelGrid binding="#{myBean.tableComponent}"/>
In my backing bean, I have:
private UIComponent tableComponent;
public UIComponent getTableComponent() {
if (tableComponent == null) {
tableComponent = new PanelGrid();
populateTableComponent(); // Populate datatable.
}
return tableComponent;
}
public void setTableComponent(UIComponent tableComponent) {
this.tableComponent = tableComponent;
}
private void populateTableComponent() {
PanelGrid tbl = (PanelGrid) tableComponent;
//...
for (MyPojo row : data.getRows) {
// ...here I create the row/column UIComponent subtree
}
}
Now, my problem is:
For a specific column, I have to render a commandLink in each row.
This Link should AJAX-call a bean's method which should do something related to the clicked row.
Something like <p:commandLink action="#{myBean.myFieldClick(***row***)}"> but
how can I refer to row?
Other ideas?
Thank you in advance
Just use exactly the same variable name as definied in var attribute of the data table. In other words, write down exactly the same EL expression string as you would do when normally writing it in a view file instead of in a backing bean.
Thus, the action attribute of the following command link example in the view
<p:dataTable ... var="row">
...
<p:commandLink ... action="#{myBean.myFieldClick(row)}">
could programmatically be represented as
MethodExpression action = createMethodExpression("#{myBean.myFieldClick(row)}", null, Row.class);
with this helper method
public static MethodExpression createMethodExpression(String expression, Class<?> returnType, Class<?>... parameterTypes) {
FacesContext facesContext = FacesContext.getCurrentInstance();
return facesContext.getApplication().getExpressionFactory().createMethodExpression(
facesContext.getELContext(), expression, returnType, parameterTypes);
}
I have problems with SelectOneMenu. I write this:
<h:selectOneMenu id="listaEstados"
styleClass="comboboxStyle"
value="#{detalleSistemaBean.sistema.indEstado}"
immediate="true">
<f:selectItems value="#{detalleSistemaBean.indEstados}" />
</h:selectOneMenu>
<h:commandButton id ="SubmitModificar"
value="Modificar"
styleClass="botonPeque"
action="#{detalleSistemaBean.modificaSistema}">
</h:commandButton>
But when I choose one value from the list "indEstados" and I submit the form, the bean "sistema.indEstado" doesn't change. I have seen that the bean property changes just before the method modificaSistema, but inside this method (where I have a database connection and a sql sentence), "sistema.indEstado" returns to its original value. Why this happens? I have tried to save the value using valueChangeListener, and that works, but I guess that is not a neat solution.
That can happen when you're doing data loading inside the getter method instead of inside the (post)constructor of the bean class.
Fix your managed bean code to not do anything else inside getter methods than just returning the property.
I.e. do not do
public Sistema getSistema() {
return sistemaService.find(someSistemaId);
}
but rather do
private Sistema sistema;
#PostConstruct
public void init() {
sistema = sistemaService.find(someSistemaId);
}
public Sistema getSistema() {
return sistema;
}
Can you try without setting
immediate="true"
JSF commandButton with immediate="true"
This is a pattern that I would use over and over again if I get it to work. I have an enum name Log.LogKey that I want to user to pick out instances of. So the facelet has this:
<h:form id="testForm" >
<h:selectManyCheckbox value="#{test.selectedKeys}" >
<f:selectItems value="#{test.allKeys}"
var="lk"
itemLabel="#{lk.display}"
itemValue="#{lk}" />
</h:selectManyCheckbox>
<h:commandButton value="Do It" action="#{test.doNothng}" />
</h:form>
The enum has a getter called getDisplay(). The selectItems attribute calls that correctly because that's the string that gets rendered to the user. And the backing bean has this:
public class Test implements Serializable {
private List<Log.LogKey> selectedKeys = null;
public List<Log.LogKey> getAllKeys() {
return Arrays.asList(Log.LogKey.values());
}
public List<Log.LogKey> getSelectedKeys() { return selectedKeys; }
public void setSelectedKeys(List selected) {
System.out.println("getSelecgedKeus() got " + selected.size());
int i = 0;
for (Object obj : selected) {
System.out.println(i++ + " is " + obj.getClass() + ":" + obj);
}
}
public String doNothng() { return null; }
}
So on the form submit, the array setSelectedKeys(selected) gets called with a List of Strings, not a List of Log.LogKey. The reference to #{lk} in the selectItems tag is converting the object to a string. What would be the right way to do this?
You need to specify a converter. JSF EL is not aware about the generic List type because that's lost during runtime. When you do not explicitly specify a converter, JSF will not convert the submitted String values and plain fill the list with them.
In your particular case, you can make use of the JSF builtin EnumConverter, you just have to super() the enum type in the constructor:
package com.example;
import javax.faces.convert.EnumConverter;
import javax.faces.convert.FacesConverter;
#FacesConverter(value="logKeyConverter")
public class LogKeyConverter extends EnumConverter {
public LogKeyConverter() {
super(Log.LogKey.class);
}
}
To use it, just declare it as follows:
<h:selectManyCheckbox value="#{test.selectedKeys}" converter="logKeyConverter">
...
</h:selectManyCheckbox>
See also:
Use enum in h:selectManyCheckbox