Creating dynamic controls in jsf managed bean? - jsf

I want to dynamically create object of HtmlDivElement in my jsf managed bean and add it to panel but it seems that HtmlDivElement is interface. So, how can i do it?

This is a pretty major confusion. The org.w3c.dom.html.HTMLDivElement is not a JSF component. This represents a W3 DOM element which has an entirely different purpose (JAXP, DOM parsing).
You need a subclass of javax.faces.component.UIComponent (just click your way through the "Direct Known Subclasses" in the aforelinked Javadoc to find them all). To render a HTML <div> element, just use HtmlPanelGroup whose layout attribute is set to block.
HtmlPanelGroup div = new HtmlPanelGroup();
div.setLayout("block");
someParentComponent.getChildren().add(div);
which does effectively the same as the following in "static" JSF:
<h:panelGroup layout="block" />

Related

primefaces update attribute not working on modal dialog opened from modal dialog [duplicate]

I have a question about the idea behind the fact, that only UIForm got the attribute prependId. Why is the attribute not specified in the NamingContainer interface? You will now probably say that's because of backward compability but I would preferre breaking the compability and let users which implement that interface, also implement methods for the prependId thing.
The main problem from my perspective about the prependId in the UIForm component is, that it will break findComponent()
I would expect that if I use prependId, then the NamingContainer behaviour would change, not only related to rendering but also when wanting to search for components in the component tree.
Here a simple example:
<h:form id="test" prependId="false">
<h:panelGroup id="group"/>
</h:form>
Now when i want to get the panelGroup component I would expect to pass the string "group" to the method findComponent(), but it won't find anything, I have to use "test:group" instead.
The concrete problem with that is, when using ajax with prependId="false". The ajax tag expects in the attributes update and process, that the values care of naming containers. It's a bit strange that when I use prependId="false" that I have to specify the full id or path, but okay.
<h:form id="test" prependId="false">
<h:panelGroup id="group"/>
</h:form>
<h:form id="test1" prependId="false">
<h:commandButton value="go">
<f:ajax render="test:group"/>
</h:commandButton>
</h:form>
Well this code will render without problems but it won't update the panelGroup because it cannot find it. The PartialViewContext will contain only the id "group" as element of the renderIds. I don't know if this is expected, probably it is but I don't know the code. Now we come to the point where the method findComponent() can not find the component because the expression passed as parameter is "group" where the method would expect "test:group" to find the component.
One solution is to write your own findComponent() which is the way I chose to deal with this problem. In this method i handle a component which is a NamingContainer and has the property prependId set to false like a normal UIComponent. I will have to do that for every UIComponent which offers a prependId attribute and that is bad. Reflection will help to get around the static definition of types but it's still not a really clean solution.
The other way would be introducing the prependId attribute in the NamingContainer interface and change the behaviour of findComponent() to work like described above.
The last proposed solution would be changing the behaviour of the ajax tag to pass the whole id, but this would only solve the ajax issue and not the programmatic issues behind the findComponent() implementation.
What do you think about that and why the hell is it implemented like that? I can't be the first having this problem, but I wasn't able to find related topics?!
Indeed, UIComponent#findComponent() as done by <f:ajax render> fails when using <h:form prependId="false">. This problem is known and is a "Won't fix": JSF spec issue 573.
In my humble opinion, they should never have added the prependId attribute to the UIForm during the JSF 1.2 ages. It was merely done to keep j_security_check users happy who would like to use a JSF form with JSF input components for that (j_security_check requires exact input field names j_username and j_password which couldn't be modified by configuration). But they didn't exactly realize that during JSF 1.2 another improvement was introduced which enables you to just keep using <form> for that instead of sticking to <h:form>. And then CSS/jQuery purists start abusing prependId="false" to avoid escaping the separator character : in their poorly chosen CSS selectors.
Just don't use prependId="false", ever.
For j_security_check, just use <form> or the new Servlet 3.0 HttpServletRequest#login(). See also Performing user authentication in Java EE / JSF using j_security_check.
For CSS selectors, in case you absolutely need an ID selector (and thus not a more reusable class selector), simply wrap the component of interest in a plain HTML <div> or <span>.
See also:
How to select JSF components using jQuery?
How to use JSF generated HTML element ID with colon ":" in CSS selectors?
By default, JSF generates unusable ids, which are incompatible with css part of web standards

JSF same ID on rendered

Let's say I am using rendered as basically a case statement. I have a label and message for an input field, but I want the field itself to change depending on the case. As such:
<p:inputText id="foo" value="#{myBean.params[paramKey]}"
rendered="#{paramIsInput}" />
<p:calendar id="foo" value="#{myBean.params[paramKey]}"
rendered="#{paramIsCalendar}" />
If I do that then I get the following error: java.lang.IllegalStateException: Component ID j_idt64:foo has already been found in the view.
As a workaround I created lots of labels/messages for each param type and changed their ids. But this brings my question. If only one component with an id is actually rendered, why would it matter that I have multiple defined in my jsf file? Is there a way to keep them with all the same ID?
JSF component IDs are supposed to be unique during view build time already, not during view render time only. This way you effectively end up with two JSF components with the same ID which is indeed invalid. You'd like to effectively end up with one JSF component with the desired ID in the JSF component tree after view build time.
You can achieve this by populating the component during the view build time instead of generating its HTML output conditionally during the view render time. You can use the JSTL <c:if> tag for this.
<c:if test="#{paramIsInput}">
<p:inputText id="foo" value="#{myBean.params[paramKey]}" />
</c:if>
<c:if test="#{paramIsCalendar}">
<p:calendar id="foo" value="#{myBean.params[paramKey]}" />
</c:if>
This has however caveats: the <c:if test> condition can't depend on a variable which is only known during JSF render time. So it has not to depend on var of a JSF iterating component, or to be a property of a view scoped bean, etc.
See also:
JSTL in JSF2 Facelets... makes sense?
If only one component with an id is actually rendered, why would it matter that I have multiple defined in my jsf file?
How would JSF know that only one component will be rendered? You are using EL in rendered and both can evaluate to true. Here is the documentation which says you can't have duplicate ids inside a naming container.
The specified identifier must be unique among all the components (including facets) that are descendents of the nearest ancestor UIComponent that is a NamingContainer, or within the scope of the entire component tree if there is no such ancestor that is a NamingContainer.
-
Is there a way to keep them with all the same ID?
In case you still want to have same ids on more than one components you need to separate the naming container.
You can use PanelGrid as a naming container.

How to not render whole block in JSF?

Is there a JSF 2.1 component which lets me conditionally render (or not render) all its content? Something like
<h:component rendered="#{user.loggedIn}">
...a bunch of jsf components and HTML code...
...even more HTML code...
</h:component>
I am using PrimeFaces 3M4 as this may influence your answer!
<h:panelGroup>
If you set attribute layout="block", you will have a <div> tag
Otherwise, you have a <span> tag.
In general most of jsf components support the render attribute (never bumped in some that does not),
container components like h:panelGrid or h:panelGroup supports the rendered attribute and if its set to false all its child will be hidden too
Same goes for the primefaces components ,and if not it probably a bug (i think there was an issue with tabview of primefaces)
Here's a link for primefaces user guide, you can find supported attributes of all primefaces components there User’s Guide for 3.0.M4

JSF 2.0: Preserving component state across multiple views

The web application I am developing using MyFaces 2.0.3 / PrimeFaces 2.2RC2 is divided into a content and a navigation area. In the navigation area, which is included into multiple pages using templating (i.e. <ui:define>), there are some widgets (e.g. a navigation tree, collapsible panels etc.) of which I want to preserve the component state across views.
For example, let's say I am on the home page. When I navigate to a product details page by clicking on a product in the navigation tree, my Java code triggers a redirect using
navigationHandler.handleNavigation(context, null,
"/detailspage.jsf?faces-redirect=true")
Another way of getting to that details page would be by directly clicking on a product teaser that is shown on the home page. The corresponding <h:link> would lead us to the details page.
In both cases, the expansion state of my navigation tree (a PrimeFaces tree component) and my collapsible panels is lost. I understand this is because the redirect / h:link results in the creation of a new view.
What is the best way of dealing with this? I am already using MyFaces Orchestra in my project along with its conversation scope, but I am not sure if this is of any help here (since I'd have to bind the expansion/collapsed state of the widgets to a backing bean... but as far as I know, this is not possible). Is there a way of telling JSF which component states to propagate to the next view, assuming that the same component exists in that view?
I guess I could need a pointer into the right direction here. Thanks!
Update 1: I just tried binding the panels and the tree to a session-scoped bean, but this seems to have no effect. Also, I guess I would have to bind all child components (if any) manually, so this doesn't seem like the way to go.
Update 2: Binding UI components to non-request scoped beans is not a good idea (see link I posted in a comment below). If there is no easier approach, I might have to proceed as follows:
When a panel is collapsed or the tree is expanded, save the current state in a session-scoped backing bean (!= the UI component itself)
The components' states are stored in a map. The map key is the component's (hopefully) unique, relative ID. I cannot use the whole absolute component path here, since the IDs of the parent naming containers might change if the view changes, assuming these IDs are generated programmatically.
As soon as a new view gets constructed, retrieve the components' states from the map and apply them to the components. For example, in case of the panels, I can set the collapsed attribute to a value retrieved from my session-scoped backing bean.
Update 3: I got it working as described above. To sum it up, the solution is to store the relevant properties in a session-scoped bean instead of making the entire UIComponent session-scoped. Then, when the component is re-constructed after navigation has occurred, set the attribute values by retrieving the saved properties (using EL), e.g.
<p:panel collapsed="#{backingBean.collapsedState}" ... />
(This is a simplified example. Since I am using multiple panels, I am using a map to store these properties, as described above).
One solution would be to use session-scoped beans.
What do you mean by collapsible panels? I ask because there is a component that is closable as well as a component. I am using in the navigation pane in my project. The accordianPanel has an attribute named "activeIndex". Here's what I did in my sessionBean to maintain the state of my accordion tabs:
private int tabIndex; //declared a private variable
public SessionBean() {
tabIndex = 100; //set the initial tab index to 100 so all tabs are closed when page loads.
}
public int getTabIndex(){
return tabIndex;
}
public void setTabIndex(int tabIndex){
this.tabIndex=tabIndex;
}
in my navigation pane:
<p:accordionPanel activeIndex="#{sessionBean.tabIndex}" collapsible="true" autoHeight="false">
<p:tab title="#{tab1_title}">
<h:commandLink value="link here" action="target_page?faces-redirect=true" /><br/>
</p:tab>
<p:tab title="#{tab2_title}">
<h:commandLink value="link here" action="target_page?faces-redirect=true" />
</p:tab>
<p:tab title="#{tab3_title}">
<h:commandLink value="link here" action="target_page?faces-redirect=true" />
</p:tab>
</p:accordionPanel>
I'm not using the tree component for navigation as that presented my project with some difficulties that were easily overcome by using the accordionPanel, so I can't speak to that part of your navigation.

Adding JSF 2 composite component at runtime from backing bean

Edited question...
Hello,
I would like to load a .xhtml file of my composite component from a backing bean, and add it to the page dynamically. The name of the .xhtml file comes form a variable.
Ex.:
public MyBean (){
String componentFile = "myCompositeComponent.xhtml"
public String addComponentToPage(){
//how do that?...
return null;
}
}
Thank you!
That's not possible. A composite component is template-based and can only be used in views. Your best bet is to repeat exactly the JSF code which you've originally written in the composite component in the model. Better would be to create a full worthy #FacesComponent class which extends UIComponent, complete with a #FacesRenderer. True, it's a tedious and opaque job, but this way you'll end up with a component which is reuseable in both the view and the model by a single code line.
An -ugly- alternative is to place all possible components in the view and use the rendered attribute.
<my:component1 rendered="#{bean.myComponentType == 'component1'}" />
<my:component2 rendered="#{bean.myComponentType == 'component2'}" />
<my:component3 rendered="#{bean.myComponentType == 'component3'}" />
...
Wrap this if necessary in a Facelets tag file so that it can be hidden away and reused in several places.
I don't understand why do you want to add a composite component from a backing bean. I guess you want to make it visible dynamically in case of an event, but for that there is AJAX reRender.
For example you can do the following:
<h:panelGroup id="composite" rendered="#{myBean.renderComponent}">
<my:compositecomponent/>
</h:panelGroup>
The renderComponent property stores a boolean value. You can switch that value and reRender composite with for e.g. Richfaces's <a4j:commandLink>.
Hope that helps, Daniel

Resources