JSTL no JSF2 Facelets… faz sentido?

Eu gostaria de produzir um pouco de código Facelets condicionalmente.

Para esse propósito, as tags JSTL parecem funcionar bem:

 ...  

No entanto, não tenho certeza se essa é uma prática recomendada? Existe outra maneira de alcançar meu objective?

Introdução

Tags JSTL são todos taghandlers e são executados durante o tempo de construção da view , enquanto tags JSF são todos componentes da UI e são executados durante o tempo de renderização da view .

Note que a partir das tags e do JSF, apenas aquelas que não se estendem do UIComponent são também taghandlers, por exemplo, , , , etc. Os que se estendem a partir do UIComponent também são componentes de UI JSF, por exemplo, , , , etc. A partir dos componentes de IU do JSF, os atributos id e binding também são avaliados durante o tempo de compilation . Assim, a resposta abaixo quanto ao ciclo de vida do JSTL também se aplica aos atributos id e binding dos componentes JSF.

O tempo de compilation da visualização é aquele momento em que o arquivo XHTML / JSP deve ser analisado e convertido em uma tree de componentes JSF que é então armazenada como UIViewRoot do FacesContext . O tempo de renderização da visualização é aquele momento em que a tree do componente JSF está prestes a gerar HTML, começando com UIViewRoot#encodeAll() . Portanto, os componentes da interface do JSF e as tags JSTL não são executados em sincronia como seria de esperar da codificação. Você pode visualizá-lo da seguinte maneira: O JSTL é executado de cima para baixo primeiro, produzindo a tree de componentes JSF, depois é a vez de o JSF executar de cima para baixo novamente, produzindo a saída HTML.

vs

Por exemplo, esta marcação do Facelets iterando mais de 3 itens usando :

    

… cria durante o tempo de compilation da visualização três componentes separados na tree de componentes JSF, aproximadamente representados da seguinte forma:

    

… que, por sua vez, geram individualmente sua saída HTML durante o tempo de renderização da visualização:

 value1 value2 value3 

Observe que você precisa garantir manualmente a exclusividade dos IDs dos componentes e que eles também são avaliados durante o tempo de criação da visualização.

Enquanto esta marcação Facelets iterating mais de 3 itens usando , que é um componente de interface do usuário JSF:

    

… já termina como está na tree de componentes do JSF, na qual o mesmo componente é durante o tempo de renderização da visualização sendo reutilizado para gerar saída HTML com base na rodada de iteração atual:

 value1 value2 value3 

Observe que o como sendo um componente NamingContainer já garantiu a exclusividade do ID do cliente com base no índice de iteração; também não é possível usar EL no atributo id de componentes filhos dessa forma, pois ele também é avaliado durante o tempo de construção da visualização, enquanto #{item} está disponível apenas durante o tempo de renderização da visualização. O mesmo é verdadeiro para um h:dataTable e componentes semelhantes.

/ vs rendered

Como outro exemplo, esta marcação Facelets adiciona condicionalmente tags diferentes usando (você também pode usar para isto):

          

… no caso de type = TEXT somente o componente adicionado à tree de componentes do JSF:

  

Enquanto esta marcação Facelets:

    

… terminará exatamente como acima na tree de componentes do JSF, independentemente da condição. Isso pode acabar em uma tree de componentes “inchada” quando você tem muitos deles e eles são realmente baseados em um modelo “estático” (ou seja, o field nunca muda durante pelo menos o escopo da visão). Além disso, você pode encontrar problemas EL ao lidar com subclasss com propriedades adicionais nas versões do Mojarra anteriores a 2.2.7.

vs

Eles não são intercambiáveis. O define uma variável no escopo EL, que é acessível somente após o local da tag durante o tempo de criação da visualização, mas em qualquer lugar na visualização durante o tempo de renderização da exibição. O passa uma variável EL para um modelo do Facelet incluído via , , ou . Versões mais antigas do JSF possuíam erros nos quais a variável também está disponível fora do modelo do Facelet em questão, isso nunca deve ser invocado.

O sem um atributo de scope se comportará como um alias. Não armazena em cache o resultado da expressão EL em qualquer escopo. Assim, pode perfeitamente ser usado dentro de, por exemplo, iterar componentes JSF. Assim, por exemplo, abaixo irá funcionar bem:

     

Só não é adequado para, por exemplo, calcular a sum em um loop. Para isso, use o stream do EL 3.0 :

  ...  

Total price: #{bean.products.stream().map(product->product.price).sum()}

Somente quando você definir o atributo scope com um dos valores permitidos request , view , session ou application , ele será avaliado imediatamente durante o tempo de construção da view e armazenado no escopo especificado.

  

Isso será avaliado apenas uma vez e estará disponível como #{dev} todo o aplicativo.

Use o JSTL para controlar a construção de tree de componentes JSF

O uso do JSTL pode levar apenas a resultados inesperados ao ser usado dentro de componentes de iteração JSF, como , , etc, ou quando atributos de tag JSTL dependem de resultados de events JSF como preRenderView ou valores de formulário enviados o modelo que não está disponível durante o tempo de criação da visualização. Portanto, use tags JSTL apenas para controlar o stream de construção de tree de componentes JSF. Use os componentes da UI JSF para controlar o stream de geração de saída HTML. Não ligue a var de iterar componentes JSF a atributos de tag JSTL. Não confie nos events JSF nos atributos de tag JSTL.

Toda vez que você acha que precisa ligar um componente ao backing bean via binding , ou pegue um via findComponent() , e crie / manipule seus filhos usando o código Java em um backing bean com o new SomeComponent() e o que não, então você deve imediatamente Pare e considere o uso do JSTL. Como o JSTL também é baseado em XML, o código necessário para criar dinamicamente os componentes do JSF se tornará muito mais legível e sustentável.

É importante saber que as versões do Mojarra anteriores à versão 2.1.18 tinham um bug no estado parcial de economia ao fazer referência a um bean com escopo de visão em um atributo de tag JSTL. Todo o bean com escopo de visão seria recriado em vez de recuperado da tree de exibição (simplesmente porque a tree de exibição completa ainda não está disponível no ponto em que o JSTL é executado). Se você está esperando ou armazenando algum estado no bean com escopo de visão por um atributo de tag JSTL, ele não retornará o valor esperado ou será “perdido” no bean com escopo de visão real que é restaurado após a exibição tree é construída. Caso você não possa atualizar para o Mojarra 2.1.18 ou mais recente, a solução é desativar a economia de estado parcial no web.xml como abaixo:

  javax.faces.PARTIAL_STATE_SAVING false  

Veja também:

  • Qual é o tempo de compilation da visualização?
  • Como o atributo ‘binding’ funciona no JSF? Quando e como deve ser usado?
  • Como refatorar o trecho do antigo JSP para algum equivalente JSF?
  • Deve PARTIAL_STATE_SAVING ser definido como falso?
  • Comunicação no JSF 2.0 – @ViewScoped falha em manipuladores de tag

Para ver alguns exemplos do mundo real em que as tags JSTL são úteis (ou seja, quando realmente usadas corretamente durante a criação da visualização), consulte as seguintes perguntas / respostas:

  • Como fazer uma grade de componente composto JSF?
  • Crie colunas de tabela dinamicamente no JSF
  • Como personalizar o layout h: selectOneRadio
  • Definição de variável condicional no JSF
  • Como fazer um componente composto semelhante a
  • JSF 2 – Componente composto com atributo listener opcional em f: ajax
  • Componentes compostos JSF nesteds que levam a uma exceção de estouro de pilha

Em poucas palavras

Quanto ao seu requisito funcional concreto, se desejar renderizar condicionalmente os componentes JSF, use o atributo rendered no componente JSF HTML, principalmente se #{lpc} representar o item atualmente iterado de um componente de iteração JSF, como ou .

  ...  

Ou, se você quiser construir (criar / adicionar) componentes JSF condicionalmente, continue usando o JSTL. É muito melhor que fazer o new SomeComponent() em java.

   ...   

Veja também:

  • Exibindo Condicionalmente os Componentes JSF
  • JSTL c: se não funciona dentro de um JSF h: dataTable
  • Especifique a renderização condicional do elemento dentro de ? O parece não funcionar

usar

  ...  

Desculpe pela resposta em separado, mas não consegui comentar as respostas acima.

Para saída tipo switch, você pode usar o switch from primefaces-extensions .