Понимание процессов / обновлений PrimeFaces и атрибутов JSF f: ajax execute / render

195

Что именно есть processи updateв p:commandXxxкомпонентах PrimeFaces, executeи renderв f:ajaxтеге?

Что работает во время проверки? Что делает updateатрибут, а не обновляет значение для компонента из серверной части? Есть ли processзначение привязки атрибута к модели? Что же делать @this, @parent, @allи @formв обоих атрибутов?

Пример ниже работает нормально, но я немного запутался в основных понятиях.

<p:commandButton process="@parent"
                 update="@form"
                 action="#{bean.submit}" 
                 value="Submit" />
Shardendu
источник

Ответы:

308

<p:commandXxx process> <p:ajax process> <f:ajax execute>

processАтрибут на стороне сервера и может повлиять только UIComponentS , реализующие EditableValueHolder(поля ввода) или ActionSource(командные поля). processАтрибут сообщает JSF, используя разделенный пробелами список идентификаторов клиентов, какие компоненты точно должны быть обработаны в течение всего жизненного цикла JSF после (частичного) отправки формы.

Затем JSF будет применять значения запроса (находя параметр запроса HTTP на основе собственного идентификатора клиента компонента, а затем либо устанавливая его как переданное значение в случае EditableValueHolderкомпонентов, либо помещая в очередь новое значение ActionEventв случае ActionSourceкомпонентов), выполнит преобразование, проверку и обновление значений модели ( EditableValueHolderтолько компоненты) и, наконец, вызвать в очередь ActionEvent( ActionSourceтолько компоненты). JSF пропустит обработку всех других компонентов, которые не покрыты processатрибутом. Кроме того, компоненты, renderedатрибут которых оценивается на falseэтапе применения значений запроса, также будут пропущены как часть защиты от несанкционированных запросов.

Обратите внимание, что в случае ActionSourceкомпонентов (таких как <p:commandButton>) очень важно, чтобы вы также включили сам компонент в processатрибут, особенно если вы намереваетесь вызвать действие, связанное с компонентом. Таким образом, приведенный ниже пример, предназначенный для обработки только определенного входного компонента (компонентов) при вызове определенного компонента команды, работать не будет:

<p:inputText id="foo" value="#{bean.foo}" />
<p:commandButton process="foo" action="#{bean.action}" />

Это процесс будет только #{bean.foo}и не#{bean.action} . Вам также необходимо включить сам компонент команды:

<p:inputText id="foo" value="#{bean.foo}" />
<p:commandButton process="@this foo" action="#{bean.action}" />

Или, как вы, по-видимому, выяснили, используя @parentединственные компоненты, имеющие общего родителя:

<p:panel><!-- Type doesn't matter, as long as it's a common parent. -->
    <p:inputText id="foo" value="#{bean.foo}" />
    <p:commandButton process="@parent" action="#{bean.action}" />
</p:panel>

Или, если оба они являются единственными компонентами родительского UIFormкомпонента, вы также можете использовать @form:

<h:form>
    <p:inputText id="foo" value="#{bean.foo}" />
    <p:commandButton process="@form" action="#{bean.action}" />
</h:form>

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

Тогда есть @all. Это не имеет никакого специального эффекта в processатрибуте, но только в updateатрибуте. А process="@all"ведет себя точно так же, как process="@form". HTML не поддерживает отправку нескольких форм одновременно.

Между прочим, есть еще один, @noneкоторый может быть полезен в случае, если вам абсолютно не нужно ничего обрабатывать, а нужно только обновить некоторые конкретные части update, особенно те разделы, содержимое которых не зависит от представленных значений или слушателей действий.

Следует отметить, что processатрибут не влияет на полезную нагрузку HTTP-запроса (количество параметров запроса). Это означает, что поведение HTML по умолчанию при отправке «всего», содержащегося в представлении HTML, <h:form>не будет затронуто. Если у вас большая форма и вы хотите уменьшить полезную нагрузку HTTP-запроса только до этих абсолютно необходимых при обработке, то есть только тех, которые покрыты processатрибутом, то вы можете установить partialSubmitатрибут в компонентах Ajax PrimeFaces как в <p:commandXxx ... partialSubmit="true">или <p:ajax ... partialSubmit="true">. Вы также можете настроить это «глобально», отредактировав web.xmlи добавив

<context-param>
    <param-name>primefaces.SUBMIT</param-name>
    <param-value>partial</param-value>
</context-param>

Кроме того, вы также можете использовать <o:form>OmniFaces 3.0+, который по умолчанию это поведение.

Стандартный JSF - эквивалентно PrimeFaces конкретное processсоставляет executeот<f:ajax execute> . Он ведет себя точно так же, за исключением того, что он не поддерживает строку, разделенную запятыми, в отличие от строки PrimeFaces (хотя я лично рекомендую придерживаться соглашения, разделенного пробелами), а также @parentключевое слово. Также может быть полезно знать, что по <p:commandXxx process>умолчанию используется @formwhile, <p:ajax process>а по <f:ajax execute>умолчанию - @this. Наконец, также полезно знать, что processподдерживает так называемые «селекторы PrimeFaces», см. Также Как работают селекторы PrimeFaces, как в update = "@ (. MyClass)"?


<p:commandXxx update> <p:ajax update> <f:ajax render>

updateАтрибут на стороне клиента и может повлиять на HTML представление всех UIComponentс. updateАтрибут сообщает JavaScript (один отвечает за обработку Ajax запрос / ответ), используя разделенный пробелами список идентификаторов клиентов, которые в части необходимости дерева HTML DOM будет обновляться по мере ответа на форме представить.

JSF подготовит для этого правильный ответ ajax, содержащий только запрашиваемые части для обновления. JSF пропустит все остальные компоненты, которые не охвачены updateатрибутом в ответе ajax, тем самым сохраняя полезную нагрузку ответа малой. Кроме того, компоненты, renderedатрибут которых оценивается во falseвремя фазы ответа рендеринга, будут пропущены. Обратите внимание, что даже если он вернется true, JavaScript не сможет обновить его в дереве HTML DOM, если оно было изначально false. Вы должны были бы обернуть это или обновить его родителя вместо этого. См. Также Обновление / рендеринг Ajax не работает с компонентом, который имеет атрибут рендеринга .

Обычно вы хотите обновить только те компоненты, которые действительно необходимо « обновить » на стороне клиента при (частичной) отправке формы. Пример ниже обновляет всю родительскую форму через @form:

<h:form>
    <p:inputText id="foo" value="#{bean.foo}" required="true" />
    <p:message id="foo_m" for="foo" />
    <p:inputText id="bar" value="#{bean.bar}" required="true" />
    <p:message id="bar_m" for="bar" />
    <p:commandButton action="#{bean.action}" update="@form" />
</h:form>

(обратите внимание, что processатрибут пропущен, поскольку по умолчанию он @formуже установлен)

Хотя это может работать нормально, обновление компонентов ввода и команд в этом конкретном примере не требуется. Если вы не измените значения моделиfoo и метод barinside action(что, в свою очередь, не будет интуитивно понятным в перспективе UX), нет смысла их обновлять. Компоненты сообщения - единственные, которые действительно должны быть обновлены:

<h:form>
    <p:inputText id="foo" value="#{bean.foo}" required="true" />
    <p:message id="foo_m" for="foo" />
    <p:inputText id="bar" value="#{bean.bar}" required="true" />
    <p:message id="bar_m" for="bar" />
    <p:commandButton action="#{bean.action}" update="foo_m bar_m" />
</h:form>

Однако это становится утомительным, когда у вас их много. Это одна из причин существования селекторов PrimeFaces. Эти компоненты сообщений имеют в сгенерированном HTML-выводе общий класс стилей ui-message, поэтому следует также выполнить следующее:

<h:form>
    <p:inputText id="foo" value="#{bean.foo}" required="true" />
    <p:message id="foo_m" for="foo" />
    <p:inputText id="bar" value="#{bean.bar}" required="true" />
    <p:message id="bar_m" for="bar" />
    <p:commandButton action="#{bean.action}" update="@(.ui-message)" />
</h:form>

(обратите внимание, что вы должны хранить идентификаторы на компонентах сообщений, в противном случае @(...) они не будут работать! Опять же, см. подробнее, как работают селекторы PrimeFaces, как в update = "@ (. myClass)"? )

@parentОбновляет только родительский компонент, который , таким образом , охватывает текущий компонент и все братья и сестры и их дети. Это более полезно, если вы разделили форму на вменяемые группы со своими обязанностями. В @thisобновлениях, очевидно, только текущий компонент. Обычно это необходимо, только когда вам нужно изменить один из собственных атрибутов HTML компонента в методе действия. Например

<p:commandButton action="#{bean.action}" update="@this" 
    oncomplete="doSomething('#{bean.value}')" />

Представь, что oncomplete необходимо работать с valueизмененным значением action, тогда эта конструкция не сработала бы, если бы компонент не обновлялся по той простой причине, что oncompleteявляется частью сгенерированного вывода HTML (и, следовательно, все выражения EL в нем оцениваются во время рендеринга ответа).

@allОбновляет весь документ, который должен использоваться с осторожностью. Обычно вы хотите использовать для этого истинный GET-запрос вместо простой ссылки ( <a>или <h:link>) или перенаправления после POST с помощью ?faces-redirect=trueили ExternalContext#redirect(). В результате,process="@form" update="@all" сути имеет тот же эффект, что и не-ajax (не частичная) передача. За всю мою карьеру в JSF единственным разумным вариантом использования, с которым я столкнулся, @allявляется отображение страницы с ошибкой в ​​полном объеме в случае возникновения исключения во время запроса AJAX. См. Также Как правильно обрабатывать исключения JSF 2.0 для компонентов AJAXified?

Стандартный JSF - эквивалентно специфический PrimeFaces updateэто renderот <f:ajax render>. Он ведет себя точно так же, за исключением того, что он не поддерживает строку, разделенную запятыми, в отличие от строки PrimeFaces (хотя я лично рекомендую придерживаться соглашения, разделенного пробелами), а также @parentключевое слово. Как updateи по renderумолчанию@none (то есть «ничего»).


Смотрите также:

BalusC
источник
Когда я использую update = "", тогда управляемое свойство компонента поддержки не устанавливается, и моя процедура @PostConstruct завершается ошибкой. Есть предположения? РЕДАКТИРОВАТЬ: • Если вы полагаетесь на управляемое свойство # {param}, присутствующее в последующих запросах POST, то вам нужно включить его как <f: param> в компоненты UICommand.
К.Николас
Может ли процесс / обновление PanelGroup будет обрабатывать / обновлять содержимое этой PanelGroup, например: <h: panelGroup id = "pgId"> // здесь вводятся тексты <h: panelGroup> <p: commandLink process = "pgId" update = "pgId" />
bob-cac
Спасибо @BalusC за это очень хорошее объяснение!
ProgrammingIsAwsome
2
@Rapster: потому что processне установлен, поэтому он использует значение по умолчанию @form. Это также объясняется в ответе выше.
BalusC
2
@Roland: скрывает другую, более серьезную проблему с настройкой приложения.
BalusC
54

Если вам трудно запомнить значения по умолчанию (я знаю, что у меня есть ...), вот краткая выдержка из ответа BalusC:

Компонент | Отправить | обновление
------------ | --------------- | --------------
f: ajax | execute = "@ this" | рендеринг = «@ никто»
p: ajax | process = "@ this" | обновление = «@ ни один»
p: commandXXX | process = "@ form" | обновление = «@ ни один»
Jaqen H'ghar
источник
Просто незначительное исправление: значение по умолчанию processдля p:commandXXXis @all. Кроме того, похоже, что это относится ко всем компонентам, поддерживающим AJAX, например p:menuitem.
Стефан Раух
1
Привет @StephanRauh, большое спасибо за комментарий. Где вы читали по умолчанию @all? Насколько я могу прочитать из ответа BalusC, он @form, тем не менее @all, эквивалентен действующему @form. Хорошие замечания по поводу других компонентов, я думаю, мне нужно будет заглянуть в исходный код, когда придет время увидеть, к каким компонентам он относится, так как я бы не стал писать что-то, что может быть не так
Jaqen H'ghar
1
@ JaqenH'ghar Томас Андрашко рассказал мне об этом @all. Он должен знать, что он недавно внедрил AJAX-движок PrimeFaces. Позже я дважды проверил это, но читая исходный код PrimeFaces и просматривая запросы XHR. Надеюсь, на этот раз я понял это правильно, потому что реализовал запросы AJAX BootsFaces, чтобы они работали идентично запросам AJAX PrimeFaces.
Стефан Раух
Было бы неверно утверждать, что по умолчанию используется значение @all, если HTML не поддерживает отправку нескольких форм. Разработчики должны знать эффективное значение по умолчанию (чтобы Томас мог изменить его соответствующим образом). Между прочим, эти значения по умолчанию неправильно определены как нулевые в Руководстве пользователя Primefaces 6.2.
Марк Дзабель
27

По процессу (в спецификации JSF это называется execute) вы указываете JSF ограничить обработку компонентом, который указан, а все остальное просто игнорируется.

Обновление указывает, какой элемент будет обновлен, когда сервер ответит на ваш запрос.

@all : каждый компонент обрабатывается / отображается.

@this : запрашивающий компонент с атрибутом execute обрабатывается / отображается.

@form : форма, содержащая запрашивающий компонент, обрабатывается / отображается.

@parent : родительский , содержащий запрашивающий компонент, обрабатывается / отображается.

С Primefaces вы даже можете использовать селекторы JQuery, посмотрите этот блог: http://blog.primefaces.org/?p=1867

faissalb
источник
2

Обратите внимание, что PrimeFaces поддерживает стандартные ключевые слова JSF 2.0+:

  • @this Текущий компонент.
  • @all Весь взгляд.
  • @form Ближайшая форма предка текущего компонента.
  • @none Нет компонента.

и стандартные ключевые слова JSF 2.3+:

  • @child(n) n-й ребенок
  • @composite Ближайший составной компонент предка.
  • @id(id) Используется для поиска компонентов по их идентификатору, игнорируя структуру дерева компонентов и именуя контейнеры.
  • @namingcontainer Контейнер наименования ближайшего предка текущего компонента.
  • @parent Родитель текущего компонента.
  • @previous Предыдущий брат.
  • @next Следующий брат.
  • @root Экземпляр UIViewRoot представления, может использоваться, чтобы начать поиск от корня вместо текущего компонента.

Но он также поставляется с некоторыми ключевыми словами PrimeFaces:

  • @row(n) n-й ряд
  • @widgetVar(name) Компонент с заданным widgetVar.

И вы даже можете использовать то, что называется «PrimeFaces Selectors», что позволяет использовать jQuery Selector API. Например, чтобы обработать все входные данные в элементе с помощью класса CSS myClass:

process="@(.myClass :input)"

Видеть:

Яшма де врис
источник
2
Обратите внимание, что даже JSF2.3 + поддерживает большинство ключевых слов.
тандрашко