Entendendo o processo / atualização do PrimeFaces e os atributos de execução / renderização do JSF f: ajax

193

O que exatamente são processe updatenos p:commandXxxcomponentes PrimeFaces e executee renderna f:ajaxtag?

O que funciona no momento da validação? O que o updateatributo faz, em vez de atualizar o valor para o componente do back-end? Fazer processvalor ligam atributo a modelo? O que exatamente @this, @parent, @alle @formem ambos os atributos?

O exemplo abaixo está funcionando bem, mas estou um pouco confuso em conceitos básicos.

<p:commandButton process="@parent"
                 update="@form"
                 action="#{bean.submit}" 
                 value="Submit" />
Shardendu
fonte

Respostas:

306

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

O processatributo é do lado do servidor e pode afetar apenas a UIComponentimplementação EditableValueHolder(campos de entrada) ou ActionSource(campos de comando). O processatributo informa ao JSF, usando uma lista separada por espaço de IDs do cliente, quais componentes exatamente devem ser processados ​​durante todo o ciclo de vida do JSF após o envio do formulário (parcial).

O JSF aplicará os valores de solicitação (localizando o parâmetro de solicitação HTTP com base no próprio ID do cliente do componente e, em seguida, configurá-lo como valor enviado no caso de EditableValueHoldercomponentes ou enfileirar um novo ActionEventno caso de ActionSourcecomponentes), executar a conversão, validação e atualizar os valores do modelo ( EditableValueHoldersomente componentes) e, finalmente, invoque a fila ActionEvent( ActionSourcesomente componentes). O JSF ignorará o processamento de todos os outros componentes que não são cobertos por processatributo. Além disso, os componentes cujo renderedatributo é avaliado falsedurante a fase de aplicar valores de solicitação também serão ignorados como parte da proteção contra solicitações adulteradas.

Observe que, no caso de ActionSourcecomponentes (como <p:commandButton>), é muito importante incluir também o próprio componente no processatributo, principalmente se você pretende invocar a ação associada ao componente. Portanto, o exemplo abaixo, que pretende processar apenas determinados componentes de entrada quando um determinado componente de comando é chamado, não funcionará:

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

Processaria apenas o #{bean.foo}e não o #{bean.action}. Você também precisará incluir o próprio componente de comando:

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

Ou, como você aparentemente descobriu, usar @parentse eles forem os únicos componentes com um pai comum:

<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>

Ou, se os dois forem os únicos componentes do UIFormcomponente pai , você também poderá usar @form:

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

Às vezes, isso é indesejável se o formulário contiver mais componentes de entrada que você gostaria de ignorar no processamento, mais frequentemente nos casos em que você gostaria de atualizar outro (s) componente (s) de entrada ou alguma seção da interface do usuário com base no componente de entrada atual em um método de ouvinte ajax. Você não quer que erros de validação em outros componentes de entrada estejam impedindo a execução do método do ouvinte ajax.

Então há o @all. Isso não tem efeito especial no processatributo, mas apenas no updateatributo. Um process="@all"comporta-se exatamente da mesma forma que process="@form". O HTML não suporta o envio de vários formulários ao mesmo tempo.

A propósito, também há um @noneque pode ser útil caso você não precise absolutamente processar nada, mas apenas deseja atualizar algumas partes específicas update, principalmente as seções cujo conteúdo não depende dos valores enviados ou dos ouvintes de ação.

Deve-se notar que o processatributo não tem influência na carga útil da solicitação HTTP (a quantidade de parâmetros da solicitação). Ou seja, o comportamento HTML padrão do envio de "tudo" contido na representação HTML do <h:form>não será afetado. Caso você tenha um formulário grande e deseje reduzir a carga útil da solicitação HTTP apenas para aqueles absolutamente necessários no processamento, ou seja, apenas aqueles cobertos pelo processatributo, é possível definir o partialSubmitatributo nos componentes do PrimeFaces Ajax como em <p:commandXxx ... partialSubmit="true">ou <p:ajax ... partialSubmit="true">. Você também pode configurar isso 'globalmente' editando web.xmle adicionando

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

Como alternativa, você também pode usar o <o:form>OmniFaces 3.0+, cujo padrão é esse comportamento.

O JSF padrão equivalente ao específico do PrimeFaces processé executede <f:ajax execute>. Ele se comporta exatamente da mesma forma, exceto que não suporta uma cadeia de caracteres separada por vírgula enquanto a do PrimeFaces (embora eu pessoalmente recomendo apenas manter a convenção separada por espaço), nem a @parentpalavra - chave. Além disso, pode ser útil saber que o <p:commandXxx process>padrão é @formwhile <p:ajax process>e o <f:ajax execute>padrão é while @this. Por fim, também é útil saber que processsuporta os chamados "Seletores PrimeFaces", consulte também Como funcionam os seletores PrimeFaces, como em update = "@ (. MyClass)"?


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

O updateatributo é do lado do cliente e pode afetar a representação HTML de todos os UIComponents. O updateatributo informa ao JavaScript (o responsável por manipular a solicitação / resposta do ajax), usando uma lista de IDs de clientes separada por espaço, cujas partes da árvore DOM do HTML precisam ser atualizadas como resposta ao envio do formulário.

O JSF preparará a resposta correta do ajax para isso, contendo apenas as partes solicitadas para atualização. O JSF ignorará todos os outros componentes que não são cobertos pelo updateatributo na resposta ajax, mantendo a carga útil da resposta pequena. Além disso, os componentes cujo renderedatributo é avaliado falsedurante a fase de resposta de renderização serão ignorados. Observe que, embora retorne true, o JavaScript não pode atualizá-lo na árvore DOM HTML, se fosse inicialmente false. Você precisaria envolvê-lo ou atualizar seu pai. Consulte também Ajax update / render não funciona em um componente que possui atributo de renderização .

Geralmente, você deseja atualizar apenas os componentes que realmente precisam ser "atualizados" no lado do cliente após o envio do formulário (parcial). O exemplo abaixo atualiza todo o formulário pai via @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>

(observe que o processatributo foi omitido, pois o padrão é @formjá)

Embora isso possa funcionar bem, a atualização dos componentes de entrada e comando é desnecessária neste exemplo específico. A menos que você altere os valores do modelo fooe o método barinterno action(o que por sua vez não seria intuitivo na perspectiva do UX), não há motivo para atualizá-los. Os componentes da mensagem são os únicos que realmente precisam ser atualizados:

<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>

No entanto, isso fica entediante quando você tem muitos deles. Essa é uma das razões pelas quais existem os seletores PrimeFaces. Esses componentes de mensagem têm na saída HTML gerada uma classe de estilo comum ui-message; portanto, o seguinte também deve ser:

<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>

(observe que você deve manter os IDs nos componentes da mensagem, caso contrário @(...)não funcionará! Mais uma vez, consulte Como funcionam os seletores do PrimeFaces como em update = "@ (. myClass)" funcionam? para obter detalhes)

Ele @parentatualiza apenas o componente pai, que cobre o componente atual e todos os irmãos e filhos. Isso é mais útil se você tiver separado o formulário em grupos sãos, cada um com sua própria responsabilidade. As @thisatualizações, obviamente, apenas o componente atual. Normalmente, isso é necessário apenas quando você precisa alterar um dos atributos HTML do componente no método action. Por exemplo

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

Imagine que as oncompletenecessidades de trabalhar com as valuealterações foram alteradas action, então essa construção não funcionaria se o componente não fosse atualizado, pelo simples motivo de fazer oncompleteparte da saída HTML gerada (e, portanto, todas as expressões EL nele são avaliadas durante a resposta de renderização).

A @allatualiza todo o documento, que deve ser usado com cuidado. Normalmente, você deseja usar uma solicitação GET verdadeira para isso usando um link simples ( <a>ou <h:link>) ou um redirecionamento após o POST por ?faces-redirect=trueou ExternalContext#redirect(). Nos efeitos, process="@form" update="@all"tem exatamente o mesmo efeito que um envio não-ajax (não parcial). Em toda a minha carreira no JSF, o único caso de uso sensato que encontrei @allé exibir uma página de erro na íntegra, caso ocorra uma exceção durante uma solicitação de ajax. Consulte também Qual é a maneira correta de lidar com exceções do JSF 2.0 para componentes AJAXified?

O JSF padrão equivalente ao específico do PrimeFaces updateé renderde <f:ajax render>. Ele se comporta exatamente da mesma forma, exceto que não suporta uma cadeia de caracteres separada por vírgula enquanto a do PrimeFaces (embora eu pessoalmente recomendo apenas manter a convenção separada por espaço), nem a @parentpalavra - chave. Ambos updatee o renderpadrão @noneé (que é "nada").


Veja também:

BalusC
fonte
Quando uso update = "", a propriedade gerenciada do bean de backup não é definida e minha rotina @PostConstruct falha. Alguma ideia? EDIT: • Se você confiar que uma propriedade gerenciada de # {param} esteja presente nas solicitações subsequentes do POST, será necessário incluí-la como <f: param> nos componentes do UICommand.
18714 K.K. Nicolas
pode que um processo / atualização de um panelGroup processe / atualize o conteúdo deste panelGroup ex: <h: panelGroup id = "pgId"> // os textos de entrada vão aqui <h: panelGroup> <p: commandLink process = "pgId" update = "pgId" />
bob-cac
Thx @BalusC por esta explicação muito agradável!
ProgrammingIsAwsome
2
@ Rapster: como processnão está definido, usa o valor padrão de @form. Isso também é explicado na resposta acima.
precisa saber é o seguinte
2
@Roland: está escondendo um problema diferente e mais sério com a configuração do aplicativo.
BalusC
54

Se você tiver dificuldade em lembrar os valores padrão (eu sei que tenho ...), aqui está um pequeno extrato da resposta do BalusC:

Componente | Enviar Atualizar
------------ | --------------- | --------------
f: ajax | execute = "@ isto" | render = "@ nenhum"
p: ajax | process = "@ this" | update = "@ nenhum"
p: commandXXX | process = "@ form" | update = "@ nenhum"
Jaqen H'ghar
fonte
Apenas uma pequena correção: o valor padrão de processfor p:commandXXXé @all. Além disso, isso parece se aplicar a todos os componentes que suportam AJAX, como p:menuitem.
23816 Stephan Rauh
1
Olá @StephanRauh, muito obrigado por comentar. Onde você leu o padrão é @all? Tanto quanto eu posso ler da resposta de BalusC @form, @allé equivalente a @formno processo. Bom ponto sobre os outros componentes, eu acho que vou ter de olhar para o código-fonte quando o tempo para ver quais os componentes que se aplica, como eu preferiria não escrever algo que pode estar errado
Jaqen H'ghar
1
@ JaqenH'ghar Thomas Andraschko me contou sobre o @allpouco. Ele deve saber, ele reimplementou o mecanismo AJAX do PrimeFaces recentemente. Mais tarde, verifiquei novamente, mas lendo o código fonte do PrimeFaces e examinando as solicitações XHR. Espero ter acertado desta vez, porque implementei as solicitações AJAX do BootsFaces para trabalhar de forma idêntica às solicitações AJAX do PrimeFaces.
Stephan Rauh 27/16
Seria enganoso dizer que o padrão é @all quando o HTML não suporta o envio de vários formulários. Os desenvolvedores precisam conhecer o valor padrão efetivo (para que Thomas possa alterá-lo de acordo). A propósito, esses padrões são definidos incorretamente como nulos no Guia do Usuário do Primefaces 6.2.
Marc Dzaebel
27

Por processo (na especificação JSF, é chamado de execução), você diz ao JSF para limitar o processamento ao componente que é especificado, tudo o que é ignorado.

update indica qual elemento será atualizado quando o servidor responder novamente à sua solicitação.

@all : todo componente é processado / renderizado.

@ isto : O componente solicitante com o atributo execute é processado / renderizado.

@form : o formulário que contém o componente solicitante é processado / renderizado.

@parent : o pai que contém o componente solicitante é processado / renderizado.

Com o Primefaces, você pode até usar seletores JQuery, confira este blog: http://blog.primefaces.org/?p=1867

faissalb
fonte
2

Observe que o PrimeFaces suporta as palavras-chave JSF 2.0+ padrão:

  • @this Componente atual.
  • @all Visão completa.
  • @form Forma ancestral mais próxima do componente atual.
  • @none Nenhum componente.

e as palavras-chave JSF 2.3+ padrão:

  • @child(n) enésimo filho.
  • @composite Antepassado de componente composto mais próximo.
  • @id(id) Usado para procurar componentes por seu ID, ignorando a estrutura da árvore de componentes e nomeando contêineres.
  • @namingcontainer Contêiner de nomeação de ancestral mais próximo do componente atual.
  • @parent Pai do componente atual.
  • @previous Irmão anterior.
  • @next Próximo irmão.
  • @root A instância UIViewRoot da visualização pode ser usada para iniciar a pesquisa a partir da raiz, em vez do componente atual.

Mas também vem com algumas palavras-chave específicas do PrimeFaces:

  • @row(n) enésima linha.
  • @widgetVar(name) Componente com o widgetVar fornecido.

E você pode até usar algo chamado "Seletores PrimeFaces", que permite usar a API do jQuery Selector. Por exemplo, para processar todas as entradas em um elemento com a classe CSS myClass:

process="@(.myClass :input)"

Vejo:

Jasper de Vries
fonte
2
Observe que até o JSF2.3 + suporta a maioria das palavras-chave.
Tandraschko #