2013-12-22 8 views
2

(в данном примере мы используем primefaces компоненту, но вопрос не связан с Primefaces)JSF композита - Аякс поведение для итерационных элементов

Введения:

Для того, чтобы иметь АЯКС поддержки составных элементов компонентов мы просто используем элемент:

  • композиционный: clientBehavior

Давайте посмотрим на эту ситуацию:

<composite:interface> 
    <composite:clientBehavior name="dateSelect" event="dateSelect" targets="id111 id222" /> 
</composite:interface> 

<composite:implementation> 

    <p:calendar id="id111" value="#{csController.selectedDate}" mode="inline" 
       mindate="#{csController.minDate(2013,9)}" 
       maxdate="#{csController.maxDate(2013,9)}"/> 

    <p:calendar id="id222" value="#{csController.selectedDate}" mode="inline" 
       mindate="#{csController.minDate(2013,10)}" 
       maxdate="#{csController.maxDate(2013,10)}"/> 

</composite:implementation> 

Мы имеем два элемента и поддержку Ajax для этих двух элементов. Это работает так, как ожидалось. Мы могли бы даже изменить на этот интерфейс:

<composite:interface> 
    <composite:clientBehavior name="dateSelect" event="dateSelect" targets="id111" /> 
    <composite:clientBehavior name="dateSelect" event="dateSelect" targets="id222" /> 
</composite:interface> 

и это все еще работает отлично.

Проблема:

Я хотел бы изменить реализацию, чтобы показать произвольное число календарей, не exaclty два, как показано выше. Поэтому я пробовал это:

<composite:interface> 
    <composite:attribute name="firstMonth" default="1"/> 
    <composite:attribute name="lastMonth" default="12"/> 

    <c:forEach var="i" begin="#{cc.attrs.firstMonth}" end="#{cc.attrs.lastMonth}"> 
     <composite:clientBehavior name="dateSelect" event="dateSelect" targets="#{cc.clientId}#{i}"/> 
    </c:forEach> 

</composite:interface> 

<composite:implementation> 

    <c:forEach var="i" begin="#{cc.attrs.firstMonth}" end="#{cc.attrs.lastMonth}"> 

      <p:calendar id="#{cc.clientId}#{i}" value="#{csController.selectedDate}" mode="inline" 
       mindate="#{csController.minDate(2013,i)}" 
       maxdate="#{csController.maxDate(2013,i)}"/> 

    </c:forEach> 
</composite:implementation> 

Это, конечно, не работает.

Вопрос:

Как получить поддержку AJAX для всех элементов, порождаемых с: Foreach цикл?

ответ

1

На самом деле вам не нужно следовать этой процедуре, чтобы добавить функциональность ajax для ваших компонентов. Просто используйте f:ajax в свои календари. Как c:forEach работы перед ним, это не проблема:

<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:h="http://java.sun.com/jsf/html" 
    xmlns:cc="http://java.sun.com/jsf/composite" 
    xmlns:p="http://primefaces.org/ui" 
    xmlns:ui="http://java.sun.com/jsf/facelets" 
    xmlns:f="http://java.sun.com/jsf/core" 
    xmlns:c="http://java.sun.com/jsp/jstl/core"> 
<cc:interface> 
    <cc:attribute name="val" /> 
</cc:interface> 

<cc:implementation> 
    <c:forEach var="date" items="#{cc.attrs.val}"> 
     <p:calendar value="#{date}" mode="inline"> 
      <f:ajax event="dateSelect" listener="#{bean.printCurrentValues}" /> 
     </p:calendar> 
    </c:forEach> 

</cc:implementation> 
</html> 

Будучи это главная страница:

<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:f="http://java.sun.com/jsf/core" 
    xmlns:composite="http://java.sun.com/jsf/composite/composites"> 
<h:head /> 
<h:body> 
    <h:form> 
     <composite:comp val="#{bean.calendars}" /> 
    </h:form> 
</h:body> 
</html> 

Я добавил этот метод слушателя к бина, чтобы проверить текущие даты действительно меняется:

@ManagedBean 
@ViewScoped 
public class Bean { 

    public List<Date> calendars = Arrays.asList(new Date(), new Date()); 

    public List<Date> getCalendars() { 
     return calendars; 
    } 

    /** 
    * Just prints the updated values ;-) 
    */ 
    public void printCurrentValues() { 
     System.out.println("Current selected dates: " + calendars); 
    } 
} 

Для вашего конкретного случая вам нужно будет добавить список minDates и другой номер maxDates, чтобы связать их с вашим calendar Недвижимость. Кроме того, вы также можете создать свой собственный класс, который обертывает их, чтобы все было упаковано. Это ваш собственный выбор.


Решение выше будет работать для dateSelect события и предоставленного слушателя. Что делать, если мы хотим иметь разные события с разными слушателями?

Просто определите их на интерфейсе и разрешите их с помощью JSTL's c:if.Здесь у вас есть составная реализация для одного входа, который может запустить метод прослушивателя, а также динамическое число компонентов p:calendar, которое будет уведомлять пользовательский метод. По умолчанию ни один из них не запускается.

<html xmlns="http://www.w3.org/1999/xhtml" 
    xmlns:h="http://java.sun.com/jsf/html" 
    xmlns:cc="http://java.sun.com/jsf/composite" 
    xmlns:p="http://primefaces.org/ui" 
    xmlns:ui="http://java.sun.com/jsf/facelets" 
    xmlns:f="http://java.sun.com/jsf/core" 
    xmlns:c="http://java.sun.com/jsp/jstl/core"> 
<cc:interface> 
    <cc:attribute name="dateSelect" default="false" /> 
    <cc:attribute name="click" default="false" /> 
    <cc:attribute name="dateSelectListener" method-signature="void f()" /> 
    <cc:attribute name="inputClickedListener" method-signature="void f()" /> 
    <cc:attribute name="val" /> 
</cc:interface> 

<cc:implementation> 
    <h:inputText> 
     <c:if test="#{cc.attrs.click}"> 
      <f:ajax event="click" listener="#{cc.attrs.inputClickedListener}" /> 
     </c:if> 
    </h:inputText> 
    <c:forEach var="date" items="#{cc.attrs.val}"> 
     <p:calendar value="#{date}" mode="inline"> 
      <c:if test="#{cc.attrs.dateSelect}"> 
       <f:ajax event="dateSelect" listener="#{cc.attrs.dateSelectListener}" /> 
      </c:if> 
     </p:calendar> 
    </c:forEach> 
</cc:implementation> 
</html> 

И здесь главная страница:

<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:f="http://java.sun.com/jsf/core" 
    xmlns:composite="http://java.sun.com/jsf/composite/composites"> 
<h:head /> 
<h:body> 
    <h:form> 
     <composite:comp val="#{bean.calendars}" dateSelect="true" 
      dateSelectListener="#{bean.printCurrentValues}" click="true" 
      inputClickedListener="#{bean.inputClicked}" /> 
    </h:form> 
</h:body> 
</html> 

Испытано с Mojarra JSF 2.1.25 & Tomcat 7.

+0

И если мы хотим, чтобы добавить больше атрибутов в ajax, мы должны отредактировать составной компонент, например добавив 'onchange' (говорящий в общем случае, не особенно календарь). решение здесь очень специфично, я думаю, было бы неплохо создать clientBehavior «на лету». Я устал, используя тот же пример в вопросе, основная проблема заключается в том, что теги реализации (например, календари) не имеют предварительно оцененных идентификаторов, это не сработает! –

+0

@HatemAlimam, это хороший момент. Я собираюсь обновить свой ответ, я не думаю, что можно добавить ajax-поведение «на лету» на пути, который предлагает OP. Однако то, что уже кажется решением, состоит в том, чтобы иметь набор возможных событий ajax behavioured и определять, какие из них использовать и их слушатели на интерфейсе. –

+1

@ Xtreme Biker. Похоже, вы правы и добавляете ajax-поведение «на лету» в невозможно. По крайней мере, невозможно, если на основе входных атрибутов. Но ваше второе решение выглядит просто отлично. Я сделаю это так. Спасибо. – Hubert

Смежные вопросы