JSF e Naming Container

Todo desenvolvedor que se utiliza de JavaServer Faces deveria saber como funciona o mecanismo de geração de identificação (ID) dos componentes, pois uma hora querendo ou não ele precisará deste conhecimento, principalmente se houver a necessidade de se escrever algum código JavaScript.

Enfim, vamos ao que interessa..

Entendendo o mecanismo

Uma das caracteristicas do JSF é que todos os seus componentes possuem um atribudo “id” e este atributo deve conter um valor único, caso não seja definido um ID pelo desenvolvedor então será gerado automaticamente um ID único para cada componente durante a construção da árvore de componentes.

Sendo, observem o seguinte trecho de código JSF:

<h:form>
	<h:inputText id="nome"/>
</h:form>

No final será gerado para o cliente (browser) o seguinte código -ou algo parecido- (X)HTML:

<form id="j_id_jsp_1761815803_1" name="j_id_jsp_1761815803_1" method="post">
	<input id="j_id_jsp_1761815803_1:nome" type="text" name="j_id_jsp_1761815803_1:nome" />
</form>

Reparem que o atributo “id” do componente h:form não foi definido, porém o framework gerou um ID único para o componente, no caso o ID foi “j_id_jsp_1761815803_1“, que foi renderizado juntamente com a tag <form/> do (X)HTML.

Atentem também que o ID (gerado) do componente h:form foi concatenado ao ID (que nós definimos) do componente h:inputText separados por ‘:’ (dois pontos) na tag <input/>, logo o ID da nossa tag <input/> é “j_id_jsp_1761815803_1:nome“.

Infelizmente os IDs gerados pelo framework não são nada legíveis para nós desenvolvedores -e provavelmente não deveriam-, então para consertar isso basta definirmos o ID de cada componente na nossa página, logo nosso código JSF ficará assim:

<h:form id="form">
    <h:inputText id="nome"/>
</h:form>

E consequentemente o código (X)HTML gerado será algo semelhante a isto:

<form id="form" name="form" method="post">
	<input id="form:nome" type="text" name="form:nome" />
</form>

Como podem ver, os IDs na página gerada ficam bem mais legíveis, facilitando assim o trabalho com JavaScript no lado cliente.

Naming container

E onde afinal de contas entra essa história de Naming Container?

Se vocês observaram o componente h:inputText teve seu ID concatenado ao ID do formulário no cliente, ou seja, na tag <input/> (X)HTML, e isso aconteceria com todos os componentes dentro do componente h:form. Logo, o componente h:form é um componente e ao mesmo tempo um naming container.

Basicamente, Naming Container é uma caracteristica que alguns componentes possuem, caracteristica essa que o framework utiliza para garantir que dentro de um naming container (componente) seus componentes filhos possuam IDs  únicos, evitando assim a duplicidade de componentes com o mesmo ID na página (viewroot).

Outra caracteristica importante que você deve saber sobre naming containers é que eles podem ser aninhados, logo os componentes mais internos terão seus IDs no cliente concatenados com os IDs dos naming containers mais externos também.

Logo em um caso como:

<h:form id="form">
    <f:subview id="subview">
        <h:inputText id="nome"/>
    </f:subview>
</h:form>

Teríamos o código (X)HTML abaixo gerado:

<form id="form" name="form" method="post">
	<input id="form:subview:nome" type="text" name="form:subview:nome" />
</form>

O componente f:subview também é um naming container, porém ele não gera qualquer output no cliente, ele é utilizado basicamente para servir como naming container, principalmente quando se faz includes de páginas dinâmicas.

Simples até demais, não?

Componentes padrões como h:form, f:subview e h:dataTable são naming containers. A maioria dos conjuntos de componentes possuem alguns naming containers, logo isso depende do conjunto de componentes.

Evitando naming container no formulário

As vezes temos páginas simples em que o único naming container é o próprio componente h:form, e nestas páginas precisamos manipular alguns dados no formulário através de JavaScript, porém é algo realmente chato ficar concatenando IDs para obter o ID de um input do formulário.

Para resolver isso o componente h:form (no JSF1.2) possui o atributo “prependId” que define se o componente se comportará no cliente como naming container ou não. Para evitar que o h:form se comporte como naming container basta setarmos o atributo “prependId” para false. Assim quando o código (X)HTML for gerado para o cliente as tags internas não terão seus IDs modificados.

<h:form id="form" prependId="false">
    <h:inputText id="nome"/>
</h:form>

Sem complicações, certo?

Essa caracteristica funciona somente para os componentes filhos do h:form, caso haja um naming container dentro do h:form então os filhos deste name container terão seus IDs alterados normalmente no cliente.

Concluindo

O post ficou até longo para um assunto básico, mas acredito que consegui abordar os fundamentos sobre naming container para quem pretende apenas utilizar os componentes na construção de páginas. Para quem realmente pretende criar (ou estender) seus próprios componentes seria interessante conhecer o conceito mais a fundo.

Enfim, o conceito é básico, porém fundamental para desenvolvedores que usam JavaServer Faces. Contudo é incrível como a maioria dos desenvolvedores não se interessam pelos fundamentos do framework, fundamentos estes que evitariam diversas dúvidas e problemas durante o desenvolvimento.

17 Replies to “JSF e Naming Container”

  1. Parabens pelos posts. Sempre de otima qualidade e com uma quantidade enorme de informacoes.

    Abraco

  2. Olá rafael! Acompanho sempre seus posts e na maioria das vezes eles me salvam!
    nao sei se vc verá esse comentário, mas me ficou uma duvida. Como posso agir se o inpuText está dentro de um repeat do facelets?
    Tipo, estou criando um panel que renderiza os nomes das categorias por repeat, dentro de cada categoria, eu tenho os produtos em uma rich:tree.
    Até aí, tudo OK. Agora, quando eu clico no nó da tree de um dos panels, ele abre os dois.
    Verifiquei que o JSF estah nomeando os ids da tree do mesmo jeito e gostaria de concatenar esses ids com alguma coisa que os diferenciassem.
    o Tomahawk tem um atributo “forceId” nos inputText, mas na tree nao, entao nao sei como eu poderia fazer isso.
    Alguma idéia…?
    Obrigada pela atenção e desculpa se nao fui clara. Se precisar explico mais detalhadamente….

  3. Olá Inah,

    Eu nunca tive essa necessidade, assim como não sei como o componente de rich:tree trabalha ao certo.

    Mas quando você se utiliza do componente ui:repeat (ou mesmo h:dataTable) do Facelets ele simplesmente itera sobre o mesmo componente, ou seja, haverá somente UM único componente na árvore do JSF, porém este será renderizado diversas vezes, ou seja, para cada iteraçao do ui:repeat. Então acredito que por isso ele possua o mesmo ID.

    Uma possível solução, seria utilizar JSTL, mas precisamente a tag c:forEach. Diferentemente do ui:repeat esta tag itera sobre o componente e cria novos componentes na árvore de componentes do JSF a cada iteraçao. Sendo, você não pode fixar um ID a qualquer componente interno do c:forEach, caso contrário terá conflito entre os IDs.

    Acredito que com ele seja possível você resolver o problema, mas não tenho certeza.

    Pensando melhor talvez o próprio componente h:dataTable, que é um naming container, possa resolver teu problema também. Se o h:dataTable resolver então vá com ele, já que JSTL e JSF não combinam muito.

    Enfim, faça alguns testes. Se der certo não deixe de me avisar.
    Um abraço e boa sorte.

  4. Os fundamentos dos frameworks em Java são fundamentais para o entendimento e desenvolvimento de aplicações com essa linguagem. Parabéns por compartilhar o teu conhecimento e pelo post.

    Abraço
    Marcelo Hexsel

  5. Hi admin do you need unlimited articles for your page ?
    What if you could copy article from other blogs, make it unique and publish
    on your site – i know the right tool for you, just search
    in google:
    Ziakdra’s article tool

  6. Excelente post e de fácil entendimento. Obrigado!

  7. Fico feliz que tenha gostado do post! Apesar dele ser antigo ainda é bastante acessado para quem inicia com JSF.

  8. Excelelente post, objetivo, simples e suficiente pra se ter uma base, uma coisa ruim de ler artigos sobre Linguagens, é que sempre tem enrolação e tals. Muito Obrigado!!!

Deixe um comentário