Memahami proses / pembaruan PrimeFaces dan atribut JSF f: ajax execute / render

193

Apa sebenarnya yang processdan updatedi PrimeFaces p:commandXxxkomponen dan executedan renderdi f:ajaxtag?

Yang berfungsi saat validasi? Apa yang dilakukan updateatribut daripada memperbarui nilai ke komponen dari ujung belakang? Apakah processatribut mengikat nilai ke model? Apa sebenarnya yang @this, @parent, @alldan @formdi kedua atribut?

Contoh di bawah ini berfungsi dengan baik, tetapi saya sedikit bingung dalam konsep dasar.

<p:commandButton process="@parent"
                 update="@form"
                 action="#{bean.submit}" 
                 value="Submit" />
Shardendu
sumber

Jawaban:

306

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

The processatribut sisi server dan hanya dapat mempengaruhi UIComponents menerapkan EditableValueHolder(bidang input) atau ActionSource(bidang perintah). The processatribut memberitahu JSF, menggunakan daftar dipisahkan dengan spasi dari ID klien, yang komponen persis harus diproses melalui seluruh siklus hidup JSF pada (parsial) bentuk kirimkan.

JSF kemudian akan menerapkan nilai-nilai permintaan (menemukan parameter permintaan HTTP berdasarkan pada ID klien komponen itu sendiri dan kemudian mengaturnya sebagai nilai yang diajukan dalam kasus EditableValueHolderkomponen atau mengantri yang baru ActionEventdalam kasus ActionSourcekomponen), melakukan konversi, validasi, dan memperbarui nilai-nilai model ( EditableValueHolderhanya komponen) dan akhirnya meminta antrian ActionEvent( ActionSourcehanya komponen). JSF akan melewati pemrosesan semua komponen lain yang tidak tercakup oleh processatribut. Selain itu, komponen yang renderedatributnya dievaluasi falseselama fase nilai permintaan yang berlaku juga akan dilewati sebagai bagian dari perlindungan terhadap permintaan yang dirusak.

Perhatikan bahwa dalam kasus ActionSourcekomponen (seperti <p:commandButton>) sangat penting bahwa Anda juga memasukkan komponen itu sendiri dalam processatribut, terutama jika Anda bermaksud untuk meminta tindakan yang terkait dengan komponen. Jadi contoh di bawah ini yang bermaksud memproses hanya komponen input tertentu ketika komponen perintah tertentu dipanggil tidak akan berfungsi:

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

Itu hanya akan memproses #{bean.foo}dan tidak yang #{bean.action}. Anda juga perlu memasukkan komponen perintah:

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

Atau, seperti yang Anda ketahui, menggunakan @parentjika mereka merupakan satu-satunya komponen yang memiliki orang tua yang sama:

<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>

Atau, jika keduanya merupakan satu-satunya komponen komponen induk UIForm, maka Anda juga dapat menggunakan @form:

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

Ini kadang-kadang tidak diinginkan jika formulir berisi lebih banyak komponen input yang ingin Anda lewati dalam proses, lebih sering jika Anda ingin memperbarui komponen input lain atau beberapa bagian UI berdasarkan komponen input saat ini di metode pendengar ajax. Anda tidak ingin kesalahan validasi pada komponen input lainnya mencegah metode pendengar ajax dieksekusi.

Lalu ada @all. Ini tidak memiliki efek khusus pada processatribut, tetapi hanya pada updateatribut. A process="@all"berperilaku persis sama dengan process="@form". Lagipula HTML tidak mendukung pengiriman beberapa formulir sekaligus.

Ngomong-ngomong ada juga @noneyang mungkin berguna jika Anda benar-benar tidak perlu memproses apa pun, tetapi hanya ingin memperbarui beberapa bagian tertentu melalui update, terutama bagian-bagian yang isinya tidak bergantung pada nilai yang dikirimkan atau pendengar tindakan.

Perlu dicatat bahwa processatribut tidak berpengaruh pada payload permintaan HTTP (jumlah parameter permintaan). Artinya, perilaku HTML default mengirim "semuanya" yang terkandung dalam representasi HTML <h:form>tidak akan terpengaruh. Jika Anda memiliki formulir besar, dan ingin mengurangi payload permintaan HTTP hanya untuk ini yang benar-benar diperlukan dalam pemrosesan, yaitu hanya ini yang dicakup oleh processatribut, maka Anda dapat mengatur partialSubmitatribut dalam komponen PrimeFaces Ajax seperti pada <p:commandXxx ... partialSubmit="true">atau <p:ajax ... partialSubmit="true">. Anda juga dapat mengonfigurasi ini 'secara global' dengan mengedit web.xmldan menambahkan

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

Sebagai alternatif, Anda juga dapat menggunakan <o:form>OmniFaces 3.0+ yang menjadi default untuk perilaku ini.

Standar JSF setara dengan PrimeFaces tertentu processadalah executedari <f:ajax execute>. Berperilaku sama persis kecuali bahwa itu tidak mendukung string yang dipisahkan koma sedangkan yang PrimeFaces tidak (meskipun saya pribadi merekomendasikan untuk hanya tetap pada konvensi yang dipisahkan ruang), atau @parentkata kunci. Juga, mungkin berguna untuk mengetahui bahwa <p:commandXxx process>default untuk @formsementara <p:ajax process>dan <f:ajax execute>default untuk @this. Akhirnya, penting juga untuk mengetahui bahwa processmendukung apa yang disebut "PrimeFaces Selectors", lihat juga Bagaimana PrimeFaces Selectors seperti dalam pembaruan = "@ (. MyClass)" berfungsi?


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

The updateatribut sisi klien dan dapat mempengaruhi representasi HTML dari semua UIComponents. The updateatribut memberitahu JavaScript (yang bertanggung jawab untuk menangani ajax permintaan / tanggapan), menggunakan daftar dipisahkan dengan spasi dari ID klien, yang bagian dalam HTML DOM kebutuhan pohon diperbarui sebagai respon terhadap bentuk kirimkan.

JSF kemudian akan menyiapkan respons ajax yang tepat untuk itu, hanya berisi bagian yang diminta untuk diperbarui. JSF akan melewati semua komponen lain yang tidak tercakup oleh updateatribut dalam respons ajax, dengan ini menjaga agar muatan respons tetap kecil. Juga, komponen yang renderedatributnya dievaluasi falseselama fase respons render akan dilewati. Perhatikan bahwa meskipun akan kembali true, JavaScript tidak dapat memperbaruinya di pohon DOM HTML jika awalnya false. Anda harus membungkusnya atau memperbarui induknya. Lihat juga pembaruan / render Ajax tidak berfungsi pada komponen yang telah memberikan atribut .

Biasanya, Anda ingin memperbarui hanya komponen yang benar - benar perlu "di-refresh" di sisi klien setelah pengiriman (sebagian) formulir. Contoh di bawah ini memperbarui seluruh formulir induk melalui @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>

(perhatikan bahwa processatribut dihilangkan karena @formsudah default untuk )

Sementara itu mungkin berfungsi dengan baik, pembaruan komponen input dan perintah dalam contoh khusus ini tidak perlu. Kecuali Anda mengubah nilai foo- nilai model dan metode bardi dalam action(yang pada gilirannya tidak intuitif dalam perspektif UX), tidak ada gunanya memperbarui mereka. Komponen pesan adalah satu-satunya yang benar - benar perlu diperbarui:

<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>

Namun, itu membosankan ketika Anda memiliki banyak dari mereka. Itulah salah satu alasan mengapa Penyeleksi PrimeFaces ada. Komponen-komponen pesan itu memiliki dalam output HTML yang dihasilkan kelas gaya umum ui-message, jadi yang berikut ini juga harus dilakukan:

<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>

(perhatikan bahwa Anda harus menyimpan ID pada komponen pesan, jika @(...)tidak tidak akan berfungsi! Sekali lagi, lihat Bagaimana Penyeleksi PrimeFaces seperti pada pembaruan = "@ (.Class)" berfungsi? untuk detail)

The @parentupdate hanya komponen orangtua, yang dengan demikian meliputi komponen saat ini dan semua saudara dan anak-anak mereka. Ini lebih berguna jika Anda telah memisahkan formulir dalam kelompok waras dengan masing-masing tanggung jawabnya sendiri. The @thisupdate, jelas, hanya komponen saat ini. Biasanya, ini hanya diperlukan ketika Anda perlu mengubah salah satu atribut HTML komponen dalam metode tindakan. Misalnya

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

Bayangkan bahwa oncompletekebutuhan untuk bekerja dengan valueyang diubah action, maka konstruksi ini tidak akan berfungsi jika komponen tidak diperbarui, karena alasan sederhana yang oncompletemerupakan bagian dari output HTML yang dihasilkan (dan dengan demikian semua ekspresi EL di sana dievaluasi selama tanggapan render).

The @allupdate seluruh dokumen, yang harus digunakan dengan hati-hati. Biasanya, Anda ingin menggunakan permintaan GET yang sebenarnya untuk ini sebagai gantinya dengan tautan biasa ( <a>atau <h:link>) atau redirect-setelah-POST oleh ?faces-redirect=trueatau ExternalContext#redirect(). Efeknya, process="@form" update="@all"memiliki efek yang persis sama dengan pengiriman non-ajax (non-parsial). Dalam seluruh karir JSF saya, satu-satunya kasus penggunaan yang masuk akal yang saya temui @alladalah untuk menampilkan halaman kesalahan secara keseluruhan jika terjadi pengecualian selama permintaan ajax. Lihat juga Apa cara yang benar untuk menangani pengecualian JSF 2.0 untuk komponen AJAXified?

Standar JSF setara dengan PrimeFaces tertentu updateadalah renderdari <f:ajax render>. Berperilaku sama persis kecuali bahwa itu tidak mendukung string yang dipisahkan koma sedangkan yang PrimeFaces tidak (meskipun saya pribadi merekomendasikan untuk hanya tetap pada konvensi yang dipisahkan ruang), atau @parentkata kunci. Baik updatedan renderdefault ke @none(yaitu, "tidak ada").


Lihat juga:

BalusC
sumber
Ketika saya menggunakan pembaruan = "" maka properti yang dikelola dari kacang dukungan tidak mendapatkan pengaturan dan rutin @PostConstruct saya gagal. Adakah pikiran? EDIT: • Jika Anda mengandalkan properti terkelola # {param} yang ada dalam permintaan POST berikutnya, maka Anda harus memasukkannya sebagai <f: param> dalam komponen perintah UIC.
K.Nicholas
semoga proses / pembaruan panelGroup akan memproses / memperbarui konten panelGroup ini ex: <h: panelGroup id = "pgId"> // teks input masuk ke sini <h: panelGroup> <p: commandLink process = "pgId" pembaruan = "pgId" />
bob-cac
Terima kasih @BalusC untuk penjelasan yang sangat bagus ini!
ProgrammingIsAwsome
2
@ Rapster: karena processtidak disetel, sehingga menggunakan nilai default @form. Ini juga dijelaskan dalam jawaban di atas.
BalusC
2
@Roland: menyembunyikan masalah konfigurasi aplikasi yang lebih serius, lebih serius.
BalusC
54

Jika Anda kesulitan mengingat nilai default (saya tahu saya punya ...) berikut ini kutipan singkat dari jawaban BalusC:

Komponen | Kirim | Menyegarkan
------------ | --------------- | --------------
f: ajax | mengeksekusi = "@ ini" | | render = "@ none"
p: ajax | process = "@ this" | update = "@ none"
p: commandXXX | process = "@ form" | update = "@ none"
Jaqen H'ghar
sumber
Hanya koreksi kecil: nilai default processuntuk p:commandXXXadalah @all. Plus, ini tampaknya berlaku untuk setiap komponen yang mendukung AJAX, seperti p:menuitem.
Stephan Rauh
1
Hai @StephanRauh, terima kasih banyak atas komentarnya. Di mana Anda membaca defaultnya @all? Sejauh yang saya bisa baca dari BalusC jawaban itu @form, namun @allsetara dengan yang sedang @formdalam proses. Poin bagus tentang komponen lain, saya kira saya harus melihat dalam kode sumber kapan waktunya untuk melihat komponen apa yang berlaku, karena saya lebih suka tidak menulis sesuatu yang mungkin salah
Jaqen H'ghar
1
@ JaqenH'ghar Thomas Andraschko memberi tahu saya tentang @allbit. Dia harus tahu, dia kembali menerapkan mesin AJAX dari PrimeFaces baru-baru ini. Kemudian, saya mengeceknya tetapi membaca kode sumber PrimeFaces dan dengan melihat permintaan XHR. Saya harap saya sudah benar kali ini karena saya sudah mengimplementasikan permintaan AJAX dari BootsFaces untuk bekerja secara identik dengan permintaan AJAX dari PrimeFaces.
Stephan Rauh
Akan menyesatkan untuk mengatakan, bahwa defaultnya adalah @all ketika HTML tidak mendukung pengiriman beberapa bentuk. Pengembang perlu mengetahui nilai default yang efektif (sehingga Thomas mungkin mengubahnya sesuai). Omong-omong, standar-standar ini secara keliru didefinisikan sebagai null dalam Panduan Pengguna Primefaces 6.2.
Marc Dzaebel
27

Dengan proses (dalam spesifikasi JSF itu disebut mengeksekusi) Anda memberitahu JSF untuk membatasi pemrosesan ke komponen yang ditentukan setiap hal lain hanya diabaikan.

pembaruan menunjukkan elemen mana yang akan diperbarui ketika server merespons kembali permintaan Anda.

@all : Setiap komponen diproses / dirender.

@ini : Komponen yang meminta dengan atribut eksekusi diproses / dirender.

@form : Formulir yang berisi komponen yang diminta diproses / dirender.

@ orangtua: Orang tua yang berisi komponen yang meminta diproses / dirender.

Dengan Primefaces Anda bahkan dapat menggunakan penyeleksi JQuery, lihat blog ini: http://blog.primefaces.org/?p=1867

faissalb
sumber
2

Harap perhatikan bahwa PrimeFaces mendukung kata kunci JSF 2.0+ standar:

  • @this Komponen saat ini.
  • @all Seluruh tampilan.
  • @form Bentuk leluhur terdekat dari komponen saat ini.
  • @none Tidak ada komponen

dan kata kunci JSF 2.3+ standar:

  • @child(n) anak ke-n.
  • @composite Nenek moyang komponen komposit terdekat.
  • @id(id) Digunakan untuk mencari komponen dengan id mereka mengabaikan struktur pohon komponen dan penamaan kontainer.
  • @namingcontainer Wadah penamaan leluhur terdekat dari komponen saat ini.
  • @parent Induk komponen saat ini.
  • @previous Saudara sebelumnya.
  • @next Saudara berikutnya
  • @root Contoh tampilan UIViewRoot, dapat digunakan untuk mulai mencari dari root bukan komponen saat ini.

Tetapi, ia juga dilengkapi dengan beberapa kata kunci spesifik PrimeFaces:

  • @row(n) baris ke-n.
  • @widgetVar(name) Komponen dengan widgetVar yang diberikan.

Dan Anda bahkan dapat menggunakan sesuatu yang disebut "PrimeFaces Selectors" yang memungkinkan Anda untuk menggunakan API Pemilih jQuery. Misalnya untuk memproses semua input dalam elemen dengan kelas CSS myClass:

process="@(.myClass :input)"

Lihat:

Jasper de Vries
sumber
2
Perhatikan bahwa bahkan JSF2.3 + mendukung sebagian besar kata kunci.
tandraschko