JSF: ui:include и (сломанная) область представления

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

mainview.xhtml 
     --backed by--> mainViewBean (request scope) 
       --with managed property--> mainViewView (view scope)

include1.xhtml
     --backed by--> include1Bean (request scope)
       --with managed property--> mainViewBean

include2.xhtml
     --backed by--> include2Bean (request scope)
       --with managed property--> mainViewBean

include3.xhtml
     --backed by (and with component bindings to)--> include3Bean (request scope)
       --with managed property--> mainViewBean

include4.xhtml
     --backed by--> mainViewBean

На главной странице просмотра каждое включение включается через серию условно отображаемых групп h:panelGroups, как описано BalusC в этих вопросах:

https://stackoverflow.com/a/9897016/945403

https://stackoverflow.com/a/7113961/945403

Компонент представления содержит некоторую различную информацию о представлении, касающуюся текущего состояния действий пользователя, какие элементы он просматривает в данный момент и так далее.

Каждое из включенных представлений выполняет различные задачи с помощью сообщений как ajax, так и не ajax. Моя проблема в том, что определенные действия на определенных панелях, по-видимому, приводят к разрушению области просмотра, и, похоже, в этом нет рифмы или причины. Я заранее извиняюсь за запутанный рабочий процесс, описанный ниже, но я постараюсь быть настолько ясным, насколько смогу.

Если я выполняю действия ajax в include3.xhtml, они отображают компоненты только внутри включения, и я могу выполнять их в течение всего дня, а область просмотра остается. Если я выполняю сообщения без ajax, обновление обновит (и, возможно, добавит ранее не отображаемый) include4.xhtml. Затем я могу впоследствии выполнить действие в любом из других включений.

Если я выполняю действие ajax в include1.xhtml, которое вызывает методы только в своем собственном вспомогательном компоненте и обновляет только свои собственные компоненты, область представления остается. Если я выполняю действие ajax, которое вызывает метод в include3Bean и обновляет div, содержащий include2.xhtml и include3.xhtml, область просмотра остается, и пока я продолжаю выполнять действия в include1.xhtml, область просмотра останется. Как только я пытаюсь выполнить другое действие в одном из других включений, область представления уничтожается.

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

include2.xhtml имеет действие ajax, которое при запуске вызывает метод в mainViewBacking и обновляет div, содержащий include2.xhtml и include3.xhtml. Если я продолжу выполнять это действие или предприму любое другое действие в include2.xhtml (включая действия, отличные от ajax), все будет работать так, как ожидалось, и область просмотра останется. Однако, если я впоследствии выполню действие в include3.xhtml, область представления будет уничтожена. Что становится странным, так это то, что я могу выполнять действия в include1.xhtml, и они будут по-прежнему иметь доступ к области представления столько, сколько я захочу, но если я попытаюсь вернуться и выполнить действие в include2.xhtml или include3.xhtml область просмотра снова теряется.

Я немного застрял на этом этапе, и я даже не уверен, как понять, что не так. Я предполагаю, что что-то об обновлении (и удалении или добавлении) включений приводит к потере области представления, но из ранее связанных вопросов кажется, что это не должно быть проблемой, поскольку фактические значения src для пользовательского интерфейса :includes не генерируются динамически. И у меня отключено частичное сохранение состояния для mainview.xhtml.

Есть ли что-то в этих динамически отображаемых ui:includes, что нарушает область просмотра?


person moneyt    schedule 13.09.2012    source источник
comment
2 вопроса: Какую версию мохарры вы используете? Привязываете ли вы какие-либо компоненты ввода к поддерживающему bean-компоненту viewscoped? См. ошибку mojarra, касающуюся привязки компонентов. Также убедитесь, что вы не выполняете перенаправление на страницу, которая также ссылается на тот же bean-компонент с областью просмотра.   -  person kolossus    schedule 14.09.2012
comment
@kolossus Использование Моржарры 2.1.3. include3.xhtml имеет некоторые компоненты, привязанные к include3Bean области запроса (который благодаря связыванию управляемого свойства имеет доступ к bean-компоненту с областью видимости), но, насколько я понимаю, до тех пор, пока привязки не были в фактическом bean-компоненте с областью видимости, и что я если PATIAL_STATE_SAVING отключен для этого представления, все должно быть в порядке. Кроме того, никаких перенаправлений не происходит, все действия являются недействительными.   -  person moneyt    schedule 14.09.2012


Ответы (1)


Редактировать 2014-02-28:

Глядя на последнюю демонстрацию omnifaces, я заметил, что BalusC реализовал скрипт, который должен решить ту же проблему и, вероятно, сделать это гораздо лучше, чем мой код ниже.

http://showcase.omnifaces.org/scripts/FixViewState

Оригинальный ответ:

Оказывается, это была ошибка в JSF, описанная BalusC здесь: ">http://balusc.blogspot.com/2011/09/communication-in-jsf-20.html#AjaxRenderingOfContentWhichContainsAnotherForm

К сожалению, его решение по какой-то причине не работало последовательно для меня. В результате я написал свой собственный (немного более раздражающий) обходной путь, который я предоставлю здесь другим, если они в этом нуждаются.

Я добавил следующий javascript на страницу mainview.xhtml:

var lastForm = null;

        function getViewStateFromLastForm(callingElement){

            var currentForm = $(callingElement).closest("form");
            var formId = currentForm.attr("id");

            if(lastForm != null ){
                var viewState = $("#" + lastForm).children("[name='javax.faces.ViewState']").val();
                currentForm.children("[name='javax.faces.ViewState']").remove();

                $('<input/>').attr({
                    type: 'hidden',
                    id: 'javax.faces.ViewState',
                    name: 'javax.faces.ViewState',
                    autocomplete: 'off',
                    value: viewState
                }).appendTo(currentForm);
            }
            lastForm = formId;

        }

Затем каждая кнопка на различных включенных страницах, которые отправляются на сервер, имеют вызов getViewStateFromLastForm(this); в своих атрибутах onclick.

person moneyt    schedule 20.09.2012