I have a JSF 2.2 composite component which is used more than once on the same page.
#FacesComponent("myComponent")
public class MyComponent extends UIComponent {
public void test() {
System.out.printlin(getAttributes("value"));
}
}
component xhtml:
<composite:interface componentType="myComponent">
<composite:attribute name="value" required="true" type="java.lang.String" />
</composite:interface>
<composite:implementation>
<a4j:jsFunction name="test" action="#{cc.test()}" execute="input" />
<s:span id="input">
<h:inputText value="#{cc.attrs.value}" onclick="test()" />
</s:span>
</composite:implementation>
page xhtml
<my:myComponent value="#{bean.value}" /> -- line 1
<my:myComponent value="#{bean2.value}" /> -- line 2
When I click on the first myComponent, it calls test() but prints the value of bean2.value instead of bean.value. If I remove line 2 then it prints bean.value. I thought that the call to getAttributes() would get the value for current composite component, but it seems that it is only getting the value for the last composite component on the page. Could someone explain to me how the attributes are supposed to work or what I am missing?
Here is the solution, with id attribute appended to the jsFunction to distinguish it from other same components on the page:
<composite:interface componentType="myComponent">
<composite:attribute name="id" type="java.lang.String" />
<composite:attribute name="value" required="true" type="java.lang.String" />
</composite:interface>
<composite:implementation>
<a4j:jsFunction name="#{cc.attrs.id}test" action="#{cc.test()}" execute="input" />
<s:span id="input">
<h:inputText value="#{cc.attrs.value}" onclick="#{cc.attrs.id}test()" />
</s:span>
</composite:implementation>
Related
I'm having one or two problems with Primefaces (v5.2):
Referencing components inside composite components
Let's say I have a composite component that wraps an inputfield:
myinputfield.xhtml
<composite:interface>
<composite:attribute name="value" />
...
</composite:interface>
<composite:implementation>
<h:inputText value="#{cc.attrs.value}" />
</composite:implementation>
(Of course the real application does "a little" more.)
In my page I now use this field like this:
index.xhtml
<my:myinputputfield value=#{controller.inputstring} />
This works. But:
Know I want to reference that inner inputfield from outside, for example for labels or messages. Something like:
<p:inputLabel for="mif" value="Your Input:"/>
<my:myinputputfield id="mif" value=#{controller.inputstring} />
<p:message for="mif" />
Of course that doesn't work, because id isn't defined for myinputfield.
So the first idea that pops to mind is to extent the cc like this:
myinputfield.xhtml (new)
<composite:interface>
<composite:attribute name="id" />
<composite:attribute name="value" />
...
</composite:interface>
<composite:implementation>
<h:inputText id="{cc.attrs.id}" value="#{cc.attrs.value}" />
</composite:implementation>
Which does not work as well. I tried different things and read different answers and articles without finding an answer to this.
The second problem is the complete opposite:
Referencing components outside composite components
This time imagine it the other way around. I have a customized label, message or in my case a tooltip:
mytooltip.xhtml
<composite:interface>
<composite:attribute name="for" />
<composite:attribute name="value" />
...
</composite:interface>
<composite:implementation>
<p:toolTip for="#{cc.attrs.for}" value="#{cc.attrs.value}" />
</composite:implementation>
This time I want to attach mytooltip to an existing component:
index.xhtml
<h:outputtext id="ot" value="Hello World!" />
<my:mytooltip for="ot" value="since 1974" />
Which also does not work. (Of course!?)
This problem I had some time ago and solved it by inclduing the outputText in the composite component.
But I have the feeling it should be possible to manage both user cases. But how?
Referencing components inside composite components
give the internal input a static id
<composite:interface>
<composite:attribute name="value" />
...
</composite:interface>
<composite:implementation>
<h:inputText id="input" value="#{cc.attrs.value}" />
</composite:implementation>
reference the internal component as with any naming container:
<p:inputLabel for="mif:input" value="Your Input:"/>
<my:myinputputfield id="mif" value=#{controller.inputstring} />
<p:message for="mif:input" />
Referencing components outside composite components
the canonical way is to use the full client id:
<h:form id="form">
<h:outputText id="ot" value="Hello World!" />
<my:mytooltip for=":form:ot" value="since 1974" />
</h:form>
but, since you are passing the search expression to a PF component, you can also:
<h:form>
<h:outputText id="ot" value="Hello World!" />
<my:mytooltip for="#form:ot" value="since 1974" />
</h:form>
or generically:
<p:tabView>
<p:tab title="random tab">
<h:outputText id="ot" value="Hello World!" />
<my:mytooltip for="#namingcontainer:ot" value="since 1974" />
</p:tab>
</p:tabView>
or even:
<h:outputText value="Hello World!" />
<my:mytooltip for="#composite:#previous" value="since 1974" />
however, in such cases, a tag-component/facelet-tag-file could be a better approach.
This question already has answers here:
commandButton/commandLink/ajax action/listener method not invoked or input value not set/updated
(12 answers)
Closed 6 years ago.
I 'm trying to call a method in java through the SelectOneRadio component, but nothing happen. But the component is created by my company to accept ENUM.
THE COMPONENT:
<composite:interface>
<composite:attribute name="label" />
<composite:attribute name="value" />
<composite:attribute name="converter" />
<composite:attribute name="lista" />
<composite:attribute name="enumClass" />
<composite:attribute name="id" default="campo"/>
<composite:attribute name="columns" default="1"/>
<composite:attribute name="required" default="false"/>
<composite:attribute name="disabled" default="false"/>
<composite:attribute name="tamanhoTotal" default="12"/>
<composite:attribute name="tamanho" default="10"/>
<composite:attribute name="tamanhoLabel"/>
<composite:attribute name="layout" default="lineDirection"/>
<composite:clientBehavior name="change" event= "change" targets = "campo"/>
<composite:implementation>
<p:selectOneRadio id="#{cc.attrs.id}"
value="#{cc.attrs.value}"
disabled="#{cc.attrs.disabled}"
columns="#{cc.attrs.columns}"
layout="#{cc.attrs.layout}"
required="#{cc.attrs.required}"
label="#{cc.attrs.label}"
converter="#{cc.attrs.converter}"
requiredMessage="#{cc.attrs.label} : Campo obrigatório">
<f:selectItems value="#{referenciaMap[cc.attrs.enumClass]}"/>
</p:selectOneRadio>
And a try this until now :
This is MY XHTML :
<campo:radio enumClass="StatusTituloEnum"
label="Situação" tamanho="1" tamanhoTotal="1"
columns="1" layout="grid"
disabled="#{!recTituloCriteria.disableRadioStatus}"
converter="#{StatusTituloConverterById}">
<p:ajax event="change" process="#this"
update=":form:idTabela" listener="#{recTituloCriteria.handleKeyEvent}" />
</campo:radio>
And this is my method in JAVA :
public void handleKeyEvent() {
//text = text.toUpperCase();
System.out.println("hi");
}
Some part of your <campo:radio> in XHTML is missing. Can you please edit it?
Are there any errors in your web browser console?
Probably it helps to add onclick="this.form.submit();" in your selectOneRadio.
Another suggestion is to use valueChangeListener if you don't insist on ajax calls.
EDIT: Try to change the change event to a click event. I think this will do...
I have two composites and I need to render the field in the second composite when I change the name of the car, but shows this error:
<f:ajax> contains an unknown id 'nameCli' - cannot locate it in the context of the component nameCar.
Follow the code:
1ª composite car.xhtml
<composite:interface>
<composite:attribute name="id" required="true" type="java.lang.String" />
<composite:attribute name="nameCar" />
<composite:attribute name="clear" method-signature="java.lang.String action()" />
</composite:interface>
<composite:implementation>
<label>Car:</label>
<h:inputText id="nameCar" value="#{cc.attrs.nameCar}">
<!-- Here is the ajax that call the method 'clear' when the inputText changed -->
<f:ajax listener="#{cc.attrs.clear}" event="change" render="nameCli ageCli" />
</h:inputText>
</composite:implementation>
2ª composite client.xhtml
<composite:interface>
<composite:attribute name="id" required="true" type="java.lang.String" />
<composite:attribute name="nameCli" />
<composite:attribute name="ageCli" />
</composite:interface>
<composite:implementation>
<label>Client's Name:</label>
<h:inputText id="nameCli" value="#{cc.attrs.nameCli}" />
<label>Age:</label>
<h:inputText id="ageCli" value="#{cc.attrs.ageCli}" />
</composite:implementation>
The principal.xhtml
<proj:car id="car" nameCar="#{beanController.car.name}" clear="#{beanController.clear}" />
<proj:client id="client" nameCli="#{beanController.client.name}" ageCli="#{beanController.client.age}" />
And BeanController.java
private Car car;
private Client client;
public String clear() {
client.setName(null);
client.setAge(null);
return null;
}
//getters and setters
If I change the
<f:ajax listener="#{cc.attrs.clear}" event="change" render="nameCli ageCli" />
to
<f:ajax listener="#{cc.attrs.clear}" event="change" render=":client:nameCli :client:ageCli" />
doesn't work too.
I can't call to render #all or #form because there are others fields that I want to render.
Edited: Resolution
#BalusC I appreciated your comment, but your answer in other question didn't work to me. It was necessary to implement my code dynamically. Look at bellow.
In my car.xhtml composite I take off the render of ajax
<f:ajax listener="#{cc.attrs.clear}" event="change" />
And in my BeanController.java I implemented the clear method like this.
public String clear() {
client.setName(null);
client.setAge(null);
// Get the fields
UIInput uiNameCli = (UIInput) FacesContext.getCurrentInstance().getViewRoot().findComponent("myForm:client:nameCli");
UIInput uiAgeCli = (UIInput) FacesContext.getCurrentInstance().getViewRoot().findComponent("myForm:client:ageCli");
FacesContext context = FacesContext.getCurrentInstance(); // Update the fields.
context.getPartialViewContext().getRenderIds().add(uiNameCli.getClientId(context));
context.getPartialViewContext().getRenderIds().add(uiAgeCli.getClientId(context));
return null;
}
I'm facing a problem using OmniFaces 2.1 o:validateBean with method="validateCopy" when my inputs are composite components. With method="validateActual", it validates as expected.
JSF implementation: Mojarra 2.2.8-jbossorg-1.
My composite component source:
<composite:interface>
<composite:attribute name="target" />
<composite:attribute name="label"/>
<composite:attribute name="value" />
<composite:attribute name="required" />
<composite:attribute name="size" />
<composite:attribute name="disabled" />
<composite:attribute name="styleInput" required="false" />
<composite:editableValueHolder name="input" targets="input" />
<composite:clientBehavior name="change" event="change" targets="input" />
<composite:clientBehavior name="keypress" event="keypress" targets="input" />
</composite:interface>
<composite:implementation>
<p:outputLabel id="label" for="input" value="#{cc.attrs.label}" />
<h:panelGrid columns="3">
<p:inputText id="input" value="#{cc.attrs.value}"
style="#{cc.attrs.styleInput}" size="#{cc.attrs.size}"
disabled="#{cc.attrs.disabled}" required="#{cc.attrs.required}">
</p:inputText>
<p:message for="input" display="icon">
<p:effect type="pulsate" event="load" delay="500" />
</p:message>
</h:panelGrid>
</composite:implementation>
I tracked down to the omnifaces source and got to the source point below, in the o:validateBean:
ValueReference valueReference = getValueReference(context.getELContext(), valueExpression);
if (valueReference.getBase().equals(base)) {
operation.run((EditableValueHolder) component, valueReference);
}
In a case where I use a simple input text, the valueReference().getBase() returns my to be validated bean. In a case where I use a composite component, the valueReference().getBase() returns a reference to CompositeComponentAttributesELResolver.ExpressionEvalMap.
Is threre a way to change my composite component so that it works with o:validateBean?
I have the following JSF composite component:
<composite:interface componentType="myComp">
<composite:attribute name="input" type="java.lang.Integer" />
<composite:attribute name="output" type="java.lang.Integer" />
<composite:attribute name="action" method-signature="java.lang.String action()"/>
</composite:interface>
<composite:implementation>
<h:inputText id="input" value="#{cc.attrs.input}" />
</composite:implementation>
Assuming the composite is invoked as
<h:form id="form">
<cc:myComposite id="cc" input="#{bean.input}"
output="#{bean.output}" action="#{bean.action}" />
</h:form>
Once bean.action is invoked it sets a value in bean.output. I need to access this value in my javascript, something like this
document.getElementById('form:cc:output').value
From myComp I can set the attribute with
getAttributes().put("output", output);
But the data resides in the backing bean. Any ideas?
You need a component to submit the 'output' value to the backing bean. Use inputHidden to accomplish this:
<composite:interface componentType="myComp">
<composite:attribute name="input" type="java.lang.Integer" />
<composite:attribute name="output" type="java.lang.Integer" />
<composite:attribute name="action" method-signature="java.lang.String action()"/>
</composite:interface>
<composite:implementation>
<h:inputText id="input" value="#{cc.attrs.input}" />
<h:inputHidden id="output" value="#{cc.attrs.output}" />
</composite:implementation>
Then you'll be able to set the 'output' value using its hidden input element via javascript.