Предобработка / постобработка метода действия компонента из p:remoteCommand внутри составного

У меня есть следующий сценарий:

Составной компонент JSF со сложным JavaScript, который я хотел бы частично обновить с помощью JavaScript, добавив новые значения из компонента поддержки (компонент поддержки страницы, которая использует этот составной компонент, а не компонент поддержки) @FacesComponent). Я не хочу делать полное обновление, потому что это сложный плагин JavaScript, и он недопустимо сломает UX.

Я получаю значения от компонента поддержки @FacesComponent используя Primefaces's <p:remoteCommand> с обратным вызовом, как описано здесь. Лучший метод для передачи данных из компонента Java/JSF2 в компоненты Javascript/jQuery.

Я знаю, что это злоупотребление JSF, но хотел бы инкапсулировать всю функциональность в одном модуле и не связываться с JAX-RS. Если вы можете посоветовать другое хорошее решение, как инкапсулировать такой сложный плагин jQuery (для ясности мы мы говорим о FullCalendar, я знаю, что у Primefaces есть собственная реализация этого компонента, но его функциональность недостаточна для моих требований, поэтому мне нужно было создать свою собственную реализацию), которая тесно связана с обратными вызовами ajax с параметрами, с которыми вы можете поделиться Вот.

Мой вопрос, как обновить значения в компоненте поддержки @FacesComponent от поддержки бина с помощью JavaScript? В настоящее время я участвую в следующей цепочке событий:

  1. звонит из Javascript <p:remoteCommand> с параметрами, которые передаются компоненту поддержки @FacesComponent будет отправлен позже в AjaxBehaviorEvent

    JavaScript:

           refreshEvents([
                  {name:'start', value:start.format()}, 
                  {name:'end', value:end.format()}
           ]);
    

    Код JSF:

     <p:remoteCommand name="refreshValues" oncomplete="loadValues()"  action="#{cc.refreshLocal()}" process="@this"/>
    

    Параметры, которые я передал, хранятся в компоненте поддержки с помощью

    getStateHelper().put(...);
    
  2. Событие jQuery отправляется из составного компонента с помощью следующего кода JavaScript:

        var hiddenField = $(document.getElementById(variables.hiddenId));
        hiddenField.trigger("keypress");
    
  3. В переопределенном методе составного компонента public void queueEvent(FacesEvent event) Я добавляю к этому AjaxBehaviorEvent свойство, которое я сохранил ранее, на 1-м шаге и отправлю его вперед.

  4. Отправленное событие из составного компонента, "захваченного" на странице, где составной компонент вложен и выполнен process на этом компоненте:

    <p:ajax event="refreshEvent" process="@this"  listener="#{bean.refreshEvents}"/>
    

    в #{bean.refreshEvent} метод я выполняю запрос @EJB бин и загрузка данных.

  5. При обратном вызове с шага 1 снова вызывается loadValues()

    <p:remoteCommand name="loadValues" action="#{cc.getLocalData()}" oncomplete="updateValues(xhr, status, args);"/>

  6. В методе вспомогательного компонента #{cc.getLocalData()} Я добавляю параметр обратного вызова, используя:

    RequestContext.getCurrentInstance().addCallbackParam("param", ...);

  7. функция updateValues(xhr, status, args) с шага 5 войти в args значения этого параметра и выполняет актуальное обновление.

Итак, мой общий вопрос: возможно ли упростить этот процесс и как?

Спасибо.

1 ответ

Решение

Это действительно немного сложнее. Всего 3 ajax-запроса просто выполнить действие и компонент поддержки, передавая данные вперед и назад через состояние просмотра.

Ваша основная цель - объявить метод действия компонента в качестве атрибута составного компонента, который затем должен вызываться <p:remoteCommand> внутри композита и возвращают желаемый объект модели на основе переданных параметров, предпочтительно с некоторой предварительной и последующей обработкой.

Ты можешь использовать <cc:attribute method-signature> в составном интерфейсе объявить атрибут выражения метода:

<cc:interface componentType="yourComposite">
    <cc:attribute name="eventListener" method-signature="com.example.Entity method(java.lang.String, java.lang.String)" required="true" />
</cc:interface>

Который можно использовать в шаблонном клиенте, как показано ниже:

<my:composite ... eventListener="#{bean.eventListener}" />
public Entity eventListener(String start, String end) {
    // ...
    return entity;
}

Составная реализация может выглядеть так:

<cc:implementation>
    ...
    <p:remoteCommand name="refreshEvents" 
        process="@this" action="#{cc.processEventListener}"
        oncomplete="updateValues(xhr, status, args)" />
    ...
</cc:implementation>

#{cc.processEventListener} метод может получить eventListener атрибут как MethodExpression и вызовите его, как показано ниже, вместе с некоторой предварительной и последующей обработкой:

public void processEventListener() {
    String start = getRequestParameter("start");
    String end = getRequestParameter("end");
    // ...
    MethodExpression method = (MethodExpression) getAttributes().get("eventListener");
    Entity entity = (Entity) eventListener.invoke(getFacesContext().getELContext(), new Object[] { start, end });
    // ...
    addCallbackParam("param", entityAsJSON);
}

Теперь это всего лишь 1 AJAX-запрос "как обычно".

Другие вопросы по тегам