| Autor |
Mensagem |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 25/04/2011 16:03:24
|
nei.junior
JavaBaby
Membro desde: 11/12/2008 15:57:03
Mensagens: 98
Localização: SP
Offline
|
Pessoal, boa tarde !
Estou com um problema no "h:inputText" com atributo "required=true".
Para entender minha pergunta no final, considere o seguinte exemplo:
Obs.: Segue abaixo um link com um exemplo montado para testarem também, porém vou explicar:
http://www.mandamais.com.br/download/8beq2542011165533
Ao executar o exemplo, irá abrir uma grid com duas colunas preenchidas da seguinte forma:
Agora siga os seguintes passos:
* Cliquei no "Editar" do nome JOÃO e repare que na próxima tela aparecerá assim:
* Feito isso clique em voltar;
* Cliquei no "Editar" do nome MARIA e repare que na próxima tela aparecerá assim:
* Feito isso clique em voltar;
* Depois cliquei novamente no "Editar" do nome JOÃO;
* Na próxima tela apague input nome ("JOÃO nome") deixando em branco e clique em "Atualizar e Voltar". Observe que no input nome aparecerá uma mensagem de "Campo Obrigatório";
* Clique no botão "Voltar";
* Na grid clique no "Editar" do nome "MARIA nome";
* Repare que na próxima tela aparecerá aparecerá da seguinte forma:
* Obs.: O correto era aparecer da seguinte forma:
Minha pergunta é: Porque isso acontece quando tenho um input que é requerido na tela ?
O correto não era ignorar a execução do botão "Atualizar e Voltar" que quando clico em "Voltar" e quando "Editar" novamente entrar com os valores correspondentes ao objeto que selecionei ?
Obs.: Não quero saber como contornar essa questão, isso eu já sei, quero saber por que ocorre isso neste caso.
Isso é um comportamento correto do JSF ou não ?
Eu estou fazendo algum procedimento errado ? Se sim, qual seria a forma correta neste caso ?
This message was edited 2 times. Last update was at 25/04/2011 20:18:57
|
Mojarra 2.1.6, Facelets, Glassfish V3.1.1, EclipseLink 2.2, Primefaces 3.1, NetBeans 7.1.
Nei Alcantara Jr.
http://twitter.com/NeiAlcantaraJr
"Tudo aquilo que algum idiota diz que é urgente, é algo que um imbecil não fez em tempo hábil e quer que você se ferre para fazer em tempo recorde." |
|
|
 |
|
|
![[Post New]](/templates/default/images/icon_minipost_new.gif) 25/04/2011 22:42:41
|
rponte
JavaEvangelist
![[Avatar]](/images/avatar/37a90a1fe7512a804347fa3e572c6b86.png)
Membro desde: 18/02/2008 10:06:25
Mensagens: 412
Offline
|
Olá nei.junior,
Antes de mais nada, esse problema não está relacionado somente a validação "required", mas sim qualquer erro na fase de validação (seja conversação ou validação).
Vou tentar explicar de maneira simples, o problema e as possíveis soluções que eu conheço.
Os componentes de inputs (todos que implementam EditableValueHolder) possuem 3 (três) tipos de valores que são alterados durante o ciclo de vida de uma requisição, eles são:
1) Submitted Value
2) Local Value
3) Value Binding (aka model value)
Vamos entender agora como esses 3 valores mudam nos componentes durante o ciclo de vida:
** Quando você submete um formulário todos os inputs da página são submetidos como String (parâmetros de request) e na APPLY REQUEST VALUES (2a fase) este valores são setados nos seus devidos componentes de inputs como "submitted value";
** Após isso, na fase de validação (3a fase), cada componente de input tenta converter e validar seu submitted value, em caso de sucesso o componente define seu novo valor convertido como "local value" e seta para null seu submitted value, continuando assim o ciclo de vida. Em caso de erro de conversão ou validação o componente não define seu "local value" e marca o componente como invalido, que por fim pula para última fase (RENDER RESPONSE);
** Se não houver erro na fase de validação o ciclo de vida continua na UPDATE MODEL VALUES para popular o modelo (managed bean etc), para cada componente de input setado no modelo o seu "local value" é setado para null e o ciclo termina na RENDER RESPONSE exibindo os valores do modelo (através das EL's);
O "problema" realmente ocorre na RENDER RESPONSE porque o componente pode retornar qualquer um dos 3 valores, contudo seguindo essa ordem de prioridade:
** Se houver submitted value então retorne-o;
** Caso contrário, se o local value é não nulo então retorne-o;
** Caso contrário, avalie a EL, ou seja, chame o getter do modelo;
Entendendo essa prioridade acima você mata a charada do problema
Esse problema ocorre muito comumente quando trabalhamos com a mesma árvore de componentes, ou seja, quando utilizamos muito AJAX e/ou navegação orientada a estados. Quando utilizamos a navegação padrão do JSF dificilmente caímos nesse problema.
Todas as soluções que conheço envolve limpar a árvore de componentes que está "suja":
1) Navegação padrão do Faces para recriar toda a viewroot (não vale retornar null);
2) Limpar de maneira educada todos os componentes de inputs;
3) Limpar os inputs de maneira "brute force" ( parentComponent.getChildren().clear() - eles serão recriados na RENDER RESPONSE novamente, porém só funciona com JSF 1.x, pois o 2.x parece seguir corretamente a spec);
Eu acho que acabei falando de mais, isso daria até um post no blog, mas a preguiça nunca me deixou escrever, rss.
No mais, segue alguns links para complementar o que eu disse,
http://cagataycivici.wordpress.com/2005/12/28/jsf_component_s_value_local/
http://ovaraksin.blogspot.com/2010/06/submitted-value-local-value-model-value.html
http://stackoverflow.com/questions/260094/jsf-getvalue-v-s-getsubmittedvalue
Um abraço e espero que tenha ficado claro!
|
Rafael Ponte
http://www.rponte.com.br/ |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 25/04/2011 23:19:23
|
Paulo Silveira
Administrador
![[Avatar]](/images/avatar/a87ff679a2f3e71d9181a67b7542122c.jpg)
Membro desde: 07/08/2002 18:38:50
Mensagens: 4158
Localização: São Paulo
Offline
|
Viveriamos melhor se todos nos conhecessemos tanto de JSF quanto o Ponte!
|
http://blog.caelum.com.br twitter: @paulo_caelum
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 25/04/2011 23:23:43
|
vinnysoft
JavaTeenager
![[Avatar]](/images/avatar/41147eabcdf237c41b03485364b8057e.jpg)
Membro desde: 21/09/2010 00:56:24
Mensagens: 191
Localização: Vitória - Espírito Santo
Offline
|
Quando eu crescer quero ser igual ao Ponte e ao VinyGodoi!
|
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 26/04/2011 08:15:26
|
danilo.magrini
What is classpath?
Membro desde: 26/04/2011 08:09:57
Mensagens: 8
Offline
|
** Após isso, na fase de validação (3a fase), cada componente de input tenta converter e validar seu submitted value, em caso de sucesso o componente define seu novo valor convertido como "local value" e seta para null seu submitted value, continuando assim o ciclo de vida. Em caso de erro de conversão ou validação o componente não define seu "local value" e marca o componente como invalido, que por fim pula para última fase (RENDER RESPONSE);
** Se não houver erro na fase de validação o ciclo de vida continua na UPDATE MODEL VALUES para popular o modelo (managed bean etc), para cada componente de input setado no modelo o seu "local value" é setado para null e o ciclo termina na RENDER RESPONSE exibindo os valores do modelo (através das EL's);
Só fazendo uma observação aqui Rafael, o local value é setado logo após o submitted value ser convertido (se existir um converter associado) e sequer atinge o estágio de validação pois se assim fosse o local value nunca serviria pra nada já que se a conversão foi correta e a validação também então o modelo já seria atualizado e o local value passaria para null correto?
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 26/04/2011 08:58:49
|
nei.junior
JavaBaby
Membro desde: 11/12/2008 15:57:03
Mensagens: 98
Localização: SP
Offline
|
Bom dia a todos !
Rafael, primeiramente quero agradecer pela resposta, foi bastante esclarecedora.
Fazendo alguns testes aqui com o @DaniloMagrini, achamos um procedimento um pouco estranho.
Vou exemplificar o procedimento que fiz primeiramente para depois perguntar:
* No setCliente do "mbTesteRequired" e no método "editar" fiz o seguinte procedimento:
* Levando em consideração o procedimento que ja expliquei acima, onde clico para editar o "JOÃO", deixo em branco o nome e clico em "Atualizar e voltar" para dar "Campo Obrigatório", depois clico no botão "Voltar", e por fim na grid clico em editar "MARIA" e la na tela de cadastro vem como:
* Quando pego o que imprimiu no "output" do netBeans esta assim:
* Agora no momento que cliquei no botão "Editar" do nome "MARIA" ele atualizou o modelo, significa que ele executou todos os outros processos corretamente, ou seja, o "Submitted Value" e o "Local Value" estão como "NULL".
Agora porque que na tela continua errado ? Não era para vir certo ?
Obrigado por enquanto !
|
Mojarra 2.1.6, Facelets, Glassfish V3.1.1, EclipseLink 2.2, Primefaces 3.1, NetBeans 7.1.
Nei Alcantara Jr.
http://twitter.com/NeiAlcantaraJr
"Tudo aquilo que algum idiota diz que é urgente, é algo que um imbecil não fez em tempo hábil e quer que você se ferre para fazer em tempo recorde." |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 26/04/2011 09:35:55
|
rponte
JavaEvangelist
![[Avatar]](/images/avatar/37a90a1fe7512a804347fa3e572c6b86.png)
Membro desde: 18/02/2008 10:06:25
Mensagens: 412
Offline
|
Oi Danilo,
danilo.magrini wrote:
Só fazendo uma observação aqui Rafael, o local value é setado logo após o submitted value ser convertido (se existir um converter associado) e sequer atinge o estágio de validação pois se assim fosse o local value nunca serviria pra nada já que se a conversão foi correta e a validação também então o modelo já seria atualizado e o local value passaria para null correto?
Na verdade eu gostaria de garantir isso para você, mas já li artigos que afirmam que o local value é setado após a validação e outros dizem que é setado logo após a conversão, na qual a validação só cuidaria de invalidar o componente. Mas no geral, para nós "usuários" do framework que não criamos componentes não faz tanta diferença assim. No mais, o local value também é utilizado para eventos que ocorrem imediatamente após a conversão e validação dentro da própria fase de validação, como por exemplo valueChangeListener's.
|
Rafael Ponte
http://www.rponte.com.br/ |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 26/04/2011 09:50:24
|
rponte
JavaEvangelist
![[Avatar]](/images/avatar/37a90a1fe7512a804347fa3e572c6b86.png)
Membro desde: 18/02/2008 10:06:25
Mensagens: 412
Offline
|
nei.junior wrote:
* Agora no momento que cliquei no botão "Editar" do nome "MARIA" ele atualizou o modelo, significa que ele executou todos os outros processos corretamente, ou seja, o "Submitted Value" e o "Local Value" estão como "NULL".
Agora porque que na tela continua errado ? Não era para vir certo ?
Obrigado por enquanto !
Nei,
Lembre-se que a árvore de componentes ficou "suja" após o erro de validação (mas especificamente os inputs do formulário), e o que você fez após clicar no botão "Voltar" foi apenas esconder o formulário (rendered=false). O formulário, independente de quantas requisições AJAX ocorram, ainda permanece "sujo" em memoria e seus componentes de inputs não são processados no ciclo de vida pois o componente parent está rendered=false, por isso os valores internos não mudam (que já estavam "sujos" com o local value antigo, caindo naquela ordem de prioridade do valores: local value antes do model value).
Não sei se ficou claro. Caso tenha ficado confuso é só falar que tento explicar melhor.
Um abraço.
|
Rafael Ponte
http://www.rponte.com.br/ |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 26/04/2011 10:04:07
|
nei.junior
JavaBaby
Membro desde: 11/12/2008 15:57:03
Mensagens: 98
Localização: SP
Offline
|
rponte wrote:
Nei,
Lembre-se que a árvore de componentes ficou "suja" após o erro de validação (mas especificamente os inputs do formulário), e o que você fez após clicar no botão "Voltar" foi apenas esconder o formulário (rendered=false). O formulário, independente de quantas requisições AJAX ocorram, ainda permanece "sujo" em memoria e seus componentes de inputs não são processados no ciclo de vida pois o componente parent está rendered=false, por isso os valores internos não mudam (que já estavam "sujos" com o local value antigo, caindo naquela ordem de prioridade do valores: local value antes do model value).
Rafael,
Entendi sim, porém essa questão do AJAX foi o que pensei por priemiro. Portanto nesse exemplo que criei, não sei se você baixou ai, mas se sim pode observar que eu NÃO utilizo AJAX, é tudo requisição normal para recarregar a página toda e mesmo assim continua errado.
Como não é AJAX ele recarrega toda a página novamente, correto ? Com isso ele deveria reconstruir tudo novamente e vir correto, não é ?
Obrigado por enquanto !
Abraço.
|
Mojarra 2.1.6, Facelets, Glassfish V3.1.1, EclipseLink 2.2, Primefaces 3.1, NetBeans 7.1.
Nei Alcantara Jr.
http://twitter.com/NeiAlcantaraJr
"Tudo aquilo que algum idiota diz que é urgente, é algo que um imbecil não fez em tempo hábil e quer que você se ferre para fazer em tempo recorde." |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 26/04/2011 10:16:51
|
rponte
JavaEvangelist
![[Avatar]](/images/avatar/37a90a1fe7512a804347fa3e572c6b86.png)
Membro desde: 18/02/2008 10:06:25
Mensagens: 412
Offline
|
nei.junior wrote:
Rafael,
Entendi sim, porém essa questão do AJAX foi o que pensei por priemiro. Portanto nesse exemplo que criei, não sei se você baixou ai, mas se sim pode observar que eu NÃO utilizo AJAX, é tudo requisição normal para recarregar a página toda e mesmo assim continua errado.
Como não é AJAX ele recarrega toda a página novamente, correto ? Com isso ele deveria reconstruir tudo novamente e vir correto, não é ?
Obrigado por enquanto !
Abraço.
Nei,
Eu havia baixado sim seu código. Quando comentei sobre o AJAX foi somente para reforçar, pois normalmente o problema ocorre quando utilizamos muito AJAX. Mas como eu havia dito, seja requisição comum ou AJAX, você continua trabalhando com a mesma árvore de componentes. No seu método editar() você retorna null como regra de navegação, simbolizando para o faces navegar para a mesma página, porém utilizando a mesma árvore de componentes em vez de recriar uma nova árvore.
O problema real está na árvore de componentes "suja". Nas soluções que eu havia dado mais acima eu comentei sobre utilizar a navegação do faces, mas sem retornar null.
|
Rafael Ponte
http://www.rponte.com.br/ |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 26/04/2011 10:36:24
|
nei.junior
JavaBaby
Membro desde: 11/12/2008 15:57:03
Mensagens: 98
Localização: SP
Offline
|
rponte wrote:
Nei,
Eu havia baixado sim seu código. Quando comentei sobre o AJAX foi somente para reforçar, pois normalmente o problema ocorre quando utilizamos muito AJAX. Mas como eu havia dito, seja requisição comum ou AJAX, você continua trabalhando com a mesma árvore de componentes. No seu método editar() você retorna null como regra de navegação, simbolizando para o faces navegar para a mesma página, porém utilizando a mesma árvore de componentes em vez de recriar uma nova árvore.
O problema real está na árvore de componentes "suja". Nas soluções que eu havia dado mais acima eu comentei sobre utilizar a navegação do faces, mas sem retornar null.
Rafael,
Bom concluindo o assunto, entendi. Você deu uma boa clareada neste caso.
Agora vamos ver uma das soluções postada no inicio por você.
O @DaniloMagrini deu uma ideia de propor na lista oficial do Mojarra a criação de algo como:
O que acha ? Acho que quando cair nessa situação, pelo menos teria uma forma mais simples e objetiva de contornar.
|
Mojarra 2.1.6, Facelets, Glassfish V3.1.1, EclipseLink 2.2, Primefaces 3.1, NetBeans 7.1.
Nei Alcantara Jr.
http://twitter.com/NeiAlcantaraJr
"Tudo aquilo que algum idiota diz que é urgente, é algo que um imbecil não fez em tempo hábil e quer que você se ferre para fazer em tempo recorde." |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 26/04/2011 10:38:41
|
danilo.magrini
What is classpath?
Membro desde: 26/04/2011 08:09:57
Mensagens: 8
Offline
|
rponte wrote:
Na verdade eu gostaria de garantir isso para você, mas já li artigos que afirmam que o local value é setado após a validação e outros dizem que é setado logo após a conversão, na qual a validação só cuidaria de invalidar o componente. Mas no geral, para nós "usuários" do framework que não criamos componentes não faz tanta diferença assim. No mais, o local value também é utilizado para eventos que ocorrem imediatamente após a conversão e validação dentro da própria fase de validação, como por exemplo valueChangeListener's.
O ideal é procurar isso na especificação. Assim que eu tiver um tempo vou vasculhar entre as JSRs 314, 127 e 252 e ver se encontro algo. Porém se fosse para apostar eu apostaria que ele é setado depois da conversão porque pra mim setar o local value depois da validação se tornaria desnecessário uma vez que ele seria setado e logo em seguida receberia null já que o modelo seria atualizado.
|
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 26/04/2011 10:45:32
|
rponte
JavaEvangelist
![[Avatar]](/images/avatar/37a90a1fe7512a804347fa3e572c6b86.png)
Membro desde: 18/02/2008 10:06:25
Mensagens: 412
Offline
|
danilo.magrini wrote:
O ideal é procurar isso na especificação. Assim que eu tiver um tempo vou vasculhar entre as JSRs 314, 127 e 252 e ver se encontro algo. Porém se fosse para apostar eu apostaria que ele é setado depois da conversão porque pra mim setar o local value depois da validação se tornaria desnecessário uma vez que ele seria setado e logo em seguida receberia null já que o modelo seria atualizado.
Mas é como eu te disse, Danilo, após a validação, dentro da PROCESS VALIDATION, ainda podem ocorrer diversos eventos antes da atualização do modelo. Nesse curto intervalo o modelo precisa estar integro para que alguns eventos funcionem corretamente, como o valueChangeEvent, por exemplo.
|
Rafael Ponte
http://www.rponte.com.br/ |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 26/04/2011 10:55:27
|
rponte
JavaEvangelist
![[Avatar]](/images/avatar/37a90a1fe7512a804347fa3e572c6b86.png)
Membro desde: 18/02/2008 10:06:25
Mensagens: 412
Offline
|
nei.junior wrote:Rafael,
Bom concluindo o assunto, entendi. Você deu uma boa clareada neste caso.
Agora vamos ver uma das soluções postada no inicio por você.
O @DaniloMagrini deu uma ideia de propor na lista oficial do Mojarra a criação de algo como:
O que acha ? Acho que quando cair nessa situação, pelo menos teria uma forma mais simples e objetiva de contornar.
Nei,
Antes de mais nada, é importante definir bem o que "invalidar" significa. Significa recriar toda a árvore de componentes? Limpar o estado interno de todos os inputs ou todos os componentes?
O pessoal do Trinidad criou algo semelhante, mas acho que somente para inputs, não me recordo. Tanto que foi incorporado ao JSF 2.x. Se eu pesquisar talvez até ache o artigo.
No mais, eu acredito que você não queira invalidar toda a árvore de componentes, mas sim alguns componentes ou grupo de componentes. Então utilizar navegação é a solução mais simples e o próprio faces já te fornecesse isso.
Enfim, provavelmente há uma forte razão para o ciclo de vida e os componentes trabalharem assim! Se você souber de algo no forum não deixe de me informar.
|
Rafael Ponte
http://www.rponte.com.br/ |
|
|
 |
![[Post New]](/templates/default/images/icon_minipost_new.gif) 26/04/2011 11:19:27
|
nei.junior
JavaBaby
Membro desde: 11/12/2008 15:57:03
Mensagens: 98
Localização: SP
Offline
|
rponte wrote:
Nei,
Antes de mais nada, é importante definir bem o que "invalidar" significa. Significa recriar toda a árvore de componentes? Limpar o estado interno de todos os inputs ou todos os componentes?
O pessoal do Trinidad criou algo semelhante, mas acho que somente para inputs, não me recordo. Tanto que foi incorporado ao JSF 2.x. Se eu pesquisar talvez até ache o artigo.
No mais, eu acredito que você não queira invalidar toda a árvore de componentes, mas sim alguns componentes ou grupo de componentes. Então utilizar navegação é a solução mais simples e o próprio faces já te fornecesse isso.
Enfim, provavelmente há uma forte razão para o ciclo de vida e os componentes trabalharem assim! Se você souber de algo no forum não deixe de me informar.
Rafael,
O invalidar seria limpar o estado interno de todos os inputs, praticamente o que você fez nessa solução.
Quanto a navegação do faces, no caso desse exemplo se ao entrar na grid eu apertasse um botão filtrar e carregar a grid, ai quando entrasse na página de cadastro e voltasse ele perderia os dados da grid pois recriou toda a arvore novamente. Isso é um exemplo simples de como colocar a navegação do faces atrapalharia (de uma certa forma) se quero manter a grid sem ter que filtrar novamente.
Portanto deixando o voltar como NULL ele não recria e não perde. Sendo assim, usando a sua solução ele funcionaria perfeitamente.
Enfim, agora que ficou claro vamos elaborar a melhor forma de trabalhar para resolver isso.
Quero agradecer pela atenção e pelas dúvidas esclarecidas e se eu souber de algo ou achar alguma outra solução, informo todos aqui.
Muito obrigado
Abraço !
|
Mojarra 2.1.6, Facelets, Glassfish V3.1.1, EclipseLink 2.2, Primefaces 3.1, NetBeans 7.1.
Nei Alcantara Jr.
http://twitter.com/NeiAlcantaraJr
"Tudo aquilo que algum idiota diz que é urgente, é algo que um imbecil não fez em tempo hábil e quer que você se ferre para fazer em tempo recorde." |
|
|
 |
|
|