Jak znaleźć identyfikator klienta komponentu dla ajax update / render? Nie można znaleźć komponentu z wyrażeniem " foo " odwołującym się z "bar"
Poniższy kod jest zainspirowany tutorialami PrimeFaces DataGrid + DataTable i umieszczony w <p:tab>
z <p:tabView>
z <p:layoutUnit>
z <p:layout>
. Oto wewnętrzna część kodu (zaczynając od p:tab
komponentu); zewnętrzna część jest trywialna.
<p:tabView id="tabs">
<p:tab id="search" title="Search">
<h:form id="insTable">
<p:dataTable id="table" var="lndInstrument" value="#{instrumentBean.instruments}">
<p:column>
<p:commandLink id="select" update="insTable:display" oncomplete="dlg.show()">
<f:setPropertyActionListener value="#{lndInstrument}"
target="#{instrumentBean.selectedInstrument}" />
<h:outputText value="#{lndInstrument.name}" />
</p:commandLink>
</p:column>
</p:dataTable>
<p:dialog id="dlg" modal="true" widgetVar="dlg">
<h:panelGrid id="display">
<h:outputText value="Name:" />
<h:outputText value="#{instrumentBean.selectedInstrument.name}" />
</h:panelGrid>
</p:dialog>
</h:form>
</p:tab>
</p:tabView>
Kiedy klikam <p:commandLink>
, kod przestaje działać i daje komunikat:
Nie można znaleźć komponentu z wyrażeniem " insTable: display "odwołującym się do"tabs:insTable:select".
Kiedy próbuję tego samego używając <f:ajax>
, zawodzi z inną wiadomością w zasadzie mówiącą to samo:
<f:ajax>
zawiera nieznany identyfikator "insTable: display" nie może zlokalizować go w kontekście komponentu "tabs:insTable:select"
Jak to jest spowodowane i jak Mogę to rozwiązać?
4 answers
Spójrz na wyjście HTML dla Rzeczywistego ID klienta
Musisz zajrzeć do wygenerowanego wyjścia HTML, aby znaleźć odpowiedni identyfikator klienta. Otwórz stronę w przeglądarce, wykonaj rightclick i Zobacz źródło. Zlokalizuj reprezentację HTML interesującego komponentu JSF i weź jego id
jako identyfikator klienta. Można go używać w sposób bezwzględny lub względny, w zależności od bieżącego kontenera nazw. Patrz następujący rozdział.
Uwaga: jeśli będzie zawierać indeks iteracji jak :0:
, :1:
, etc (ponieważ znajduje się wewnątrz komponentu iteracyjnego), wtedy musisz zdać sobie sprawę, że aktualizacja określonej rundy iteracji nie zawsze jest obsługiwana. Więcej szczegółów na ten temat znajdziesz na dole odpowiedzi.
Zapamiętaj NamingContainer
komponenty i zawsze nadaj im stały identyfikator
Jeśli komponent, do którego chcesz się odwoływać przez proces ajax/execute/update/render, znajduje się wewnątrz tego samego NamingContainer
rodzica, a następnie wystarczy podać swój własny identyfikator.
<h:form id="form">
<p:commandLink update="result"> <!-- OK! -->
<h:panelGroup id="result" />
</h:form>
If it ' s not inside the to samo NamingContainer
, następnie musisz odwołać się do niego za pomocą absolutnego ID klienta. Absolutny identyfikator klienta zaczyna się od znaku separatora NamingContainer
, który jest domyślnie :
.
<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
komponenty są na przykład <h:form>
, <h:dataTable>
, <p:tabView>
, <cc:implementation>
(tak więc wszystkie komponenty kompozytowe), itp. Rozpoznajesz je łatwo patrząc na wygenerowany wynik HTML, ich ID zostanie dołączone do wygenerowanego identyfikatora klienta wszystkich komponentów potomnych. Zauważ, że gdy jeśli nie masz stałego ID, JSF użyje automatycznie wygenerowanego ID w formacie j_idXXX
. Należy bezwzględnie tego unikać, podając im stały identyfikator. OmniFaces NoAutoGeneratedIdViewHandler
może być pomocne w tym podczas rozwoju.
Jeśli wiesz, aby znaleźć javadoc UIComponent
w pytaniu, możesz również sprawdzić, czy implementuje on NamingContainer
interfejs czy nie. Na przykładHtmlForm
( UIComponent
za <h:form>
znacznikiem) pokazuje, że implementuje NamingContainer
, ale HtmlPanelGroup
(UIComponent
za znacznikiem <h:panelGroup>
) nie pokazuje go, więc nie implementuje NamingContainer
. tutaj jest javadoc wszystkich standardowych komponentów i tutaj jest javadoc PrimeFaces .
Rozwiązanie twojego problemu
Więc w Twoim przypadku:
<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">
Wygenerowane wyjście HTML <h:panelGrid id="display">
wygląda tak:
<table id="tabs:insTable:display">
Musisz wziąć dokładnie to id
jako identyfikator klienta, a następnie prefiks z :
do użycia w update
:
<p:commandLink update=":tabs:insTable:display">
Odwoływanie się do zewnątrz include / tagfile / composite
Jeśli ten link polecenia znajduje się wewnątrz pliku include/tag, a obiekt docelowy znajduje się poza nim, a zatem nie musisz znać ID rodzica kontenera nazw bieżącego kontenera nazw, możesz dynamicznie odwoływać się do niego za pomocą UIComponent#getNamingContainer()
w następujący sposób:
<p:commandLink update=":#{component.namingContainer.parent.namingContainer.clientId}:display">
Lub, jeśli link polecenia znajduje się wewnątrz komponentu złożonego, a cel jest poza nim:
<p:commandLink update=":#{cc.parent.namingContainer.clientId}:display">
Lub, jeśli zarówno Komenda link i cel znajduje się wewnątrz tego samego komponentu kompozytowego:
<p:commandLink update=":#{cc.clientId}:display">
Zobacz także pobranie identyfikatora nadrzędnego kontenera nazw w szablonie dla atrybutu render / update
Jak to działa pod pokrywami
To wszystko jest określone jako "wyrażenie wyszukiwania" w UIComponent#findComponent()
javadoc :
A wyrażenie wyszukiwania składa się z identyfikatora (który jest dopasowany dokładnie do właściwości id
UIComponent
, lub serii takich identyfikatory połączone przez wartość znakuUINamingContainer#getSeparatorChar
. Algorytm wyszukiwania powinien działać w następujący sposób, chociaż alternatywne alogrytmy mogą być używane tak długo, jak wynik końcowy jest taki sam: {]}
- Zidentyfikuj
UIComponent
, które będą bazą do wyszukiwania, zatrzymując się, gdy tylko spełniony zostanie jeden z następujących warunków:
- jeśli szukane wyrażenie zaczyna się od znaku separatora (zwanego "absolutnym" szukanym wyrażeniem), bazą będzie root
UIComponent
Z drzewo komponentów. Główny znak separatora zostanie usunięty, a pozostała część szukanego wyrażenia będzie traktowana jako "względne" szukane wyrażenie, jak opisano poniżej.- W przeciwnym razie, jeśli to
UIComponent
jest {[15] } będzie służyć jako podstawa.- W Przeciwnym Razie wyszukaj rodziców tego komponentu. Jeśli zostanie napotkana
NamingContainer
, będzie to baza.- W przeciwnym razie (jeśli nie występuje
NamingContainer
) rootUIComponent
będzie bazą.- wyrażenie wyszukiwania (prawdopodobnie zmodyfikowane w poprzednim kroku) jest teraz "względnym" wyrażeniem wyszukiwania, które będzie używane do zlokalizowania komponentu (jeśli istnieje), który ma pasujący identyfikator, w zakresie komponentu podstawowego. Mecz odbywa się w następujący sposób:
- jeśli szukane wyrażenie jest prostym identyfikatorem, wartość ta jest porównywana z właściwością id, a następnie rekurencyjnie przez Fasety i dzieci bazy
UIComponent
(z wyjątkiem tego, że jeśli zostanie znaleziony potomekNamingContainer
, jego własne oblicza i dzieci nie są wyszukiwane).- jeśli szukane wyrażenie zawiera więcej niż jeden identyfikator oddzielony znakiem separatora, pierwszy identyfikator jest używany do zlokalizowania
NamingContainer
zgodnie z regułami w poprzednim podpunkcie. Następnie zostanie wywołana metodafindComponent()
tegoNamingContainer
, przekazująca pozostałą część szukanego wyrażenia.
Zauważ, że PrimeFaces również przestrzega specyfikacji JSF, ale RichFaces używa "niektórych dodatkowych wyjątki " .
"rerender" używa algorytmu
UIComponent.findComponent()
(z pewnymi dodatkowymi wyjątkami), aby znaleźć komponent w drzewie komponentów.
Te dodatkowe wyjątki nie są nigdzie szczegółowo opisane, ale wiadomo, że względne identyfikatory komponentów (tj. te, które nie rozpoczynają się od :
) są wyszukiwane nie tylko w kontekście najbliższego rodzica NamingContainer
, ale także we wszystkich innych komponentach NamingContainer
w tym samym widoku (co jest stosunkowo kosztownym zadaniem przez serwer). sposób).
Nigdy nie używaj prependId="false"
Jeśli to wszystko nadal nie działa, sprawdź, czy nie używasz <h:form prependId="false">
. To nie powiedzie się podczas przetwarzania Ajax submit i renderowania. Zobacz także podobne pytanie: UIForm with prependId="false" breaks
Odniesienie do specyficznej rundy iteracji komponentów iteracyjnych
Przez długi czas nie było możliwe odwoływanie się do określonego iteracyjnego elementu w iteracyjnych komponentach, takich jak <ui:repeat>
i <h:dataTable>
, takich jak więc:
<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>
Jednakże, odkąd Mojarra 2.2.5 <f:ajax>
zaczęło ją wspierać (po prostu przestało ją zatwierdzać; w ten sposób nigdy nie spotkałbyś się już z wspomnianym wyjątkiem; kolejna poprawka ulepszenia jest planowana na to później).
To nie działa jeszcze w obecnych wersjach MyFaces 2.2.7 i PrimeFaces 5.2. Wsparcie może pojawić się w przyszłych wersjach. W międzyczasie najlepiej będzie zaktualizować komponent iteracyjny lub rodzica, jeśli nie Renderuj HTML, jak <ui:repeat>
.
Używając PrimeFaces, rozważ szukanie wyrażeń lub selektorów
PrimeFaces Search Expressions pozwala na odwoływanie się do komponentów poprzez JSF component tree search expressions. JSF ma kilka wbudowanych:
-
@this
: Składnik bieżący -
@form
: rodzicUIForm
-
@all
: cały dokument -
@none
: nic
PrimeFaces rozszerzył to o nowe słowa kluczowe i obsługa wyrażeń złożonych:
-
@parent
: element nadrzędny -
@namingcontainer
: rodzicUINamingContainer
-
@widgetVar(name)
: Składnik określony przez danywidgetVar
Możesz także mieszać te słowa kluczowe w wyrażeniach złożonych, takich jak @form:@parent
, @this:@parent:@parent
, itd.
Selektory PrimeFaces (PFS) jak w @(.someclass)
pozwalają na odwoływanie się do komponentów poprzez składnię selektora CSS jQuery. Np. odwoływanie się do komponentów mających wszystkie wspólne klasy stylu w HTML wyjście. Jest to szczególnie pomocne w przypadku, gdy trzeba odwołać się do "wielu" komponentów. To tylko wymaga, aby komponenty docelowe miały wszystkie ID klienta w wyjściu HTML (stałe lub autogenerowane, nie ma znaczenia). Zobacz także jak zrobić selektory PrimeFaces jak w update="@(.myClass) " praca?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:44
Po pierwsze: z tego, co wiem, umieszczanie okna dialogowego wewnątrz widoku kart jest złą praktyką... lepiej to wyjmij...
A teraz do pytania: Przepraszam, Zajęło mi trochę czasu, żeby dostać to, co chciałeś zaimplementować.]}Zrobiłem w mojej aplikacji internetowej właśnie teraz, i to działa
Tak jak przed umieszczeniem okna p:Po stronie ' p: tabView,
Pozostaw okno dialogowe p: tak jak początkowo sugerowałeś:
<p:dialog modal="true" widgetVar="dlg">
<h:panelGrid id="display">
<h:outputText value="Name:" />
<h:outputText value="#{instrumentBean.selectedInstrument.name}" />
</h:panelGrid>
</p:dialog>
I P: commandlink powinien wyglądać tak (wszystkie I did is to change the update atrybut)
<p:commandLink update="display" oncomplete="dlg.show()">
<f:setPropertyActionListener value="#{lndInstrument}"
target="#{instrumentBean.selectedInstrument}" />
<h:outputText value="#{lndInstrument.name}" />
</p:commandLink>
To samo działa w mojej aplikacji internetowej, a jeśli nie działa dla ciebie, to chyba coś jest nie tak w Twoim kodzie java bean...
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-28 08:11:33
Dzieje się tak dlatego, że tab jest również kontenerem nazw... twoja aktualizacja powinna być update="Search:insTable:display"
to, co możesz zrobić, to po prostu umieścić okno dialogowe poza formularzem i nadal wewnątrz karty, a następnie będzie to: update="Search:display"
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-26 10:59:36
Spróbuj zmienić update="insTable:display"
na update="display"
. Wierzę, że nie można przedrostka id z ID formularza w ten sposób.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-26 09:25:56