Rechercher dans la sortie HTML l'ID client réel
Vous devez regarder dans la sortie HTML générée pour trouver le bon ID client. Ouvrez la page dans le navigateur, faites un clic droit et voir la source . Recherchez la représentation HTML du composant JSF qui vous intéresse et prenez-la id
comme ID client. Vous pouvez l'utiliser de manière absolue ou relative en fonction du conteneur de dénomination actuel. Voir le chapitre suivant.
Note: si elle arrive à contenir l' itération index comme :0:
, :1:
, etc (parce qu'il est à l' intérieur d' un composant itérer), alors vous devez réaliser que la mise à jour d' un cycle d'itération spécifique ne sont pas toujours pris en charge. Voir le bas de la réponse pour plus de détails à ce sujet.
Mémorisez les NamingContainer
composants et donnez-leur toujours un identifiant fixe
Si un composant que vous souhaitez référencer par ajax process / execute / update / render se trouve dans le même NamingContainer
parent, alors référencez simplement son propre ID.
<h:form id="form">
<p:commandLink update="result"> <!-- OK! -->
<h:panelGroup id="result" />
</h:form>
Si ce n'est pas le même NamingContainer
, vous devez le référencer à l'aide d'un ID client absolu. Un ID client absolu commence par le NamingContainer
caractère de séparation, qui est par défaut :
.
<h:form id="form">
<p:commandLink update="result"> <!-- FAIL! -->
</h:form>
<h:panelGroup id="result" />
<h:form id="form">
<p:commandLink update=":result"> <!-- OK! -->
</h:form>
<h:panelGroup id="result" />
<h:form id="form">
<p:commandLink update=":result"> <!-- FAIL! -->
</h:form>
<h:form id="otherform">
<h:panelGroup id="result" />
</h:form>
<h:form id="form">
<p:commandLink update=":otherform:result"> <!-- OK! -->
</h:form>
<h:form id="otherform">
<h:panelGroup id="result" />
</h:form>
NamingContainer
composants sont par exemple <h:form>
, <h:dataTable>
, <p:tabView>
, <cc:implementation>
(ainsi, tous les composants composites), etc. Vous les reconnaissent facilement en regardant la sortie HTML généré, leur carte d' identité sera préfixé au client ID généré de tous les composants de l' enfant. Notez que lorsqu'ils n'ont pas d'ID fixe, JSF utilisera un ID généré automatiquement au j_idXXX
format. Vous devez absolument éviter cela en leur donnant un identifiant fixe. Les OmniFacesNoAutoGeneratedIdViewHandler
peuvent être utiles à cet égard pendant le développement.
Si vous savez trouver le javadoc de l'objet UIComponent
en question, vous pouvez également simplement vérifier s'il implémente l' NamingContainer
interface ou non. Par exemple, HtmlForm
(la balise UIComponent
derrière <h:form>
) montre qu'elle implémente NamingContainer
, mais HtmlPanelGroup
(la balise UIComponent
derrière <h:panelGroup>
) ne l'affiche pas, donc elle ne l'implémente pas NamingContainer
. Voici le javadoc de tous les composants standard et voici le javadoc de PrimeFaces .
Résoudre votre problème
Donc dans votre cas de:
<p:tabView id="tabs"><!-- This is a NamingContainer -->
<p:tab id="search"><!-- This is NOT a NamingContainer -->
<h:form id="insTable"><!-- This is a NamingContainer -->
<p:dialog id="dlg"><!-- This is NOT a NamingContainer -->
<h:panelGrid id="display">
La sortie HTML générée de <h:panelGrid id="display">
ressemble à ceci:
<table id="tabs:insTable:display">
Vous devez prendre exactement cela id
comme ID client, puis préfixer avec :
pour une utilisation dans update
:
<p:commandLink update=":tabs:insTable:display">
Référencement extérieur à include / tagfile / composite
Si ce lien de commande est à l'intérieur d'un include / tagfile et que la cible est à l'extérieur de celui-ci, et que vous ne connaissez donc pas nécessairement l'ID du conteneur de dénomination parent du conteneur de dénomination actuel, vous pouvez le référencer dynamiquement via UIComponent#getNamingContainer()
comme ceci:
<p:commandLink update=":#{component.namingContainer.parent.namingContainer.clientId}:display">
Ou, si ce lien de commande est à l'intérieur d'un composant composite et que la cible est à l'extérieur de celui-ci:
<p:commandLink update=":#{cc.parent.namingContainer.clientId}:display">
Ou, si le lien de commande et la cible sont à l'intérieur du même composant composite:
<p:commandLink update=":#{cc.clientId}:display">
Voir aussi Obtenir l'ID du conteneur de dénomination parent dans le modèle pour l'attribut de rendu / mise à jour
Comment ça marche sous les couvertures
Tout cela est spécifié comme "expression de recherche" dans le UIComponent#findComponent()
javadoc :
Une expression de recherche se compose soit d'un identificateur (qui correspond exactement à la propriété id de a UIComponent
, soit d'une série d'identificateurs liés par la UINamingContainer#getSeparatorChar
valeur du caractère. L'algorithme de recherche doit fonctionner comme suit, bien que d'autres algorithmes puissent être utilisés tant que le le résultat final est le même:
- Identifiez le
UIComponent
qui sera la base de la recherche, en vous arrêtant dès que l'une des conditions suivantes est remplie:
- Si l'expression de recherche commence par le caractère séparateur (appelé expression de recherche "absolue"), la base sera la racine
UIComponent
de l'arborescence des composants. Le caractère séparateur de tête sera supprimé et le reste de l'expression de recherche sera traité comme une expression de recherche "relative" comme décrit ci-dessous.
- Sinon, s'il
UIComponent
s'agit d'un, NamingContainer
il servira de base.
- Sinon, recherchez les parents de ce composant. Si un
NamingContainer
est rencontré, ce sera la base.
- Sinon (si aucun
NamingContainer
n'est rencontré), la racine UIComponent
sera la base.
- L'expression de recherche (éventuellement modifiée à l'étape précédente) est maintenant une expression de recherche "relative" qui sera utilisée pour localiser le composant (le cas échéant) qui a un identifiant qui correspond, dans la portée du composant de base. Le match se déroule comme suit:
- Si l'expression de recherche est un identifiant simple, cette valeur est comparée à la propriété id, puis récursivement à travers les facettes et les enfants de la base
UIComponent
(sauf que si un descendant NamingContainer
est trouvé, ses propres facettes et enfants ne sont pas recherchés).
- Si l'expression de recherche comprend plusieurs identifiants séparés par le caractère de séparation, le premier identifiant est utilisé pour localiser un
NamingContainer
par les règles de la puce précédente. Ensuite, la findComponent()
méthode NamingContainer
sera appelée, en passant le reste de l'expression de recherche.
Notez que PrimeFaces adhère également à la spécification JSF, mais RichFaces utilise «quelques exceptions supplémentaires» .
"reRender" utilise un UIComponent.findComponent()
algorithme (avec quelques exceptions supplémentaires) pour trouver le composant dans l'arborescence des composants.
Ces exceptions supplémentaires ne sont nulle part décrites en détail, mais il est connu que les ID de composants relatifs (c'est-à-dire ceux qui ne commencent pas par :
) sont non seulement recherchés dans le contexte du parent le plus proche NamingContainer
, mais également dans tous les autres NamingContainer
composants de la même vue (ce qui est relativement travail coûteux d'ailleurs).
Ne jamais utiliser prependId="false"
Si tout cela ne fonctionne toujours pas, vérifiez si vous n'utilisez pas <h:form prependId="false">
. Cela échouera pendant le traitement de la soumission et du rendu ajax. Voir aussi cette question connexe: UIForm avec prependId = "false" breaks <f: ajax render> .
Référencement d'un cycle d'itération spécifique de composants itératifs
Pendant longtemps, il n'a pas été possible de référencer un élément itéré spécifique dans des composants itératifs comme <ui:repeat>
et <h:dataTable>
comme ceci:
<h:form id="form">
<ui:repeat id="list" value="#{['one','two','three']}" var="item">
<h:outputText id="item" value="#{item}" /><br/>
</ui:repeat>
<h:commandButton value="Update second item">
<f:ajax render=":form:list:1:item" />
</h:commandButton>
</h:form>
Cependant, depuis que Mojarra 2.2.5 a <f:ajax>
commencé à le supporter (il a simplement cessé de le valider; ainsi, vous ne feriez plus jamais face à l'exception mentionnée dans la question; un autre correctif d'amélioration est prévu pour cela plus tard).
Cela ne fonctionne pas encore dans les versions actuelles de MyFaces 2.2.7 et PrimeFaces 5.2. Le support pourrait venir dans les futures versions. En attendant, votre meilleur pari est de mettre à jour le composant itératif lui-même, ou un parent au cas où il ne rendrait pas le HTML, comme <ui:repeat>
.
Lorsque vous utilisez PrimeFaces, pensez aux expressions de recherche ou aux sélecteurs
PrimeFaces Search Expressions vous permet de référencer des composants via des expressions de recherche d'arborescence de composants JSF. JSF a plusieurs intégrés:
@this
: composant actuel
@form
: parent UIForm
@all
: document entier
@none
: rien
PrimeFaces a amélioré cela avec de nouveaux mots clés et la prise en charge des expressions composites:
@parent
: composant parent
@namingcontainer
: parent UINamingContainer
@widgetVar(name)
: composant identifié par donné widgetVar
Vous pouvez également mélanger ces mots - clés dans les expressions composites tels que @form:@parent
, @this:@parent:@parent
, etc.
Les sélecteurs PrimeFaces (PFS) comme dans @(.someclass)
vous permettent de référencer des composants via la syntaxe du sélecteur CSS jQuery. Par exemple, référencer des composants ayant tous une classe de style commune dans la sortie HTML. Ceci est particulièrement utile au cas où vous auriez besoin de faire référence à «un grand nombre» de composants. Cela nécessite uniquement que les composants cibles aient tous un ID client dans la sortie HTML (fixe ou généré automatiquement, peu importe). Voir aussi Comment fonctionnent les sélecteurs PrimeFaces comme dans update = "@ (. MyClass)"?
context.getViewRoot().findComponent(":inputform" + UINamingContainer.getSeparatorChar(context) + "inputtext" );
Veuillez également inclure le code xhtml.prependId="false"
sauvé ma journée.tout d'abord: pour autant que je sache, placer une boîte de dialogue dans une vue tabulaire est une mauvaise pratique ... vous feriez mieux de la retirer ...
et maintenant à votre question:
désolé, il m'a fallu un certain temps pour obtenir exactement ce que vous vouliez mettre en œuvre,
fait moi-même sur mon application Web tout à l'heure, et cela fonctionne
comme je l'ai dit avant, placez le p: dialogue à côté du `p: tabView,
laissez la boîte de dialogue p: comme vous l'aviez initialement suggéré:
et le p: commandlink devrait ressembler à ceci (tout ce que j'ai fait est de changer l'attribut de mise à jour)
la même chose fonctionne dans mon application Web, et si cela ne fonctionne pas pour vous, alors je suppose qu'il y a quelque chose qui ne va pas dans votre code java bean ...
la source
C'est parce que l'onglet est un conteneur de nommage aussi ... votre mise à jour devrait être
update="Search:insTable:display"
Ce que vous pouvez faire est simplement de placer votre boîte de dialogue en dehors du formulaire et toujours à l'intérieur de l'onglet, alors ce serait:update="Search:display"
la source
Essayez de changer
update="insTable:display"
enupdate="display"
. Je crois que vous ne pouvez pas préfixer l'identifiant avec l'identifiant du formulaire comme ça.la source
Je sais que cela a déjà une excellente réponse de BalusC, mais voici une petite astuce que j'utilise pour que le conteneur me dise le bon clientId .
Voici un exemple de code car mes mots ne le décrivent peut-être pas le mieux.
Supprimez la mise à jour défaillante dans ce composant
Ajoutez un composant dans le composant de l'ID que vous essayez de mettre à jour à l'aide d'une mise à jour qui échouera
Accédez à cette page et affichez l'erreur. L'erreur est: javax.servlet.ServletException: Impossible de trouver le composant pour l'expression "BogusUpdate" référencé à partir des onglets: insTable: BogusButton
Ainsi, le clientId correct à utiliser serait alors le gras plus l'ID du conteneur cible (affiché dans ce cas)
la source