JSF 2.0: визуализация полей формы с исходными данными с использованием bean-объектов в области запроса (для обновления данных сервера, относящихся к текущему компоненту) - PullRequest
0 голосов
/ 28 сентября 2010

Довольно нормальный случай:

У нас есть составной компонент 'портлет', который имеет два состояния: развернуто и свернуто. Портлеты начинаются как развернутые, но пользователь может свернуть их, нажав на них. Это состояние должно быть сохранено в сеансе, чтобы после обновления страницы пользователем или перехода на новую портлеты запоминали, развернуты ли они / свернуты.

В этом суть проблемы : Как бы вы реализовали такое сохранение состояния в компоненте, который можно вставлять на страницу несколько раз?

Некоторые предпосылки / идеи:

Реализация сохранения состояния для одного портлета может быть легко достигнута с помощью bean-объекта в области сеанса. Также можно поддерживать фиксированное количество портлетов, создавая фиксированное количество bean-объектов в сессионной области или объявляя разные свойства в один bean-компонент. Однако я не хочу даже упоминать, почему эти подходы плохие.

Моя первоначальная идея для этого состояла в том, чтобы создать Map (или некоторую структуру объекта) под одним сессионным компонентом для хранения состояний для всех портлетов. Однако я не могу напрямую ссылаться на эти данные из JSF (чтобы JSF также обновил их). Я подумал о том, чтобы написать конкретный метод получения / установки для извлечения / обновления правильного значения на карте, но это невозможно, поскольку во время выполнения методов получения и установки нет идентифицирующих данных.

Однако, вероятно, ясно, что мне нужно сохранять состояния в сессионный компонент. Я могу довольно легко сохранить состояние, отправив форму с f:ajax и выполнив специальный метод с использованием listener и отправленных данных. Чтобы поддерживать несколько экземпляров компонента, я мог бы использовать (несколько экземпляров) bean-объект в области запросов для обработки каждого раскрытия / свертывания. Однако для фактической публикации данных, идентифицирующих портлет и его состояние, мне нужно сначала вставить их в поля формы во время рендеринга.

Итак, как на самом деле предоставить каждому портлету правильные данные во время рендеринга (на самом деле просто укажите логическое / enum в этом случае, но рассмотрите случай, когда нужно обрабатывать больше данных)?

Кажется, что:

  • h:inputHidden и h:inputText не поддерживают установку начального значения, кроме атрибута value (который будет указывать на #{portletBean.portletState}).
  • Я не могу автоматически загружать бины запроса с правильными начальными значениями во время их создания, так как нет никакой идентифицирующей информации.

Еще раз мне кажется, что я что-то упускаю ... указатели?

Я полагаю, что по крайней мере один из ответов будет использовать UIComponent, а не составные компоненты, но я хотел бы сохранить это как составной компонент, так как он содержит много необработанных HTML-элементов.

Обновление:

  • Существует довольно похожий вопрос с предложением использовать bean-объект в области видимости. Однако я не думаю, что это жизнеспособно.

Ответы [ 3 ]

0 голосов
/ 28 сентября 2010

Вы можете сделать это, используя taglibs, вы можете передать параметры в теги:

Добавьте в свой taglib следующее:

<tag>
    <tag-name>date</tag-name>
    <source>components/date.xhtml</source>
</tag>

Тогда вот содержимое компонентов / date.xhtml

<ui:composition name="date_template">
    <h:panelGrid id="#{id}Panel" columns="1" border="0" cellpadding="0" cellspacing="0">
        <rich:calendar immediate="true" id="#{id}" popup="true" datePattern="dd.MM.yyyy"
                        enableManualInput="true" showApplyButton="true" cellWidth="12px" cellHeight="11px" style="width:100px"
                        value="#{dateForm.date}" required="#{required}" readonly="#{readonly}" validator="#{dateForm.validateDate}">
            <a4j:support event="onchanged" reRender="#{id}Panel,#{reRenderDate}"/>
            <ui:insert />
        </rich:calendar>

        <rich:message for="#{id}" errorClass="error" />
    </h:panelGrid>
</ui:composition>

И затем вы используете это как:

<adse:date id="dateTransfert" required="true"
           dateForm="#{dossierBean.dateTransfert}"
           readonly="false" reRenderDate="montantAncien,montantNouveau,montantEmolument">
     <a4j:support event="oninputblur" reRender="dateTransfertPanel,montantAncien,montantNouveau,montantEmolument"/>
</adse:date>

В этом случае передается dateForm, это объект, и в taglib мы используем свойства этого объекта (dateForm.date). Также обратите внимание на , который можно использовать для включения других элементов в XHTML.

Таким образом, вы можете передать контекст для каждого портлета. Вы могли бы даже сделать этот стандарт, имея portletBean как суперкласс, который определяет метод getPortletState ().

0 голосов
/ 28 сентября 2010

Я использовал ранее решенный хак для вызова метода бина из JS :

Создала пустую невидимую форму с h:commandButton и f:ajax внутри нее, вызвав listener.

Создана отдельная кнопка для запуска события развернуть / свернуть.С этой кнопки инициируйте метод javascript, который оживляет развертывание / свертывание и одновременно нажимает скрытую кнопку внутри формы.Все необходимые данные отправляются с использованием атрибута listener.Слушатель нацелен на сессионный компонент, который проверяет / обновляет карту состояний, идентифицированных идентификаторами клиента компонента.

Это довольно просто, удивительно, почему я не понял этого раньше ...

Тем не менее, он все еще далек от совершенства и не дает ответа на вопрос, каким образом bean-объекты в области запроса могут быть инициированы со значениями по умолчанию, чтобы использовать их в качестве формы хранения / транспортировки.

0 голосов
/ 28 сентября 2010

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

Используйте javascript для установки полей формы с правильными данными сразу после рендеринга:

window.addEvent('domready', function() {
    var portletState = '#{portletBean.getPortletState(cc.attrs.clientId)}';
    // find the field and set the data...
});

Чувствует себя очень счастливым.Я не хочу идти по этому маршруту.

Используйте карту атрибутов компонента для хранения данных:

<cc:interface>
    <cc:attribute name="portletState" default="#{portletBean.getPortletState(cc.attrs.clientId)}" />
</cc:interface>

Доступ к этому из кода:

public void stateChangedCallback(String clientId) {
    UIComponent component = FacesContext.getCurrentInstance().getViewRoot().findComponent(clientId);
    String state = (String) component.getAttributes().get("portletState");
}

Также не чувствует себя хорошо.Также я не уверен, работает ли он (можно ли использовать EL в атрибуте default).

Использовать карту атрибутов компонента для хранения данных, предоставляя их при вызове компонента:

<portlet:portlet id="specificPortlet">
    <f:attribute name="portletState" value="#{portletBean.getPortletState(component.clientId)}" />
</portlet:portlet>

Опять очень неуклюже и дублирует ваш код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...