ui: включать в зависимости от viewParam

У меня есть страница, на которую я хочу включить часть страницы (в данном случае нижний колонтитул) в зависимости от значений, заданных параметром представления.

У меня инициализируется мой вспомогательный компонент ViewScoped на preRenderView

<f:metadata>
    <f:viewParam name="racecode" value="#{displayResults.racecode}" />
    <f:event type="preRenderView" listener="#{displayResults.init}" />  
</f:metadata>

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

<h:panelGroup id="customFooter" display="block">
    <ui:include src="#{displayResults.customFooter}" />
</h:panelGroup>

Это всегда дает мне недостающую страницу. Но если я ввожу имя страницы вручную, оно работает. То же самое, если я заменю ui:include на h:outputText.

Я понимаю, что это как-то связано с фазами JSF и что на момент выполнения ui:include значение еще не установлено. (Чтение и лучшее понимание фаз входит в мой список TODO).

Вопрос остается. Как я могу сделать что-то в этом роде. Использовать bean-компонент viewParam, запрашивать базу данных и использовать это значение в ui:include?


person blo0p3r    schedule 04.10.2012    source источник


Ответы (2)


@wemu уже объяснил причину. <ui:include src> оценивается до вызова метода init(). Однако предложенное им <f:phaseListener> решение неуклюже.

Просто используйте @ManagedProperty/@PostConstruct для bean-компонента @RequestScoped.

@ManagedProperty("#{param.racecode}")
private String racecode;

@PostConstruct
public void init() {
    // ...
}
person BalusC    schedule 04.10.2012
comment
Это имеет смысл. Я часто беспокоюсь о лучших практиках и подобных вещах (я думаю, немного обсессивно-компульсивное расстройство). Теперь предположим, что я загружаю два bean-компонента для этой загрузки одной страницы, и это создает дополнительный вызов базы данных. Конечно, у меня есть информация, необходимая для этой работы. Не лучше ли полностью изменить мой текущий preRenderView на этот и разместить все в одном месте? Кроме того, почему @RequestScoped здесь? - person blo0p3r; 04.10.2012
comment
Вы можете внедрять bean-компоненты друг в друга с помощью @ManagedProperty. @RequestScoped является обязательным по двум причинам: 1) #{param} относится к области запроса 2) <ui:include> является обработчик тегов. Так что @ViewScope абсолютно не вариант. - person BalusC; 04.10.2012
comment
Это сработало для того, что я хотел сделать. Но, кажется, перешел к другому вопросу. У меня есть область запроса и область просмотра на одной странице. Когда я запускаю actionListener на своей странице, который должен запускать метод в моем bean-компоненте viewScope, он вызывает только bean-компонент области запроса и никогда не переходит к рассматриваемому методу. - person blo0p3r; 04.10.2012
comment
Действительно, существуют проблемы с использованием форм в сочетании с динамическими включениями. См. этот вопрос + ответ для более подробной информации: stackoverflow .com/questions/11408130/ - person BalusC; 05.10.2012
comment
Аналогичная проблема, но решение не помогло. Теперь у меня тот же displayResults установлен на viewScoped, а новый customResults установлен на requestScoped. Этот customResults получает информацию о моих включениях и работает нормально. Но когда я щелкаю прослушиватель на странице, все, что он делает, это вызывает конструктор для customResults, а не метод displayResults, вызываемый действием. - person blo0p3r; 05.10.2012

Слушатели PreRenderView вызываются в RenderResponsePhase до того, как компоненты будут визуализированы, НО ПОСЛЕ вызова TagHandlers. Это означает, что обработчики тегов НЕ увидят данные, инициализированные в событии PreRenderView.

Если вы используете <ui:include value="#{myBean.myViewId}" /> для динамического переключения включения, вы не можете использовать прослушиватель событий PreRenderView для установки свойства myViewId для myBean.

Если вам нужно сделать это, используйте файл <f:phaseListener>.

person wemu    schedule 04.10.2012
comment
Я понимаю, что вы говорите. Но, насколько я понимаю и согласно этой ссылке, мне нужно пройти preRenderView поскольку myViewId зависит от viewParam --› так что мне все еще нужно дождаться фазы обновления значений модели? - person blo0p3r; 04.10.2012
comment
да, я бы тоже так подумал, но чтобы поверить в это самому, мне нужно попробовать (такие вещи меня смущают). - person wemu; 04.10.2012