1

I want to create dynamic dialog windows by using <ui:repeat> and <p:dialog> with <ui:include>. But there's an exception when I tried like below.

main.xhtml

<p:outputPanel id="windowsPanel" layout="block" style="width:100%;">
    <p:outputPanel rendered="#{mainView.dynamicWindows ne null}">
        <ui:repeat var="item"  value="#{mainView.dynamicWindows}">
            <p:dialog binding="#{item.dialog}">
                <ui:include src="#{item.includedWindowPath}" />
            </p:dialog>
        </ui:repeat>
    </p:outputPanel>
</p:outputPanel>

MainView.java

@ManagedBean(name = "mainView")
@SessionScoped
public class MainView extends BaseView {

private static final long serialVersionUID = -6291834350102049312L;

private List<Window> dynamicWindows;

@PostConstruct
public void init() {
    fillWindows();
}

private void fillWindows() {
    dynamicWindows = new ArrayList<Window>();

    for (int i = 0; i < 3; i++) {
        Window window = new Window("Header " + i);
        window.getDialog().setId("_dynamicWindow" + i);
        window.getDialog().setWidgetVar("_dynamicWindowWidget" + i);
        dynamicWindows.add(window);
    }
}

// getters & setters

The exception:

javax.servlet.ServletException: /main.xhtml @33,42 binding="#{item.dialog}": Target Unreachable, identifier 'item' resolved to null
    javax.faces.webapp.FacesServlet.service(FacesServlet.java:422)
    org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:79)
    org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:198)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:369)
    org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109)
    org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
    org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:97)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
    org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:100)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
    org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:78)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
    org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
    org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:35)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
    org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:187)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
    org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
    org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:79)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:381)
    org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:168)
    org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
    org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
    org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
ogok
  • 219
  • 1
  • 4
  • 14

2 Answers2

6

The <ui:include> is a tag handler which runs during view build time, while the <ui:repeat> is an UI component which runs during view render time. Tag handlers produces the JSF UI component tree. JSF UI components produces HTML. They do not run in sync.

So, when the <ui:include> runs, the #{item} which is specified by <ui:repeat var> is simply not available in the scope, because the <ui:repeat> hasn't run at that time. You need an iterating tag handler instead of an iterating JSF UI component. The JSTL <c:forEach> is such one. Replacing <ui:repeat> by <c:forEach> should fix this issue. It may however have undesireable side effects. It's hard to tell beforehand as your concrete functional requirements are not fully clear.

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thank you for your answer. But when i tried to use c:forEach the same exception occurred again at the line of p:dialog. I want to generate dynamic dialog windows and the contents of these dialogs should be replaceable. So i used ui:include. Maybe the way i used isn't the correct way. The count of the dialogs isn't important. There may be zero or n dialogs. There will be only one page. And the user clicked any link i will generate the window object and rerender the page with generated dialogs. If the user clicks the students link, the content of the dialog will be students.xhtml. – ogok Mar 08 '12 at 07:10
  • @BalusC: I too have a similar requirement to build a list of items using ui:repeat but using a dynamically chosen template for each item in list, using ui:include. I've gone through this & similar other questions but I realized that even c:forEach is not a too good solution as it would lead to huge component tree(in case the included template is complex) & thus bad performance, on the other hand with ui:repeat just a smaller component tree is built. Also I'm restricted to use c:forEach because of some other reasons as well, so what is the proper way(not just a workaround) to deal with this? – Rajat Gupta Dec 02 '12 at 18:14
  • Do we need a new custom component ? – Rajat Gupta Dec 02 '12 at 18:16
  • Isn't using several `ui:fragment`(s)(within `ui:repeat`) with `rendered` attribute a better solution in terms of component tree being created would not be too big as in case of `c:forEach`? (ok, that would be acceptable only when the no of cases for chosing templates is bearably small & less than no of items in list)\. – Rajat Gupta Dec 02 '12 at 18:28
  • @user01: This is not true. The `rendered` attribute is evaluated during view render time. Yes, the `` is an `UIComponent`. – BalusC Dec 03 '12 at 00:42
  • what I mean to say is that, with `c:forEach` the components inside the loop are repeated in the component tree are many times as size of list, however with ui:repeat that's not the case. Say if I have only 4-5 cases for dynamic xhtml inclusion, then it may be worth using ui:repeat with rendered attributes on ui:fragment or h:panelGroup to dynamically choose 1 out of several cases for rendering as xhtml. These cases wont be repeated in component tree for each item in list but just once. So isn't ui:repeat with multiple ui:fragment(s)/h:panelGroup(s) with rendered attribute better solution? – Rajat Gupta Dec 03 '12 at 04:42
  • to make my self more clearer, I just added an answer below just to clarify my understanding to you. – Rajat Gupta Dec 03 '12 at 05:00
0

If you have say a limited no of cases (say for e.g 4-5 cases) to dynamically choose from & include for an item within ui:repeat then it may be worth doing it this way, as it would save you from building huge component trees with c:forEach if your list to iterate is bigger. This'll conditionally just render one out of several cases to include xhtml from. These cases wont be repeated multiple times in the component tree, for each time in your list. Hopefully, this should give better performance & also save from concerns of mixing JSF with JSTL.

    <ui:repeat var="item"  value="#{mainView.dynamicWindows}">
         <h:panelGroup rendered="#{booleancase1}">
            <ui:include src="case1.xhtml" />
         </h:panelGroup>

         <h:panelGroup rendered="#{booleancase2}">
            <ui:include src="case2.xhtml" />
         </h:panelGroup>

         <h:panelGroup rendered="#{booleancase3}">
            <ui:include src="case3.xhtml" />
         </h:panelGroup>

         <h:panelGroup rendered="#{booleancase4}">
            <ui:include src="case4.xhtml" />
         </h:panelGroup>
    </ui:repeat>
Rajat Gupta
  • 25,853
  • 63
  • 179
  • 294
  • Your introduction is incorrect. The `` doesn't run during view build time at all, so you still end up with the component tree of the same size. Only the HTML output size is reduced. If you'd really like to reduce the component tree size, use `` or `` instead --which in turn requires ``, of course :) – BalusC Dec 03 '12 at 11:53
  • as I said in my previous comments, with `c:forEach` the components inside the loop are **repeated in the component tree as many times as size of list** (isn't that true!?), however with ui:repeat that should not be the case, No!? ui:repeat just includes the components inside of it only once in the component tree..?! – Rajat Gupta Dec 03 '12 at 14:07
  • 1
    JSTL runs during view build time, not during view render time. Your code results in a component tree with content of **all** include files which is only conditionally rendered during view render time. If you have used `` and ``, then the code would result in a component tree with content of **only** the desired include file which is always rendered. Carefully read http://stackoverflow.com/questions/3342984/jstl-in-jsf2-facelets-makes-sense to better understand "view build time" versus "view render time". – BalusC Dec 03 '12 at 14:13
  • I've gone through the post you linked up & also understand & agree to what you're saying but I just wanted to stress on the statement that whether or not `c:forEach` repeats the components inside loop for every single item in the list vs ui:repeat just includes the components inside it only once(yes I very well understand that all included components/files will be included & one rendered during render time but the inclusion is only once instead of repetitions in case of `c:forEach`). i hope you understand what I'm trying to convey. – Rajat Gupta Dec 03 '12 at 14:30
  • 1
    The `` runs during view build time as well. Your current code still ends up with the content of ALL include files in the final JSF component tree (which is later during view render time conditionally rendered). When using `` or `` to conditionally add the `` to the JSF component tree instead of using `rendered` attribute to conditionally render the HTML output, this will not happen. – BalusC Dec 03 '12 at 14:31
  • yes but you see, I have to display a list of items not just one item. if it had been single item i would agree that I should use c:choose as that will include only once but you see that when I have to display a list of items, why should I repeat the components inside of c:forEach multiple times(even if say there is just a single & always rendered component).. – Rajat Gupta Dec 03 '12 at 14:35
  • The `` is useful if the size of the includes is not determined in the view side (where you could just harcode them all) but only in the model (e.g. based on some DB). If you know them all, just feel free using `` or `` alone without a `` (and ``). – BalusC Dec 03 '12 at 14:37
  • yes but I am just referring to case when I know how many include cases could be there. I have just 4-5 cases to check for each item but need to show a big list of 30-50 items. For each item in list, I just want to pick 1 from amongst 5 include files after looking at the item. – Rajat Gupta Dec 03 '12 at 14:53