JSF 2.0: задержка рендеринга (композитного) содержимого компонента до тех пор, пока AJAX-вызов не выполнит его повторную визуализацию.

Моя цель — динамически загружать содержимое компонента в JSF 2.0. Вариант использования таков: пользователь нажимает какую-то кнопку, которая открывает модальную панель с некоторым тяжелым содержимым через AJAX. Из-за его тяжести я хочу отложить загрузку до тех пор, пока/если это действительно понадобится пользователю. Если пользователь закрывает эту панель, она фактически не удаляется из DOM, а просто исчезает. Если пользователь снова нажимает кнопку инициализации, отображается ранее загруженная панель.

Я знаю, что могу предотвратить рендеринг содержимого с помощью rendered="#{cc.attrs.visibilityState == 'hidden'}" и что я могу повторно рендерить компонент с помощью вызова JSF AJAX. Однако как я могу настроить атрибуты составного компонента на лету, чтобы во второй раз компонент действительно визуализировался?

1) Я знаю, что я мог бы сделать:

<h:outputLink>Foo
    <f:ajax event="click" render="theComponentIWantToUpdate" listener="#{someBean.someMethod()}" />
</h:outputLink>

А затем программно настроить атрибуты theComponentIWantToUpdate (чтобы изменить значение #{cc.attrs.visibilityState}), чтобы он действительно отображался с полным содержимым. Но как это сделать на самом деле?

2) Также проблема в том, что я не хочу обновлять (перерендерить) theComponentIWantToUpdate при каждом нажатии кнопки, только первый раз (см. бизнес-кейс). Как я могу установить оценку для <f:ajax /> вызова для этого? У него есть атрибут disabled, но он только указывает, действительно ли отображать AJAX-обработчик (не оценивается каждый раз при нажатии на ссылку).

3) Кроме того, я, вероятно, хочу сначала сделать какой-то собственный javascript при нажатии на ссылку и выполнить только запрос AJAX через javascript, используя jsf.ajax.request(). Однако эта функция не поддерживает предоставление атрибута listener, поэтому я не знаю, как выполнить метод резервного компонента с необработанным вызовом javascript jsf.ajax.request()? На самом деле есть аналогичный вопрос без подходящих ответов (см. only-rerender-an-area-of-page">JSF 2.0 AJAX: jsf.ajax.request для вызова метода не только для повторного рендеринга области страницы).


person Tuukka Mustonen    schedule 18.08.2010    source источник
comment
Хорошо, я выбираю собственное частичное решение как принятое на данный момент. Если у кого-то есть лучшие предложения, я с удовольствием изменю этот выбор :)   -  person Tuukka Mustonen    schedule 28.09.2010


Ответы (1)


Частичное решение:

Вот моя ссылка, которая отправляет AJAX-запрос (внутри составного компонента):

<h:form>
    <h:outputLink styleClass="modlet-icon">
        <f:ajax event="click" render=":#{cc.clientId}:modalWindow:root" listener="#{modalWindowBean.enableContentRendering(cc.clientId, 'modalWindow')}" />
    </h:outputLink>
</h:form>

Слушатель вызывает этот метод:

public class ModalWindowBean {
    ...

    public void enableContentRendering(String clientId, String windowId) {
        UIComponent component = FacesContext.getCurrentInstance().getViewRoot().findComponent(clientId + ":" + windowId);
        component.getAttributes().put("contentRenderingEnabled", true);
    }
}

Вот моя цель для рендеринга:

<modalWindow:modalWindow id="modalWindow">
    <quickMenu:quickMenuOverlay id="quickMenuOverlay" />
</modalWindow:modalWindow>

ModalWindow просто оборачивает цель в красиво выглядящую оконную панель. В модальном окне:

<composite:implementation>
    <h:outputScript library="component/modalWindow" name="modalWindow.js" target="head" />
    <h:outputStylesheet library="component/modalWindow" name="ModalWindow.css" />

    <h:panelGroup id="root" layout="block" styleClass="modalWindow hide">
        <ui:fragment rendered="#{cc.attrs.contentRenderingEnabled}">
            ...all the wrapping elements with <composite:insertChildren /> within it
            <script type="text/javascript">
                // Fade it in
                var win = ModalWindow.getInstance('#{cc.clientId}');  // this gets the instance, available everywhere
                win.position(#{cc.attrs.left}, #{cc.attrs.top});
                win.resize(#{cc.attrs.width}, #{cc.attrs.height});
                win.fadeIn();
            </script>
        </ui:fragment>
    </h:panelGroup>

    <ui:fragment rendered="#{!cc.attrs.contentRenderingEnabled}">
        <script type="text/javascript">
            // Initialize modalWindow when it is rendered for the first time
            var win = new ModalWindow('#{cc.clientId}');  // will be publicly available through ModalWindow static methods
        </script>
    </ui:fragment>

</composite:implementation>

Проблема? AJAX-запрос отправляется каждый раз, когда пользователь нажимает кнопку (поэтому окно каждый раз перезагружается и исчезает). Мне нужно иметь возможность контролировать, когда/если действительно отправляется AJAX-запрос.

Все это заставляет меня скучать по Apache Wicket, хотя я все равно не уверен, как бы я поступил с ним :)

person Tuukka Mustonen    schedule 19.08.2010