I'm using below custom component to display some kind of guidance in my page. I was asked to pass text and styleClass attributes to this component. But unfortunately styleClass attribute alone is NOT getting applied when this component gets rendered in the page. And thus I've hard coded with in my tag component. And this time style is getting applied properly. Not sure why. Can any one sugegst?
I can see styleClass attribute from css is getting passed to tag component properly. As I mentioned above component is getting rendered with out the passed style class applied.
If I hard code my style as below then it is working.
writer.writeAttribute("style", "background-color: #F1F5F2;font-size: 80%;left: 52em;position: absolute;text-align: left;width: 13.25em;z-index: 5;", null);
How is this caused and how can I solve it?
The custom component is used as follows
<mytags:guidanceBox text="#{FindPersonProps.MY_GUIDANCE_TEXT}" styleClass="guidance_css" />
The source code is below:
#FacesComponent(value="tags.guidanceBox")
public class GuidanceTag extends UIOutput {
#Override
public String getFamily() {
return "javax.faces.NamingContainer";
}
public GuidanceTag() {
}
#Override
public void encodeBegin(FacesContext context) throws IOException {
String guidanceText=(String) getAttributes().get("text");
//String styleClass=(String) getAttributes().get("styleClass");
//System.err.println("Text ["+guidanceText+"] Style ["+styleClass+"]");
ResponseWriter writer=context.getResponseWriter();
String clientId=getClientId(context);
writer.startElement("p", this);
writer.writeAttribute("style", "background-color: #F1F5F2;font-size: 80%;left: 52em;position: absolute;text-align: left;width: 13.25em;z-index: 5;", null);
writer.writeAttribute("name", clientId, "clientId");
writer.startElement("b", null);
writer.writeText("Guidance:", null);
writer.endElement("b");
writer.startElement("br", null);
writer.endElement("br");
writer.writeText(guidanceText, null);
writer.endElement("p");
}
You should implement TagHandler, that is passing the attributes to implementation of your component itself. Something like this:
public class GuidanceTagHandler extends ComponentHandler {
public GuidanceTagHandler(ComponentConfig config) {
super(config);
}
#Override
protected void onComponentCreated(FaceletContext ctx, UIComponent c, UIComponent parent) {
super.onComponentCreated(ctx, c, parent);
TagAttribute styleClassAttribute = getRequiredAttribute("styleClass");
c.getAttributes().put("styleClass", styleClassAttribute);
}
}
in taglib.xml you should have a signature of your component:
<tag>
<tag-name>guidanceTag</tag-name>
<component>
<component-type>guidance</component-type>
<handler-class>yourpackages.GuidanceTagHandler</handler-class>
</component>
</tag>
and finally in faces.config (it will bind on the component-type attribute
<component>
<component-type>guidance</component-type>
<component-class>yourpackages.GuidanceTag</component-class>
</component>
I hope this answer will help you a bit, since I was once having the same problem. So this is the solution I came up with.
Related
I wonder if should be possible to add an attribute to a component inside a converter? So inside the getAsString I would use uiComponent.addAttribute(). This seems to work 50% for me, the initial value is set, but when the converter is called later setting a new value the initial value is still retrieved.
you should not do it this way since it breaks separation of duties. you should use a bean or a scope attribute instead.
but maybe this suits:
<h:inputText value="#{bean.someValue}" converter="#{bean}">
<f:attribute name="attrName" value="#{bean.attrValue}"/>
</h:inputText>
and
#ManagedBean
public class Bean implements Converter
{
private String someValue;
private String attrValue;
#Override
public String getAsString(FacesContext context, UIComponent component, Object value)
{
attrValue = "uppercase";
return someValue.toUpperCase();
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value)
{
attrValue = "lowercase";
return value.toLowerCase();
}
public String getSomeValue()
{
return someValue;
}
public void setSomeValue(String someValue)
{
this.someValue = someValue;
}
public String getAttrValue()
{
return attrValue;
}
public void setAttrValue(String attrValue)
{
this.attrValue = attrValue;
}
}
I designed a form in FXML document.I can handle keypress vs. events. But I need text change event.I'm using Netbeans 7.3 . There's three files in the projects: SampleControler, Sample.FXML and Sample.java. I found a code but I have not solved where to use it.
input.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue ov, String t, String t1) {
System.out.println("Changed.");
}
});
My TextArea code is:
<TextArea layoutX="10" layoutY="50" maxHeight="125" minHeight="125" maxWidth="570" minWidth="570" editable="true" fx:id="input" prefWidth="570" prefHeight="125" />
What should I do?
In your controller associeted to your fxml, get your TextArea, and you will can do :
yourTextArea.textproperty().addListener ...
public class Example implements Initializable {
#FXML
private TextArea textArea;
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
textArea.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observableValue, String s, String s2) {
}
});
}
}
The varibale name on the controller need to have the same name like the fx:id in the fxml
I have situation here. I use managed bean as converter to pre populate SelectManyCheckBox from database and it works good. Here is my Converter class
#ManagedBean
#RequestScoped
public class RoleConverter implements Converter{
#EJB
private UserRoleSingleton userRoleSingleton;
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if(value == null){
return null;
}
return userRoleSingleton.getUserRoleById(Integer.parseInt(value));
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if(!(value instanceof Userrole) || ((Userrole) value).getRoleId() == null){
return null;
}
Userrole role = (Userrole) value;
return String.valueOf(role.getRoleId());
}
public RoleConverter() {
}
}
After it preselect checkboxes I select or deselect check boxes or do nothing and click submit button in form.
Then button's first click just executes convertor's getAsString method again and reload page.
And on second click it executes getAsObject method as expected then action.
Here is my SelectManyCheckBox:
<p:selectManyCheckbox id="orgpermission"
value="#{adminView.selectedrolesorg}" layout="pageDirection">
<f:selectItems value="#{adminView.allRolesRelatedToOrgInfo}"
var="citrole" itemValue="#{citrole}"
itemLabel="#{citrole.roledescription}" converter="#{roleConverter}" />
</p:selectManyCheckbox>
Why does it executes getAsString method again and how to solve it to fire action method on first click?
I would like to know how to render a composite component, through Java,
I mean I have:
<myowntags:selectOneRadio>
<f:selectItem itemValue="value0" itemLabel="This is the value 0" />
<f:selectItem itemValue="value1" itemLabel="This is the value 1" />
<f:selectItem itemValue="value2" itemLabel="This is the value 2" />
</myowntags:selectOneRadio>
or
<myowntags:selectOneRadio>
<f:selectItems value="#{controller.items}" />
</myowntags:selectOneRadio>
and I would like to create a Java class to render it.
I know how to render a custom component without using composite, but since, to render a component I have to specify some values on the block:
<renderer>
<component-family>javax.faces.SelectBoolean</component-family>
<renderer-type>javax.faces.Checkbox</renderer-type>
<renderer-class>com.myapp.CustomCheckboxRenderer</renderer-class>
</renderer>
then I get lost, because I don't know the values of those parameters
inside the render tag for a composite component.
Thanks in advance,
Angel.
First, you need to have a backing component which implements NamingContainer and returns "javax.faces.NamingContainer" as component family. This is required by composite components, you can't change that part. The UINamingContainer implementation already does that, so if you can just extend from it.
#FacesComponent("mySelectOneRadio")
public class MySelectOneRadio extends UINamingContainer {
// ...
}
Or if you rather want to extend from UISelectOne, then you'd have to implement the NamingContainer interface and make sure that you return UINamingContainer.COMPONENT_FAMILY in the getFamily() override.
Then, you need to specify it in <cc:interface componentType>.
<cc:interface componentType="mySelectOneRadio">
Note that at this step you can already perform the rendering (encoding) through Java. Just override the encodeChildren() method.
#FacesComponent("mySelectOneRadio")
public class MySelectOneRadio extends UINamingContainer {
#Override
public void encodeChildren(FacesContext context) throws IOException {
ResponseWriter writer = context.getResponseWriter();
writer.startElement("div", this);
writer.writeText("hello world", null);
writer.endElement("div");
}
}
Coming back to your concrete question, you'd thus like to have a standalone Renderer class for this. That's fine. For that you need to extend Renderer:
#FacesRenderer(componentFamily=UINamingContainer.COMPONENT_FAMILY, rendererType=MySelectOneRadioRenderer.RENDERER_TYPE)
public class MySelectOneRadioRenderer extends Renderer {
public static final String RENDERER_TYPE = "com.example.MySelectOneRadio";
#Override
public void encodeChildren(FacesContext context, UIComponent component) throws IOException {
ResponseWriter writer = context.getResponseWriter();
writer.startElement("div", component);
writer.writeText("hello world", null);
writer.endElement("div");
}
}
The backing component should be changed as follows in order to properly register this renderer as the default renderer (don't override getRendererType() method! otherwise you or anyone else would be unable to change this by <renderer> in faces-config.xml):
#FacesComponent("myComposite")
public class MyComposite extends UINamingContainer {
public MyComposite() {
// Set default renderer.
setRendererType(MySelectOneRadioRenderer.RENDERER_TYPE);
}
}
Note that thanks to the #FacesRenderer, you don't need to hassle with faces-config.xml.
Whatever way you choose to encode the children, you can get component's children just by UIComponent#getChildren(). When you're inside MySelectOneRadio component:
if (getChildCount() > 0) {
for (UICompnent child : getChildren()) {
// ...
}
}
Or when you're inside MySelectOneRadioRenderer renderer:
if (component.getChildCount() > 0) {
for (UICompnent child : component.getChildren()) {
// ...
}
}
To delegate to the component's own default rendering, invoke super.encodeChildren() or component.encodeChildren(). To delegate to child's own default rendering, invoke child.encodeAll().
See also:
What is the relationship between component family, component type and renderer type?
I read on SO some QA about the same component, but I feel I'm missing something, because I am one step behind.
I can't even make the page open when using the primefaces autocomplete component in it.
The snippet for it is:
<p:autoComplete value="#{indirizzoCtrl.selectedCodiceNazione}"
completeMethod="#{indirizzoCtrl.completeNazione}"
var="nazione" itemLabel="#{nazione.nome}"
itemValue="#{nazione.codiceNazione}" />
Nazione is a Pojo class where CodiceNazione and Nome are two String field (with getter and setter for sure). completeNazione is a method on the ManagedBean that returns List<Nazione>.
Looking at BalusC explanation here, it seems to me that i don't need any converter involved, because both itemValue and value attributes are mapped to string property.
Anyway, when I just open the page containing this autocomplete snippet, it crashes with this error:
javax.el.PropertyNotFoundException: /Cliente/Indirizzo.xhtml #23,56 itemValue="#{nazione.codiceNazione}": itemValue="#{nazione.codiceNazione}": Property 'codiceNazione' not found on type java.lang.String
Why this is happening? I really can't get it. The method completeNazione hasn't even called yet, so it shouldn't know any Nazione yet.
What's wrong with it?
Edited:
Following the suggestion, I tried to add a converter, but I still get the same error.
Here's my converter:
public class NazioneConverter implements Converter {
final static Logger log = Logger.getLogger(NazioneConverter.class);
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value.trim().equals("")) {
return null;
} else {
try {
IndirizzoRepository ir = new IndirizzoRepository();
List<Nazione> nazioni = ir.getNazioneByName(value);
if (nazioni.size()==1) return nazioni.get(0);
else throw new Exception();
} catch (Exception e) {
String msg = "Errore di conversione";
log.error(msg, e);
throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, "Non è una nazione conosciuta"));
}
}
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null || value.equals("")) {
return "";
} else {
return String.valueOf(((Nazione) value).getNome());
}
}
}
now the component in the view looks like:
<p:autoComplete value="#{indirizzoCtrl.indirizzo.nazione.codiceNazione}"
completeMethod="#{indirizzoCtrl.completeNazione}"
var="nazione" itemLabel="#{nazione.nome}" converter="#{nazioneConverter}"
itemValue="#{nazione.codiceNazione}" forceSelection="true" />
But still don't working. The converter is not even invoked: I registered it in my faces-config.xml file.
I also tried itemValue="#{nazione}" as in the primefaces showcase but the problem became the ItemLabel attribute, mapped to nazione.nome.
What am I doing wrong?
This worked for me:
//Converter
#FacesConverter(value="MarcaConverter")
public class MarcaConverter implements Converter{
MarcaDAO marcaDAO;
public Object getAsObject(FacesContext contet, UIComponent component, String value) {
if(value==null || value.equals(""))
return null;
try{
int id = Integer.parseInt(value);
return marcaDAO.findMarcaById(id);
}catch (Exception e) {
e.printStackTrace();
throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Marca no válida", ""));
}
}
public String getAsString(FacesContext contet, UIComponent component, Object value) {
if(value==null || value.equals(""))
return null;
return String.valueOf(((Marca)value).getCodigoMarca());
}
}
//--------------------------------------
//Bean
#ManagedBean
#ViewScoped
public class MyBeans implements Serializable{
private Marca marca;
...
public Marca getMarca(){
return marca;
}
public void setMarca(Marca m){
marca=m;
}
...
public List<Marca> obtenerMarcasVehiculos(String s) {
List<Marca> marcas,smarcas=new ArrayList<Marca>();
try{
marcas= marcaDAO.findAllMarcas();
if(s.trim().equals("")) return marcas;
for(Marca m:marcas)
if (m.getNombreMarca().toString().contains(s) || m.getNombreMarca().toLowerCase().contains(s.toLowerCase())) {
smarcas.add(m);
}
return smarcas;
}catch(Exception e){
//JsfUtil.showFacesMsg(e,"Error al obtener las marcas de vehículos","",FacesMessage.SEVERITY_WARN);
e.printStackTrace();
JsfUtil.lanzarException(e);
return null;
}
}
//-----------------------------------------
//*.xhtml page
...
<p:autoComplete
id="cbxMarca" value="#{myBean.marca}" size="40"
converter="MarcaConverter"
completeMethod="#{myBean.obtenerMarcasVehiculos}"
var="m" itemLabel="#{m.nombreMarca}" itemValue="#{m}"
forceSelection="true" dropdown="true"
required="true" scrollHeight="200">
</p:autoComplete>
...
//-----------------------------------------
//Class Marca
public class Marca implements Serializable{
private static final long serialVersionUID = 1L;
private Integer codigoMarca;
private String nombreMarca;
...
Have you read the user guide? http://www.primefaces.org/documentation.html
I must say I have never used the autocomplete with pojo but from what I've read in the user guide, Çağatay Çivici says there:
Note that when working with pojos, you need to plug-in your own converter.
Here you can find out that a converter (PlayerConverter) is implemented even if player.name and of the other props are Strings.
I admit this is interesting and I'll do some research but I don't have the necessary time right now...
Change
converter="#{nazioneConverter}" to converter="nazioneConverter" in autocomplete
Change the itemValue from itemValue="#{nazione.codiceNazione}" to itemValue="#{nazione}" in autoComplete.