Zrozumienie procesu / aktualizacji PrimeFaces i atrybutów wykonania / renderowania JSF f: ajax

194

Czym dokładnie są processi updatew p:commandXxxskładnikach PrimeFaces executeoraz renderw f:ajaxznaczniku?

Które działa w momencie walidacji? Co robi updateatrybut zamiast aktualizować wartość komponentu z zaplecza? Czy processatrybut wiąże wartość z modelem? Co dokładnie zrobić @this, @parent, @alli @formw obu atrybutów?

Poniższy przykład działa dobrze, ale jestem trochę zagubiony w podstawowych pojęciach.

<p:commandButton process="@parent"
                 update="@form"
                 action="#{bean.submit}" 
                 value="Submit" />
Shardendu
źródło

Odpowiedzi:

307

<p:commandXxx process> <p:ajax process> <f:ajax execute>

processAtrybut jest po stronie serwera, a może tylko wpłynąć UIComponents wykonawcze EditableValueHolder(pól wejściowych) lub ActionSource(pola poleceń). processAtrybut mówi JSF, używając rozdzieloną spacjami listę identyfikatorów klienta, który dokładnie składniki muszą być przetwarzane przez cały cykl życia JSF po (częściowe) Forma przedstawienia.

Następnie JSF zastosuje wartości żądań (znajdując parametr żądania HTTP na podstawie własnego identyfikatora klienta komponentu, a następnie ustawiając go jako przesłaną wartość w przypadku EditableValueHolderkomponentów lub ustawiając w kolejce nowy ActionEventw przypadku ActionSourcekomponentów), wykona konwersję, sprawdzenie poprawności i aktualizację wartości modelu ( EditableValueHoldertylko komponenty) i wreszcie wywołaj kolejkę ActionEvent( ActionSourcetylko komponenty). JSF pominie przetwarzanie wszystkich innych składników, które nie są objęte processatrybutem. Również komponenty, których renderedatrybut ocenia falsepodczas fazy stosowania wartości żądań, zostaną również pominięte w ramach zabezpieczenia przed nieuprawnionymi żądaniami.

Zauważ, że w przypadku ActionSourcekomponentów (takich jak <p:commandButton>) bardzo ważne jest, abyś sam uwzględnił komponent w processatrybucie, szczególnie jeśli zamierzasz wywołać akcję powiązaną z komponentem. Poniższy przykład, który zamierza przetwarzać tylko określone komponenty wejściowe po wywołaniu określonego komponentu polecenia, nie zadziała:

<p:inputText id="foo" value="#{bean.foo}" />
<p:commandButton process="foo" action="#{bean.action}" />

Byłoby przetwarzać tylko #{bean.foo}i nie#{bean.action} . Musisz także dołączyć sam komponent polecenia:

<p:inputText id="foo" value="#{bean.foo}" />
<p:commandButton process="@this foo" action="#{bean.action}" />

Lub, jak najwyraźniej się dowiedziałeś, używając, @parentjeśli są to jedyne składniki mające wspólnego rodzica:

<p:panel><!-- Type doesn't matter, as long as it's a common parent. -->
    <p:inputText id="foo" value="#{bean.foo}" />
    <p:commandButton process="@parent" action="#{bean.action}" />
</p:panel>

Lub, jeśli oba są jedynymi komponentami komponentu nadrzędnego UIForm, możesz również użyć @form:

<h:form>
    <p:inputText id="foo" value="#{bean.foo}" />
    <p:commandButton process="@form" action="#{bean.action}" />
</h:form>

Jest to czasami niepożądane, jeśli formularz zawiera więcej składników wejściowych, które chcesz pominąć w przetwarzaniu, częściej niż w przypadkach, gdy chcesz zaktualizować inne składniki wejściowe lub sekcję interfejsu użytkownika w oparciu o bieżący składnik wejściowy w metoda nasłuchująca ajax. Nie chcesz, aby błędy sprawdzania poprawności w innych komponentach wejściowych uniemożliwiały wykonanie metody nasłuchującej ajax.

Potem jest @all. Nie ma to żadnego specjalnego efektu w processatrybucie, ale tylko w updateatrybucie. process="@all"Zachowuje się dokładnie tak samo jak process="@form". HTML i tak nie obsługuje przesyłania wielu formularzy jednocześnie.

Nawiasem mówiąc, istnieje również @none , która może być przydatna w przypadku, gdy absolutnie nie trzeba niczego proces, ale tylko chcesz zaktualizować niektóre części konkretnych pośrednictwem update, szczególnie te odcinki, których zawartość nie zależy od wartości lub słuchaczy złożonych działań.

Należy zauważyć, że processatrybut nie ma wpływu na ładunek żądania HTTP (ilość parametrów żądania). Oznacza to, że <h:form>nie będzie to miało wpływu na domyślne zachowanie HTML wysyłania „wszystkiego” zawartego w reprezentacji HTML pliku . Jeśli masz dużą formę i chcesz zmniejszyć ładunek żądania HTTP do tylko tych absolutnie niezbędnych w przetwarzaniu, tj. Tylko tych objętych processatrybutem, możesz ustawić partialSubmitatrybut w komponentach PrimeFaces Ajax jak w <p:commandXxx ... partialSubmit="true">lub <p:ajax ... partialSubmit="true">. Możesz również skonfigurować to „globalnie”, edytującweb.xml i dodając

<context-param>
    <param-name>primefaces.SUBMIT</param-name>
    <param-value>partial</param-value>
</context-param>

Możesz także użyć <o:form> OmniFaces 3.0+, który domyślnie zachowuje to zachowanie.

Standardowy JSF równoważny z właściwością PrimeFaces processpochodzi executez <f:ajax execute>. Zachowuje się dokładnie tak samo, z tym wyjątkiem, że nie obsługuje łańcucha rozdzielanego przecinkami, podczas gdy PrimeFaces taki (chociaż osobiście polecam po prostu trzymać się konwencji rozdzielonej spacjami), ani @parentsłowa kluczowego. Warto też wiedzieć, że <p:commandXxx process>domyślnie jest @formwhile <p:ajax process>i <f:ajax execute>domyślnie jest @this. Na koniec warto również wiedzieć, że processobsługuje tak zwane „selektory PrimeFaces”, zobacz także Jak działają selektory PrimeFaces jak w update = "@ (. MyClass)"?


<p:commandXxx update> <p:ajax update> <f:ajax render>

Ten updateatrybut jest po stronie klienta i może wpływać na reprezentację HTML wszystkichUIComponent s. updateAtrybut mówi JavaScript (jeden odpowiedzialny za obsługę AJAX żądanie / odpowiedź), stosując rozdzieloną spacjami listę identyfikatorów klientów, które elementy w drzewie DOM HTML potrzebuje być aktualizowany jako odpowiedź do formy przedstawienia.

JSF przygotuje dla tego poprawną odpowiedź ajax, zawierającą tylko żądane części do aktualizacji. JSF pominie wszystkie inne komponenty, które nie są objęte updateatrybutem w odpowiedzi ajax, tym samym utrzymując niewielki ładunek odpowiedzi. Również komponenty, których renderedatrybut ocenia falsepodczas fazy odpowiedzi renderowania, zostaną pominięte. Zauważ, że nawet jeśli zwróci true, JavaScript nie może zaktualizować go w drzewie HTML HTML, jeśli byłby początkowo false. Zamiast tego musisz go owinąć lub zaktualizować jego element nadrzędny. Zobacz także Aktualizacja / renderowanie Ajax nie działa na komponencie, który wyrenderował atrybut .

Zwykle chcesz aktualizować tylko te komponenty, które naprawdę muszą zostać „odświeżone” po stronie klienta po (częściowym) przesłaniu formularza. Poniższy przykład aktualizuje cały formularz nadrzędny za pośrednictwem @form:

<h:form>
    <p:inputText id="foo" value="#{bean.foo}" required="true" />
    <p:message id="foo_m" for="foo" />
    <p:inputText id="bar" value="#{bean.bar}" required="true" />
    <p:message id="bar_m" for="bar" />
    <p:commandButton action="#{bean.action}" update="@form" />
</h:form>

(zauważ, że processatrybut jest pominięty, ponieważ domyślnie jest @formjuż ustawiony )

Chociaż może to działać dobrze, aktualizacja komponentów wejściowych i poleceń jest w tym konkretnym przykładzie niepotrzebna. Jeśli nie zmienisz wartości modelu fooi metody barwewnętrznej action(co z kolei byłoby nieintuicyjne w perspektywie UX), nie ma sensu ich aktualizować. Składniki wiadomości są jedynymi, które naprawdę wymagają aktualizacji:

<h:form>
    <p:inputText id="foo" value="#{bean.foo}" required="true" />
    <p:message id="foo_m" for="foo" />
    <p:inputText id="bar" value="#{bean.bar}" required="true" />
    <p:message id="bar_m" for="bar" />
    <p:commandButton action="#{bean.action}" update="foo_m bar_m" />
</h:form>

Jednak staje się to uciążliwe, gdy masz ich wiele. To jeden z powodów istnienia Selektorów PrimeFaces. Te komponenty wiadomości mają w wygenerowanym pliku wyjściowym HTML wspólną klasę stylów ui-message, dlatego też należy wykonać następujące czynności:

<h:form>
    <p:inputText id="foo" value="#{bean.foo}" required="true" />
    <p:message id="foo_m" for="foo" />
    <p:inputText id="bar" value="#{bean.bar}" required="true" />
    <p:message id="bar_m" for="bar" />
    <p:commandButton action="#{bean.action}" update="@(.ui-message)" />
</h:form>

(zwróć uwagę, że powinieneś zachować identyfikatory w komponentach wiadomości, w przeciwnym razie @(...)nie zadziała! Ponownie zobacz, jak działają selektory PrimeFaces jak w update = "@ (. myClass)"? )

@parentAktualizuje tylko składnik nadrzędny, który tym samym obejmuje bieżącego składnika i wszystkie rodzeństwo i ich dzieci. Jest to bardziej przydatne, jeśli oddzieliłeś formularz w zdrowych grupach, a każda z nich ma własną odpowiedzialność. Te @thisaktualizacje, oczywiście, tylko obecny komponent. Zwykle jest to konieczne tylko wtedy, gdy trzeba zmienić jeden z własnych atrybutów HTML komponentu w metodzie akcji. Na przykład

<p:commandButton action="#{bean.action}" update="@this" 
    oncomplete="doSomething('#{bean.value}')" />

Wyobraź sobie, że oncompletetrzeba pracować z tym, valueco zostało zmienione action, a następnie ten konstrukt nie działałby, gdyby składnik nie został zaktualizowany, z prostego powodu, który oncompletejest częścią generowanego wyniku HTML (a zatem wszystkie wyrażenia EL są tam oceniane podczas renderowania odpowiedzi).

@allAktualizuje cały dokument, który powinien być stosowany z ostrożnością. Zwykle zamiast tego chcesz użyć prawdziwego żądania GET poprzez zwykły link ( <a>lub <h:link>) lub przekierowanie po POST przez ?faces-redirect=truelub ExternalContext#redirect(). W efektach process="@form" update="@all"ma dokładnie taki sam efekt, jak przesłanie nie-ajaxowe (nie częściowe). W całej mojej karierze JSF jedynym sensownym przypadkiem użycia, na jaki się natknąłem, @alljest wyświetlenie strony błędu w całości na wypadek wystąpienia wyjątku podczas żądania ajax. Zobacz także Jaki jest właściwy sposób postępowania z wyjątkami JSF 2.0 dla komponentów AJAXified?

Standardowy JSF równoważny z właściwością PrimeFaces updatepochodzi renderz <f:ajax render>. Zachowuje się dokładnie tak samo, z tym wyjątkiem, że nie obsługuje łańcucha rozdzielanego przecinkami, podczas gdy PrimeFaces taki (chociaż osobiście polecam po prostu trzymać się konwencji rozdzielonej spacjami), ani @parentsłowa kluczowego. Zarówno domyślnie, jak updatei (czyli „nic”).render@none


Zobacz też:

BalusC
źródło
Gdy używam update = "", właściwość zarządzana komponentu bean nie jest ustawiana, a moja procedura @PostConstruct kończy się niepowodzeniem. jakieś pomysły? EDYCJA: • Jeśli polegasz na właściwości zarządzanej # {param} obecnej w kolejnych żądaniach POST, musisz dołączyć ją jako <f: param> do składników UICommand.
K.Nicholas,
może proces / aktualizacja paneluGroup przetworzy / zaktualizuje zawartość tego paneluGroup np .: <h: panelGroup id = "pgId"> // tekst wejściowy idzie tutaj <h: panelGroup> <p: commandLink process = "pgId" aktualizacja = "pgId" />
bob-cac
Dziękuję @BalusC za to bardzo miłe wytłumaczenie!
ProgrammingIsAwsome
2
@Rapster: ponieważ processnie jest ustawione, więc używa domyślnej wartości @form. Jest to również wyjaśnione w powyższej odpowiedzi.
BalusC
2
@Roland: ukrywa inny, poważniejszy problem z konfiguracją aplikacji.
BalusC
54

Jeśli masz trudności z zapamiętaniem wartości domyślnych (wiem, że mam ...), oto krótki fragment odpowiedzi BalusC:

Komponent | Prześlij | Odświeżać
------------ | --------------- | --------------
f: ajax | execute = "@ this" | render = "@ none"
p: ajax | process = "@ this" | update = „@ none”
p: polecenieXXX | proces = "@ formularz" | update = „@ none”
Jaqen H'ghar
źródło
Drobna korekta: wartość domyślna processdla p:commandXXXto @all. Ponadto wydaje się, że dotyczy to każdego komponentu obsługującego AJAX, takiego jakp:menuitem .
Stephan Rauh
1
Cześć @StephanRauh, wielkie dzięki za komentarz. Gdzie przeczytałeś, że domyślna jest @all? O ile mogę przeczytać odpowiedź BalusC, jest to@form jednak @allrównoważne z @formprocesem. Dobra uwaga na temat innych komponentów, myślę, że będę musiał zajrzeć do kodu źródłowego, aby zobaczyć, do których komponentów się odnosi, ponieważ wolałbym nie pisać czegoś, co może być złe
Jaqen H'ghar
1
@ JaqenH'ghar Thomas Andraschko powiedział mi o tym @allkawałku. Musi wiedzieć, że niedawno ponownie wdrożył silnik AJAX PrimeFaces. Później dwukrotnie go sprawdziłem, ale czytałem kod źródłowy PrimeFaces i sprawdziłem żądania XHR. Mam nadzieję, że tym razem mam rację, ponieważ zaimplementowałem żądania AJAX BootsFaces, aby działały identycznie jak żądania AJAX PrimeFaces.
Stephan Rauh
Byłoby mylące stwierdzenie, że wartością domyślną jest @ all, gdy HTML nie obsługuje przesyłania wielu formularzy. Programiści muszą znać efektywną wartość domyślną (aby Thomas mógł ją odpowiednio zmienić). Nawiasem mówiąc, te wartości domyślne są niepoprawnie zdefiniowane jako null w Podręczniku użytkownika Primefaces 6.2.
Marc Dzaebel,
27

Poprzez proces (w specyfikacji JSF nazywa się to execute) mówisz JSF, aby ograniczyło przetwarzanie do określonego komponentu, wszystko inne jest po prostu ignorowane.

Aktualizacja wskazuje, który element zostanie zaktualizowany, gdy serwer odpowie na Twoje żądanie.

@all : Każdy komponent jest przetwarzany / renderowany.

@this : Żądany komponent z atrybutem wykonania jest przetwarzany / renderowany.

@form : Formularz zawierający żądający komponent jest przetwarzany / renderowany.

@ rodzic: Element nadrzędny zawierający żądający komponent jest przetwarzany / renderowany.

Dzięki Primefaces możesz nawet używać selektorów JQuery, sprawdź tego bloga: http://blog.primefaces.org/?p=1867

faissalb
źródło
2

Pamiętaj, że PrimeFaces obsługuje standardowe słowa kluczowe JSF 2.0+:

  • @this Aktualny składnik.
  • @all Cały widok.
  • @form Najbliższa forma przodka bieżącego komponentu.
  • @none Bez komponentu.

oraz standardowe słowa kluczowe JSF 2.3+:

  • @child(n) n-te dziecko.
  • @composite Najbliższy przodek komponentu kompozytowego.
  • @id(id) Służy do wyszukiwania komponentów według ich identyfikatora, ignorując strukturę drzewa komponentów i nazywając kontenery.
  • @namingcontainer Najbliższy kontener nazewnictwa przodka bieżącego komponentu.
  • @parent Nadrzędny bieżącego komponentu.
  • @previous Poprzednie rodzeństwo.
  • @next Następne rodzeństwo.
  • @root Instancji UIViewRoot widoku można użyć do rozpoczęcia wyszukiwania od katalogu głównego zamiast bieżącego komponentu.

Ale zawiera także niektóre słowa kluczowe specyficzne dla PrimeFaces:

  • @row(n) n-ty rząd.
  • @widgetVar(name) Komponent z podanym widgetVar.

I możesz nawet użyć czegoś o nazwie „PrimeFaces Selectors”, co pozwala na użycie jQuery Selector API. Na przykład, aby przetworzyć wszystkie dane wejściowe w elemencie z klasą CSS myClass:

process="@(.myClass :input)"

Widzieć:

Jasper de Vries
źródło
2
Pamiętaj, że nawet JSF2.3 + obsługuje większość słów kluczowych.
tandraschko