Рекомендации JSF: пользовательские компоненты и JavaScript

Я разрабатываю пользовательский компонент JSF, используя информацию, которую нашел в следующей книге Pro JSF и HTML5 от Apress. .

На данный момент я успешно разработал:

  • класс java для получения данных, которые будут отображаться в компоненте
  • класс компонента Java
  • класс рендерера java
  • файл taglib
  • пример страницы для отображения taglib

Все работает нормально, компонент успешно отрисовывается.

Теперь я хочу добавить события и поведение javascript к визуализируемым элементам, более конкретно, целью моего пользовательского компонента является отображение меню на веб-странице, и я хотел бы добавить эффекты раскрывающегося списка к входу в меню. Я знаю, как все это закодировать на JavaScript, чего я не знаю:

Как лучше всего добавлять события и поведение JavaScript к элементу, отображаемому в пользовательском компоненте?

Где должны быть размещены файлы JS? Как привязать события к элементам? Это делается в классе рендеринга или после, на веб-страницах?

Спасибо, я готов предоставить более конкретную информацию о моем коде, если это необходимо.


Класс компонента Java

Примечание. Класс CosmoMenu — это просто bean-компонент. По сути, он хранит дерево меню (ярлык, идентификатор и набор дочерних элементов, если они есть).

package components;

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import domain.CosmoMenu;
import javax.faces.component.FacesComponent;
import javax.faces.component.UIComponentBase;


@FacesComponent(CosmoMenuComponent.COMPONENT_TYPE)
public class CosmoMenuComponent extends UIComponentBase{

  /** Component family of {@link CosmoMenuComponent}.        */
  public static final String COMPONENT_FAMILY = "CosmoMenu";

  /** Component type of {@link CosmoMenuComponent}.          */ 
  public static final String COMPONENT_TYPE = "CosmoMenu";    

  @Override
  public String getFamily(){
      return CosmoMenuComponent.COMPONENT_FAMILY;
  }


  private CosmoMenu theMenu;    

  public CosmoMenu getMenu(){

      Gson gson = new Gson();
      JsonParser jsonParser = new JsonParser();
      CosmoMenuAPI myApi = new CosmoMenuAPI();

      String strMenu = myApi.getMenu();
      JsonElement jEl = jsonParser.parse(strMenu);

      theMenu = gson.fromJson(jEl, CosmoMenu.class);
      return theMenu;      
  }
}

person INElutTabile    schedule 01.07.2014    source источник
comment
Не могли бы вы опубликовать свой компонент, пожалуйста? :) Просто нужно понять, как создать пример.   -  person Josef E.    schedule 01.07.2014
comment
Дайте мне знать, если вам нужен рендерер или что-то еще.   -  person INElutTabile    schedule 01.07.2014


Ответы (2)


Если вы хотите, чтобы ваши компоненты можно было использовать повторно, я рекомендую вам упаковать все в отдельную банку. При использовании Servlet 3.0 вы сможете легко получить доступ к веб-ресурсам, поместив их в META-INF/resources. Предоставьте jar файл faces-config.xml, и вы сделаете его доступным для сканирования аннотации JSF:

components
    \-(Your cource code)
META-INF 
    \-faces-config.xml
    \-resources (This ends up in docroot)
        \-resources
            \-js (Here they go your js files)
            \-comp (Here your composite components)
            \-css (Here your css)

Позже вам придется позаботиться о том, чтобы не использовать определенные идентификаторы в ваших композитах, поскольку JSF изменяет их при рендеринге. Лучше всего передать ссылку на текущий компонент вашим функциям JS:

<h:inputText styleClass="myInputStyle" onclick="showInputText(this)" />

Просто обратитесь к включенным стилям CSS и функциям JS.

И последнее, но не менее важное: будьте осторожны при включении jar в качестве веб-ресурса, если пути к файлам по-прежнему конфликтуют с путями в вашем веб-приложении, они не будут включены.

См. также:

person Xtreme Biker    schedule 01.07.2014
comment
@Biker Я работаю с пользовательскими компонентами, а не с составными компонентами, я думаю, мне не следует создавать каталог comp, верно? О событиях JS: рендеринг HTML выполняется классом java, а не страницей xhtml (как в Composite Components), обычно (или хорошо сделано) привязывать событие JS к элементу в классе рендерера java , который обрабатывается функцией в файле JS? - person INElutTabile; 01.07.2014
comment
@INElutTabile, этот макет позволяет вам решить, как вы хотите реализовать свои компоненты. Составные компоненты просто добавляют уровень представления xhtml для своего объявления, поэтому, если вы хотите работать только с кодом Java, вы можете это сделать, поскольку все достижимое с композитами можно сделать и с пользовательскими компонентами. Я предполагаю, что вы играете с фреймворком, поскольку использование пользовательских компонентов для такого поведения было бы для меня излишним, тем более, когда доступен JSF 2.x. Вот несколько связанных ссылок: bit.ly/1lP5mKs bit.ly/VCPIIx - person Xtreme Biker; 01.07.2014
comment
@Biker Спасибо за помощь! Я хотел бы, чтобы вы добавили к своему ответу еще одну важную (ИМХО) деталь, если можете. Я знаю, что каждый ресурс JS, который мне нужен, должен быть включен на мою страницу, чтобы его можно было использовать. Я использую класс рендеринга Java, я думаю, я должен включить ресурс js в такой класс, чтобы использовать его. Правильно? Правильно ли выполнять запись в классе рендерера, включая мой ресурс js, например «responseWriter.write(‹script src ....);». - person INElutTabile; 02.07.2014
comment
@Biker Чтобы ответить на ваш последний вопрос, я использую пользовательский компонент, так как имею дело с динамическим меню, которое может иметь глубину n уровней, поэтому мне нужен рекурсивный рендеринг элементов. Я предполагаю, что правильным выбором было использование java-рендерера :) - person INElutTabile; 02.07.2014
comment
@INElutTabile, пожалуйста ;-) У меня мало опыта работы с пользовательскими рендерерами, в основном мне никогда не приходилось реализовывать их самостоятельно. Но да, я думаю, что вы правы с responseWriter. Что касается вашего утверждения, связанного с динамическим меню, нет необходимости делать это с помощью пользовательского рендерера + без граней. Это перебор. Используйте композиты, они также могут поддерживаться пользовательским компонентом и могут иметь связанный фаслет (представление). Вы можете реализовать то, что хотите, просто имея структуру для своего меню в компоненте и перебирая ее с помощью ui:repeat в своем представлении. - person Xtreme Biker; 02.07.2014
comment
Кстати, то, что вы хотите сделать, уже реализовано. Хотите ли вы делать своими руками или нет, это другая история ;-) - person Xtreme Biker; 02.07.2014

Вы можете включить в фаслеты, использующие ваш компонент, внешний файл javascript, добавив следующий код:

    <script src="#{request.contextPath}/jspath/yourjs.js"></script>

В компоненте, когда вы генерируете вывод XHTML, укажите идентификатор для ваших пунктов меню, например.

    <h:outputText id="myid" value="#{bean.value}"/>

и в вашем js.js

    $(document).ready(function() {

    $("#myid").click(function(){
    // dostuff
    });
    });
person Community    schedule 01.07.2014