JSF 2.0:Отображение полей формы с исходными данными с использованием bean-компонентов области запроса (для обновления данных сервера, специфичных для текущего компонента).

StackOverflow https://stackoverflow.com/questions/3812685

Вопрос

Вполне нормальный случай:

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

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

Немного предыстории/идей:

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

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

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

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

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

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

И снова такое ощущение, что я что-то упускаю...указатели?

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

Обновлять:

  • Eсть довольно похожий вопрос, с предложением использовать bean-компонент с областью просмотра.Однако я не думаю, что здесь это целесообразно.
Это было полезно?

Решение 3

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

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

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

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

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

Другие советы

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

Используйте 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 в атрибуте по умолчанию).

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

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

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

Сделать это можно с помощью taglibs, в теги можно передавать параметры:

Добавьте в вашу библиотеку тегов следующее:

<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, это объект, и в библиотеке тегов мы используем свойства этого объекта (dateForm.date).Также обратите внимание на <ui:insert />, который можно использовать для включения других элементов в XHTML.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top