Согласно документации JSF для <composite:interface>
:
Вложение составных компонентов
Реализация должна поддерживать вложение составных компонентов. В частности, должна быть возможность, чтобы раздел составного компонента действовал как страница использования для другого составного компонента. Когда составной компонент предоставляет поведенческий интерфейс используемой странице, такой как , или другой поведенческий интерфейс, должна быть возможность «распространить» доступность такого интерфейса в случае вложенного составного компонента. Автор составного компонента должен убедиться, что значения атрибутов имени точно совпадают на всех уровнях вложенности, чтобы эта экспозиция работала. Реализация не обязана поддерживать «переназначение» имен во вложенном составном компоненте.
Далее показан пример вложения <composite:actionSource>
, однако я тестировал почти такой же пример, и он не работает. Вот мой код:
Внутренний составной компонент:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface>
<composite:attribute name="actionText"
type="java.lang.String" default="nestedastest action" />
<composite:actionSource name="someaction" />
</composite:interface>
<composite:implementation>
<h:commandLink id="someaction">#{cc.attrs.actionText}</h:commandLink>
</composite:implementation>
</html>
Внешний составной компонент:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
xmlns:composite="http://java.sun.com/jsf/composite"
xmlns:test="http://java.sun.com/jsf/composite/components/test">
<composite:interface name="nestedActionTester"
displayName="A test composite component for nested actions">
<composite:attribute name="actionText"
type="java.lang.String" default="astest action" />
<composite:actionSource name="someaction" />
</composite:interface>
<composite:implementation>
<test:nestedastest actionText="#{cc.attrs.actionText}" />
</composite:implementation>
</html>
Фейслет:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
xmlns:test="http://java.sun.com/jsf/composite/components/test">
<h:head />
<h:body>
<ui:composition template="template.xhtml">
<ui:define name="content">
<h:form id="communityMembersForm">
<div>
<test:astest>
<f:actionListener for="someaction"
binding="#{testController.someActionActionListener}" />
</test:astest>
</div>
<div>
<test:nestedastest>
<f:actionListener for="someaction"
binding="#{testController.someActionActionListener}" />
</test:nestedastest>
</div>
</h:form>
</ui:define>
</ui:composition>
</h:body>
</html>
Управляемый компонент:
package test.controller;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionEvent;
import javax.faces.event.ActionListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ManagedBean
@ViewScoped
public class TestController {
private static Logger logger =
LoggerFactory.getLogger( TestController.class );
public ActionListener getSomeActionActionListener() {
return new ActionListener() {
@Override
public void processAction( ActionEvent event )
throws AbortProcessingException {
logger.debug( "someaction occurred..." );
}
};
}
}
Я использую Мохарру 2.1.13:
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>2.1.13</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>2.1.13</version>
<type>jar</type>
<scope>runtime</scope>
</dependency>
На коте 6.0.32:
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>el-api</artifactId>
<version>6.0.32</version>
<type>jar</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>servlet-api</artifactId>
<version>6.0.32</version>
<type>jar</type>
<scope>provided</scope>
</dependency>
Когда я запускаю это приложение, ссылка для nestedastest action
(это ссылка, которая напрямую использует внутренний составной компонент) вызывает запуск прослушивателя действий и печать сообщения журнала. Однако при нажатии на astest action
(внешний составной компонент) ничего не происходит. Учитывая, что это почти точно пример, показанный в официальном javadoc JSF, я ожидаю, что это сработает. Любая идея, почему это не так?
---------- РЕДАКТИРОВАТЬ ---------
Я обнаружил, что если я изменю внешний составной компонент таким образом:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
xmlns:composite="http://java.sun.com/jsf/composite"
xmlns:test="http://java.sun.com/jsf/composite/components/test">
<composite:interface name="nestedActionTester"
displayName="A test composite component for nested actions">
<composite:attribute name="actionText"
type="java.lang.String" default="astest action" />
<composite:actionSource name="someaction" targets="inner" />
</composite:interface>
<composite:implementation>
<test:nestedastest id="inner" actionText="#{cc.attrs.actionText}" />
</composite:implementation>
</html>
Обратите внимание, что я добавил атрибут target в actionSource и соответствующий идентификатор во вложенный составной компонент
Теперь он правильно свяжет действие. Это имеет смысл, но документация заставляет вас поверить, что в этом нет необходимости. Это ошибка в документации? Или в реализации (пробовал и на Мохарре 2.1.13 и на MyFaces 2.1.10)? Или в моем понимании?
/xhtml/astestmain.xhtml at line 17 and column 70 <f:actionListener> Parent is not composite component or of type ActionSource, type is: javax.faces.component.html.HtmlForm@1ebdcc9a
что вы можете видеть в разделе Facelet выше, родительский элемент является составным компонентом, < i>и у него есть<f:actionSource name='someaction'>
- person Lucas   schedule 01.12.2012<test:nestedastest id='inner' ... />
, а затем добавлю атрибут target в<composite:actionSource name='someaction' targets='inner' />
, он пройдет, как и ожидалось. Возможно, документация просто не совсем верна, и вы должны включить цели и значения идентификатора, чтобы связать ее? - person Lucas   schedule 01.12.2012actionSource
. И поскольку внутренний источник действияcc
на самом деле нацелен на несколько компонентов, я не могу добиться совпаденияid
самих компонентов. Итак, вы говорите, что, поскольку фактический конечный компонент не имеет того жеid
, что и всеactionSource
в цепочке, я должен использоватьtargets
полностью? Если да, пожалуйста, сделайте свой ответ ответом, чтобы я мог его принять. - person Lucas   schedule 03.12.2012