Question

i have main page as that contains interests composite component and links for lazy loaded tabs as follows:

1- profile page:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition template="../templates/application.xhtml"
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:o="http://omnifaces.org/ui"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:myapp="http://java.sun.com/jsf/composite/component"
    xmlns:p="http://java.sun.com/jsf/passthrough">
        <ui:define name="head">
    <title>Profile</title>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <link rel="stylesheet" type="text/css" href="#{request.contextPath}/resources/assets/css/jquery/jquery-ui.css" media="screen"/>
    <link rel="stylesheet" type="text/css" href="#{request.contextPath}/resources/assets/css/override-jquery.css" media="screen"/>
    <style>
        li
        {
            outline: none !important;
        }​
    </style>
    </ui:define>

<ui:define name="right-side">
    <div class="three-column right">          
    <myapp:interest bean="#{interestBean}" value="#{interestBean.interest}" id="interestCmp"></myapp:interest>              
    </div>
</ui:define>    
<ui:define name="content">
    <div class="tabs">
        <ul>
            <li><a id="tab1" href="tabs/tab1.xhtml">tab1</a></li>
            <li><a id="tab2" href="tabs/tab2.xhtml">tab2</a></li>
        </ul>
    </div>


<script type="text/javascript">head.ready(function(){$('.tabs').tabs();});</script>
</ui:define>
</ui:composition>

2- interests composite component:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
    xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:composite="http://java.sun.com/jsf/composite">

<composite:interface>
    <composite:attribute name="id" />
    <composite:attribute name="index" />
    <composite:attribute name="value" />
    <composite:attribute name="bean" /> 
</composite:interface>

<composite:implementation xmlns:myapp="http://java.sun.com/jsf/composite/component">
<div >
<aside class="interests">
    <header class="header-w-flag icon-star">
        <h1>Interests</h1>
    </header>
    <h:form id="interestForm">
    <h:panelGroup id="showInterests" layout="block">
    <ui:repeat var="interest" value="#{interestBean.getUserInterests()}" >
        <div class="interest">
        <div class="interest-name"><a href="">#{interest.interestName}</a> 
        <h:commandLink  action="#{interestBean.deleteInterest(interest)}" rendered="#{permissionBean.isCurrentUser(profileBean.user)}" >
        <i class="icon-delete control-icon" style="cursor:pointer;display:none;"></i>
        <f:ajax render="@form" execute="@this"></f:ajax>
        </h:commandLink></div>
        <div class="people-grid"> 
        <ui:repeat var="user" value="#{interestBean.getUsersByInterest(interest.id)}" varStatus="status" >
        <h:panelGroup id="interestedUsers">
                            <a title="#{user.firstName} #{user.lastName}" href="../profile/index.xhtml?id=#{user.id}"><img src="#{applicationBean.avatarBaseURL}#{user.avatarUrl}" alt="#{user.firstName}" /></a>
        </h:panelGroup>
        </ui:repeat>
        </div>


       </div>
    </ui:repeat>
    </h:panelGroup>
   </h:form>
</aside>

        </div>
</composite:implementation>
</html>

3- the tab1 code:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:o="http://omnifaces.org/ui"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:myapp="http://java.sun.com/jsf/composite/component"
    xmlns:p="http://java.sun.com/jsf/passthrough">

   <div id="tab1">
            <!-- feed here -->
            <h:panelGroup layout="block" class="posts" id="feedContainer">
            <h:form id="profileFeeds">
            <ui:repeat var="post" value="#{feedBean.feeds}" varStatus="status" >
                <myapp:feedpost value="#{post}" index="{status.index}"></myapp:feedpost>    
            </ui:repeat>
            <h:panelGroup layout="block" rendered="#{feedBean.feeds.size()==0}">
                <div class="post blue">
                    <div class="post-content">

                        <h1>Nothing</h1>

                    </div>
                </div>
            </h:panelGroup>  

            <div class="post load"><h:commandLink action="#{feedBean.getMoreHomeFeeds()}" styleClass="btn btn-primary btn-small">Show more feeds
            <f:ajax render=":feedContainer" ></f:ajax>
            </h:commandLink></div>
            </h:form>
        </h:panelGroup>
    </div>



</html>

4- feedpost composite component that is linked from tab1:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
    xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:composite="http://java.sun.com/jsf/composite">

<composite:interface>
    <composite:attribute name="id" />
    <composite:attribute name="index" />
    <composite:attribute name="value" />

</composite:interface>

<composite:implementation xmlns:myapp="http://java.sun.com/jsf/composite/component">
    <h:panelGroup layout="block" class="post">
    <div class="post-content">      




                <h:panelGroup layout="block">
                        <h1><h:outputFormat value="#{cc.attrs.value.title}" /></h1>
                </h:panelGroup>

tText value="#{baseBean.replaceWithHTMLBreak(cc.attrs.value.note)}" escape="false"/></p>
                </h:panelGroup>


        </div>
    <myapp:comments value="#{cc.attrs.value}"></myapp:comments>
    </h:panelGroup> 
</composite:implementation>

</html>

5- comments composite component that is linked from feedpost component:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
    xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:composite="http://java.sun.com/jsf/composite">

<composite:interface>
    <composite:attribute name="id" />
    <composite:attribute name="index" />
    <composite:attribute name="value" />    
</composite:interface>

<composite:implementation>
        <h:panelGroup layout="block" class="comments" id="feedcomments">
        <div class="actions">

            <h:commandLink id="addToInterestLink" value="#{msg['action.addto.interests']}" styleClass="action-like"
                action="#{feedBean.addToInterests(cc.attrs.value)}">
                <f:ajax  execute="@this" render=":interestCmp:interestForm:showInterests"></f:ajax>
            </h:commandLink>

        </div>
    </h:panelGroup>
</composite:implementation>

</html>

when clicking on tab1 link (lazy loaded jquery tab) that contains the comments composite component that has the link to render interests div in interest component, i am getting following exception:

<f:ajax> contains an unknown id ':interestCmp:interestForm:showInterests' - cannot locate it in the context of the component addToInterestLink

NOTE: one workaround i have found for the issue is to add the tab1 content statically to the page instead of linking it.

please advise how to fix that.

Was it helpful?

Solution

Okay, in a nutshell and somewhat simplified (composite components actually don't play a role in the problem), your problem is here:

profile.xhtml:

<my:composite id="interestCmp"> <!-- Yes, invalid code; just to summarize. -->
    <h:form id="interestForm">
        <h:panelGroup id="showInterests">
            ...
        </h:panelGroup>
    </h:form>
</my:composite>
<div class="tabs">
    <ul>
        <li><a id="tab1" href="tabs/tab1.xhtml">tab1</a></li>
        <li><a id="tab2" href="tabs/tab2.xhtml">tab2</a></li>
    </ul>
</div>
<script>head.ready(function(){$('.tabs').tabs();});</script>

And somewhere in tab1.xhtml

<h:form id="profileFeeds">
    <h:commandLink value="Add">
        <f:ajax render=":interestCmp:interestForm:showInterests" />
    </h:commandLink>
</h:form>

You're thus using jQuery UI tabs to have a tabbed panel with dynamic content. However, the tab page tab1.xhtml doesn't share the same JSF view as the main page profile.xhtml. It are physically completely distinct views. That totally explains why the <f:ajax> couldn't find the desired component in the component tree (the current view). It can only see components which are contained in tab1.xhtml itself. It doesn't see those of profile.xhtml. It can't even see those in tab2.xhtml.

It will only work if you preload tabs by <ui:include> instead of dynamically load them. This way the tab1.xhtml will physically end up in the same view as the desired component. Let's assume that you only need to do that for tab1.xhtml and the tab2.xhtml can be kept dynamically loaded. This should then solve your problem:

<div class="tabs">
    <ul>
        <li><a id="tab1" href="#tab1_page">tab1</a></li>
        <li><a id="tab2" href="tabs/tab2.xhtml">tab2</a></li>
    </ul>
    <div id="tab1_page">
        <ui:include src="tabs/tab1.xhtml" />
    </div>
</div>

You only need to replace the <?xml...?><!DOCTYPE ...><html xmlns...> and </html> of tab1.xhtml (and actually also tab2.xhtml) by <ui:composition xmlns...> and </ui:composition> respectively. Because otherwise you end up in syntactically invalid HTML.

If you really need to have dynamically/lazily loaded tabs, then you'd better look for a fullworthy JSF component capable of the job, such as PrimeFaces <p:tabView>. Even more, PrimeFaces uses jQuery/UI under the covers for the look'n'feel, so many things will be very simliar to the current approach.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top