I'm trying to forward "f:validateRequired" validator through a composite component without using required attribute.
How to get its value inside of my component ?
<aa:myComponent id="specificNotice" value="#{edit.specificNotice}">
<f:validateRequired for="specificNotice" disabled="#{empty param['form:save']}" />
</aa:myComponent>
Thanks.
The for attribute should refer the id of the input component inside the composite component implementation. The input component in turn should be declared as <cc:editableValueHolder> inside the composite component interface.
So,
<my:input value="#{bean.input}">
<f:validateRequired for="input" />
</my:input>
with
<cc:interface>
<cc:editableValueHolder name="input" />
</cc:interface>
<cc:implementation>
<h:inputText id="input" value="#{cc.attrs.value}" />
</cc:implementation>
should do.
Related
I have a custom component that uses c:if to determine the ajax to use:
<composite:interface>
<composite:attribute name="value" required="true" />
<composite:attribute name="renderOnChange" type="java.lang.String"/>
</composite:interface>
<composite:implementation>
<h:inputText value="#{cc.attrs.value}">
<c:if test="#{not empty cc.attrs.renderOnChange}">
<a4j:ajax event="change" render="#{cc.attrs.renderOnChange}" />
</c:if>
<c:if test="#{empty cc.attrs.renderOnChange}">
<a4j:ajax event="change" render="#{somethingDifferent}" />
</c:if>
</h:inputText>
</composite:implementation>
The problem happens when I try to use the component in a data table because the c:ifs do not work. Is there a JSF equivalent that could be used to show the a4j:ajax depending on the attributes? I have tried ui:fragment, and a number of other ui tags to try to achieve this but none of them work inside the input component.
I would also like to use the same method to show f:validators.
Possible way is to create two <h:inputText> components then you can use the rendered attribute and place your condition from the <c:if> tags there.
I want to have a composite that composes
<h:form id="f_imgA" >
<h:graphicImage id="imgA"
onclick="document.getElementById('#{k_imgA.clientId}').value=mods(event)"
value="images/img?r=#{Math.random()}">
<f:ajax event="click" listener="#{mBean.handleEvent}"
execute="#this k_imgA" render="#this"></f:ajax>
</h:graphicImage>
<h:inputHidden id="k_imgA" binding="#{k_imgA}" value="#{mBean.keyX}" />
</h:form>
when I write
<comps:cimg imgId="imgA" />
The original purpose of this code is to send the modifier-states (Ctrl, Shift, Alt) to the server.
I have
<composite:interface>
<composite:attribute name="imgId" />
</composite:interface>
<composite:implementation>
<h:form id="f_#{cc.attrs.imgId}">
<h:graphicImage id="#{cc.attrs.imgId}"
onclick="document.getElementById('#{k_${cc.attrs.imgId}.clientId}').value=mods(event)"
value="images/img?r=#{Math.random()}">
<f:ajax event="click" execute="#this k_#{cc.attrs.imgId}"
listener="#{mBean.handleEvent}" render="#this">
</f:ajax>
</h:graphicImage>
<h:inputHidden id="k_#{cc.attrs.imgId}"
binding="k_#{cc.attrs.imgId}" value="#{mBean.keyX}" />
</h:form>
</composite:implementation>
which, quite expected, does not work. The offending expression is
#{k_${cc.attrs.imgId}.clientId}
which is intended to return the clientId of the hiddenInput with id k_imgA . As far as I know, EL cannot handle nested expressions like the one above, but it was worth a try. So is there a simple, straightforward way to get the clientId of k_imgA? I don't want to use more javascript, if this can be avoided.
Edit:
don't get confused about #{Math.random()}, it works just because I have a bean called "Math".
The javascript function mods is given by
<h:outputScript target="body">function mods(event) {return ((event.ctrlKey)?1:0)+((event.shiftKey)?2:0)+((event.altKey)?4:0)} </h:outputScript>
You don't need to fiddle with all those _#{cc.attrs.imgId}. Just give the composite a fixed id. They are already naming containers themselves. JSF will then worry about the rest.
<composite:implementation>
<h:form id="f">
<h:graphicImage id="i" ... />
<h:inputHidden id="k" ... />
</h:form>
</composite:implementation>
Usage:
<comps:cimg id="imgA" />
Generated HTML:
<form id="imgA:f" ...>
<img id="imgA:f:i" ... />
<input id="imgA:f:k" ... />
</form>
As to the JS attempt, you'd best use element's own ID as base:
<h:graphicImage onclick="document.getElementById(id.substring(0,id.lastIndexOf(':')+1)+'k').value='...'" />
Or, easier, if the hidden element is guaranteed to be the direct sibling of the image element in the generated HTML DOM tree, then just grab it by Node#nextSibling:
<h:graphicImage onclick="nextSibling.value='...'" />
<h:inputHidden ... />
The binding will never work as in your attempted construct, and even then you'd best do it via a Map in request scope or a so-called backing component.
See also:
Accessing JSF nested composite component elements in JavaScript
Integrate JavaScript in JSF composite component, the clean way
Rerendering composite component by ajax
I have a composite (X) like this:
<composite:interface>
<composite:attribute name="textValue" />
<composite:attribute name="textValueChangeListner"
method-signature="void valueChanged(javax.faces.event.ValueChangeEvent)" />
<composite:implementation>
<ice:inputText
value="#{cc.attrs.textValue}"
valueChangeListener="#{cc.attrs.textValueChangeListner}"/>
In the JSF page I have something like:
<X:iText
textValue="#{cardBean.getCardValue}"
textValueChangeListner="#{cardHandler.cardValueChanged}" />
The above code works fine. But it does not work when NO "textValueChangeListner" is passed to the composite from JFace page; i.e:
<X:iText
textValue="#{cardBean.getCardValue}" />
Error I got:
[javax.enterprise.resource.webcontainer.jsf.lifecycle] Unable to resolve composite component from using page using EL expression '#{cc.attrs.textValueChangeListner}': javax.faces.FacesException: Unable to resolve composite component from using page using EL expression '#{cc.attrs.textValueChangeListner}'
In my scenario it is necessary that page developer may or may not supply the "textValueChangeListner" to the composite component.
How can I achieve that ?
Rename the attribute to valueChangeListener and use targets attribute,
<composite:attribute name="valueChangeListner"
method-signature="void valueChanged(javax.faces.event.ValueChangeEvent)"
targets="text" />
where text is the ID of the target input component,
<ice:inputText id="text" ... />
and remove the valueChangeListener from it.
You have two options here: First one is the easy way, just render another input text without having a valueChangeListener if the user didn't supply Value Change listener.
<ice:inputText
value="#{cc.attrs.textValue}"
valueChangeListener="#{cc.attrs.textValueChangeListener}"
rendered="#{!empty cc.attrs.textValueChangeListener}"/>
If you need to have a valueChangeListener in any case then apply an default value for the attribute:
<composite:attribute name="textValueChangeListener"
method-signature="void valueChanged(javax.faces.event.ValueChangeEvent)"
required="false"
default="#{cc.valueChangedListener}" />
For doing this you need to bind your composite component to a backing bean. And you need to define components' backing bean type through its interface declaration like this:
<composite:interface componentType="yourComponentBean">
<composite:attribute name="textValueChangeListener"
method-signature="void valueChanged(javax.faces.event.ValueChangeEvent)"
required="false"
default="#{cc.valueChangedListener}" />
</composite:interface>
And here is yourComponentBean which implements the default ValueChangedListener.
#FacesComponent("yourComponentBean")
public class YourComponentCC extends UINamingContainer
{
public void valueChangedListener(ValueChangeEvent ev)
{
....
}
}
Btw cc is a shortcut in EL to access backing bean that is defined as the componentType in your component. so cc.valueChangedListener will call valueChangedListener method defined in YourComponentCC class.
Here is my composite component:
<composite:interface>
<composite:attribute name="attr1" />
<composite:clientBehavior name="xyz" event="valueChange" targets="chkbox" />
</composite:interface>
<composite:implementation>
<h:panelGrid>
<h:panelGroup>
<h:selectBooleanCheckbox id="chkbox"
value="#{cc.attrs.attr1}">
</h:selectBooleanCheckbox>
</h:panelGroup>
</h:panelGrid>
</composite:implementation>
And my page:
<h:form id="myForm">
<cc:myComp attr1="#{myBean.someAttr}">
<f:ajax render="myform:grid1" event="xyz" listener="{myBean.listenerMethod}"/>
</cc:myComp>
<h:panelGrid id="grid1">
<h:panelGroup>
<h:inputTextarea id="rationale" rows="4" cols="70"
value="#{myBean.rationale}" />
</h:panelGroup>
</h:panelGrid>
</h:form>
I'm getting below error:
<f:ajax> contains an unknown id 'myForm:grid1' - cannot locate it in the context of the component chkbox
If I remove render="myform:grid1" from my code then ajax call is working fine. Basically from my composite component I'm not able to refer another OUTSIDE component. How is this caused and how can I solve it?
<f:ajax render="myform:grid1">
Any client ID which does not start with the NamingContainer separator character, which is in your case :, is relative to the closest NamingContainer parent. The closest NamingContainer parent is in your particular case the composite component itself. So, this construct is basically looking for a component with the full client ID myform:XXX:myform:grid1 relative to the composite component, where XXX is the autogenerated ID of the composite component. However, there's no such component with this full client ID.
Assuming that the full client ID of the panel grid is indeed myform:grid1 (i.e. when you open the page in browser, rightclick and View Source, you're indeed seeing <table id="myform:grid1">), then you should make it an absolute client ID instead by prefixing it with the NamingContainer separator character:
<f:ajax render=":myform:grid1">
See also:
How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"
Currently I'm trying to implement webpart technology with JavaServer Faces 2.0 with Facelets view technology for educational purposes. I have created facelet templates, facelet custom components and made a few facelet "template" clients. But in one thing I'm stuck. I can't dynamically load controls and put them cc:attributes.
If I have a page for example with static text or bind it with ManagedBean the property ui:include everything works well.
<ui:define name="right-column">
right-column asd
<h:link outcome="asdf" value="link_get">
<f:param name="aa" value="123" />
<f:param name="a" value="123 dd + 20" />
</h:link>
<h:commandLink action="asdf?faces-redirect=true" value="asdf">
<f:param name="aa" value="123" />
</h:commandLink><br />
<ui:include src="./resources/Controls/CategoryTree.xhtml"/><br />
This works even if I put src with MenageBean property.
<ui:include src="#{browseProducts.incudePath}"/>
</ui:define>
Here is my facelet control (data binding is inside this control within #{TreeBean.root}:
<!-- NO INTERFACE -->
<cc:interface>
</cc:interface>
<!-- IMPLEMENTATION -->
<cc:implementation>
<!-- This is a very simply scaffolding for Category Three Control.
-->
<p:tree value="#{TreeBean.root}" var="node"
expandAnim="FADE_IN" collapseAnim="FADE_OUT">
<p:treeNode>
<h:outputText value="#{node}" />
</p:treeNode>
</p:tree>
</cc:implementation>
But I have problem when ui:include points to a control with cc:attribute. I don't know how to initialize this attribute from backing bean and do "stuff".
For example I have this page:
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets"
template="./resources/layout/Template.xhtml"
xmlns:sc="http://java.sun.com/jsf/composite/Controls">
<ui:define name="right-column">
<sc:dummy ItemCount="10" />
<ui:include src="./resources/Controls/dummy.xhtml" />
</ui:define>
</ui:composition>
Here goes the composite control:
<cc:interface>
<cc:attribute name="ItemCount" required="true"
shortDescription="This attribute is meaningful " />
</cc:interface>
<!-- IMPLEMENTATION -->
<cc:implementation>
<!-- How to pass ItemCount to my dummy bean to create so many items in
list as ItemCount value -->
<ui:repeat value="#{dummy.dummyList}" var="dummyItem">
<h:outputText value="#{dummyItem}" />
</ui:repeat>
</cc:implementation>
And backing bean code:
public ArrayList<String> getDummyList() {
//Here I try to get dummy list work.
dummyList = new ArrayList<String>(getDummyCount());
for (int i=0;i< getDummyCount();i++){
dummyList.add(i + "" + i);
}
return dummyList;
}
How can this be done?
I think you have two problems:
calling a method with parameter from a composite component
specifying some parameter to an included page
For 1., since jsf 2, you could call the method directly, specifying the parameter (which should be part of method signature):
<ui:repeat value="#{dummy.getDummyList(cc.attrs.dummyCode)}" var="dummyItem">
<h:outputText value="#{dummyItem}" />
</ui:repeat>
But I suspect you are trying to use a backing for something that it isn't designed for. Maybe you'll be interested in writing backing java code for your composite component, which is different. It's difficult to master if you are a beginner, though. I'd first try to design my pages and bean interactions differently. I don't know which problem you are trying to solve, but at first look, this solution looks too complicated.
For 2., you should have a look at ui:param. A quick google search gives me this: http://www.jsfcentral.com/articles/facelets_3.html