Hiểu quy trình / cập nhật PrimeFaces và thuộc tính JSF f: ajax thực thi / kết xuất


193

Chính xác là gì processupdatetrong p:commandXxxcác thành phần PrimeFaces executerendertrong f:ajaxthẻ?

Mà hoạt động tại thời điểm xác nhận? Gì updatethuộc tính làm chứ không phải cập nhật giá trị cho thành phần từ back-end? Do processthuộc tính liên kết giá trị với mô hình? Chính xác những gì làm @this, @parent, @all@formtrong cả hai thuộc tính?

Ví dụ dưới đây đang hoạt động tốt, nhưng tôi hơi bối rối trong các khái niệm cơ bản.

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

Câu trả lời:


306

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

Các processthuộc tính là phía máy chủ và chỉ có thể ảnh hưởng đến UIComponents thực hiện EditableValueHolder(trường đầu vào) hoặc ActionSource(trường lệnh). Các processthuộc tính nói với JSF, sử dụng một danh sách không gian tách ID khách hàng, trong đó thành phần chính xác phải được xử lý thông qua toàn bộ vòng đời JSF thuận (một phần) hình thức nộp.

Sau đó, JSF sẽ áp dụng các giá trị yêu cầu (tìm tham số yêu cầu HTTP dựa trên ID khách hàng của thành phần và sau đó đặt nó làm giá trị đã gửi trong trường hợp EditableValueHolderthành phần hoặc xếp hàng mới ActionEventtrong trường hợp ActionSourcethành phần), thực hiện chuyển đổi, xác thực và cập nhật giá trị mô hình ( EditableValueHolderchỉ các thành phần) và cuối cùng gọi ra hàng đợi ActionEvent( ActionSourcechỉ các thành phần). JSF sẽ bỏ qua việc xử lý tất cả các thành phần khác không processthuộc tính. Ngoài ra, các thành phần có renderedthuộc tính ước tính falsetrong giai đoạn áp dụng giá trị yêu cầu cũng sẽ bị bỏ qua như một phần của biện pháp bảo vệ chống lại các yêu cầu giả mạo.

Lưu ý rằng trong trường hợp các ActionSourcethành phần (chẳng hạn <p:commandButton>) rất quan trọng, bạn cũng bao gồm chính thành phần đó trong processthuộc tính, đặc biệt nếu bạn có ý định gọi hành động liên quan đến thành phần đó. Vì vậy, ví dụ dưới đây dự định chỉ xử lý (các) thành phần đầu vào nhất định khi một thành phần lệnh nhất định được gọi sẽ không hoạt động:

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

Nó sẽ chỉ xử lý #{bean.foo}không sự #{bean.action}. Bạn cũng cần bao gồm chính thành phần lệnh:

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

Hoặc, như bạn rõ ràng đã phát hiện ra, sử dụng @parentnếu chúng là thành phần duy nhất có cha mẹ chung:

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

Hoặc, nếu cả hai tình cờ là thành phần duy nhất của UIFormthành phần cha mẹ , thì bạn cũng có thể sử dụng @form:

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

Điều này đôi khi không mong muốn nếu biểu mẫu chứa nhiều thành phần đầu vào mà bạn muốn bỏ qua trong quá trình xử lý, thường xuyên hơn trong trường hợp khi bạn muốn cập nhật (các) thành phần đầu vào khác hoặc một số giao diện người dùng dựa trên thành phần đầu vào hiện tại trong một phương pháp nghe ajax. Cụ thể là bạn không muốn các lỗi xác thực trên các thành phần đầu vào khác đang ngăn phương thức nghe ajax được thực thi.

Sau đó, có @all. Điều này không có tác dụng đặc biệt trong processthuộc tính, mà chỉ trong updatethuộc tính. Một process="@all"hành vi giống hệt như process="@form". HTML không hỗ trợ gửi nhiều biểu mẫu cùng một lúc.

Nhân tiện, cũng @nonecó thể hữu ích trong trường hợp bạn hoàn toàn không cần xử lý bất cứ điều gì, mà chỉ muốn cập nhật một số phần cụ thể thông qua update, đặc biệt là những phần có nội dung không phụ thuộc vào giá trị được gửi hoặc người nghe hành động.

Cần lưu ý rằng processthuộc tính không có ảnh hưởng đến tải trọng yêu cầu HTTP (số lượng tham số yêu cầu). Có nghĩa là, hành vi HTML mặc định gửi "mọi thứ" có trong biểu diễn HTML của <h:form>sẽ không bị ảnh hưởng. Trong trường hợp bạn có một biểu mẫu lớn và muốn giảm tải trọng yêu cầu HTTP xuống chỉ những điều này thực sự cần thiết trong xử lý, tức là chỉ những processthuộc tính này được bao phủ bởi thuộc tính, thì bạn có thể đặt partialSubmitthuộc tính trong các thành phần PrimeFaces Ajax như trong <p:commandXxx ... partialSubmit="true">hoặc <p:ajax ... partialSubmit="true">. Bạn cũng có thể định cấu hình 'toàn cầu' này bằng cách chỉnh sửa web.xmlvà thêm

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

Ngoài ra, bạn cũng có thể sử dụng <o:form>OmniFaces 3.0+, mặc định cho hành vi này.

JSF tiêu chuẩn tương đương với PrimeFaces cụ thể processexecutetừ <f:ajax execute>. Nó hoạt động giống hệt nhau ngoại trừ việc nó không hỗ trợ chuỗi được phân tách bằng dấu phẩy trong khi PrimeFaces thực hiện (mặc dù cá nhân tôi khuyên bạn chỉ nên sử dụng quy ước được phân tách bằng dấu cách), cũng không phải @parenttừ khóa. Ngoài ra, có thể hữu ích khi biết rằng <p:commandXxx process>mặc định @formtrong khi <p:ajax process><f:ajax execute>mặc định là @this. Cuối cùng, cũng hữu ích khi biết rằng processhỗ trợ cái gọi là "Bộ chọn PrimeFaces", xem thêm Bộ chọn PrimeFaces như trong update = "@ (. MyClass)" hoạt động như thế nào?


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

Các updatethuộc tính là phía khách hàng và có thể ảnh hưởng đến các đại diện HTML của tất cả các UIComponents. Các updatethuộc tính nói với JavaScript (một trong những trách nhiệm xử lý các yêu cầu ajax / response), sử dụng một danh sách không gian tách ID khách hàng, phần nào trong cây cần HTML DOM để được cập nhật khi đối phó với các hình thức nộp.

Sau đó, JSF sẽ chuẩn bị phản hồi ajax đúng cho điều đó, chỉ chứa các phần được yêu cầu để cập nhật. JSF sẽ bỏ qua tất cả các thành phần khác không được updatethuộc tính trong phản hồi ajax, theo đó giữ cho trọng tải phản hồi nhỏ. Ngoài ra, các thành phần có renderedthuộc tính ước tính falsetrong giai đoạn phản hồi kết xuất sẽ bị bỏ qua. Lưu ý rằng ngay cả khi nó trả về true, JavaScript không thể cập nhật nó trong cây DOM HTML nếu ban đầu false. Thay vào đó, bạn cần phải bọc nó hoặc cập nhật cha mẹ của nó. Xem thêm Cập nhật / kết xuất Ajax không hoạt động trên một thành phần có thuộc tính kết xuất .

Thông thường, bạn muốn cập nhật chỉ những thành phần mà thực sự cần phải được "làm mới" ở phía client trên (một phần) hình thức nộp. Ví dụ dưới đây cập nhật toàn bộ biểu mẫu gốc thông qua @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>

(lưu ý rằng processthuộc tính được bỏ qua vì mặc định @formđã có)

Trong khi điều đó có thể hoạt động tốt, việc cập nhật các thành phần đầu vào và lệnh trong ví dụ cụ thể này là không cần thiết. Trừ khi bạn thay đổi các giá trị mô hình foovà phương thức barbên trong action(điều này sẽ không trực quan trong phối cảnh UX), không có điểm nào cập nhật chúng. Các thành phần thông báo là thứ duy nhất thực sự cần được cập nhật:

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

Tuy nhiên, điều đó trở nên tẻ nhạt khi bạn có nhiều người trong số họ. Đó là một trong những lý do khiến PrimeFaces Selector tồn tại. Các thành phần thông báo này có trong đầu ra HTML được tạo một lớp kiểu chung ui-message, do đó, những điều sau đây cũng nên làm:

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

(lưu ý rằng bạn nên giữ ID trên các thành phần thông báo, nếu không @(...)sẽ không hoạt động! Một lần nữa, hãy xem Cách chọn PrimeFaces như trong update = "@ (. myClass)" để biết chi tiết)

Các @parentbản cập nhật chỉ có thành phần cha mẹ, do đó bao gồm thành phần hiện tại và tất cả anh chị em và con cái của họ. Điều này hữu ích hơn nếu bạn đã tách biểu mẫu trong các nhóm lành mạnh với mỗi trách nhiệm riêng của mình. Các @thisbản cập nhật, rõ ràng, chỉ có thành phần hiện tại. Thông thường, điều này chỉ cần thiết khi bạn cần thay đổi một trong các thuộc tính HTML của chính thành phần trong phương thức hành động. Ví dụ

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

Hãy tưởng tượng rằng các oncompletenhu cầu để làm việc với cái valueđã được thay đổi action, thì cấu trúc này sẽ không hoạt động nếu thành phần không được cập nhật, vì lý do đơn giản oncompletelà một phần của đầu ra HTML được tạo (và do đó tất cả các biểu thức EL trong đó được đánh giá trong quá trình trả lời kết xuất).

Các @allcập nhật toàn bộ tài liệu, cần được sử dụng cẩn thận. Thông thường, bạn muốn sử dụng một yêu cầu GET thực sự cho việc này thay vì bằng một liên kết đơn giản ( <a>hoặc <h:link>) hoặc chuyển hướng sau khi POST bằng ?faces-redirect=truehoặc ExternalContext#redirect(). Trong các hiệu ứng, process="@form" update="@all"có chính xác hiệu ứng tương tự như một lần gửi không phải là ajax (không phải một phần). Trong toàn bộ sự nghiệp JSF của tôi, trường hợp sử dụng hợp lý duy nhất tôi gặp phải @alllà hiển thị toàn bộ trang lỗi trong trường hợp có ngoại lệ xảy ra trong yêu cầu ajax. Xem thêm Cách chính xác để xử lý các ngoại lệ JSF 2.0 cho các thành phần AJAXified là gì?

JSF tiêu chuẩn tương đương với PrimeFaces cụ thể updaterendertừ <f:ajax render>. Nó hoạt động giống hệt nhau ngoại trừ việc nó không hỗ trợ chuỗi được phân tách bằng dấu phẩy trong khi PrimeFaces thực hiện (mặc dù cá nhân tôi khuyên bạn chỉ nên sử dụng quy ước được phân tách bằng dấu cách), cũng không phải @parenttừ khóa. Cả hai updaterendermặc định là @none(không có gì ").


Xem thêm:


Khi tôi sử dụng update = "" thì thuộc tính được quản lý của bean hậu thuẫn không được thiết lập và thói quen @PostConstruct của tôi không thành công. Có suy nghĩ gì không? EDIT: • Nếu bạn dựa vào thuộc tính được quản lý của # {param} có mặt trong các yêu cầu POST tiếp theo, thì bạn cần đưa nó dưới dạng <f: param> vào các thành phần UICommand.
K.Nicholas

có thể một quá trình / cập nhật của panelgroup sẽ xử lý / cập nhật nội dung của panelgroup này ex: <h: panelgroup id = "pgId"> // văn bản đầu vào ở đây <h: panelgroup> <p: CommandLink process = "pgId" update = "pgId" />
bob-cac

Thx @BalusC cho lời giải thích rất hay này!
Lập

2
@Rapster: vì processkhông được đặt, nên nó sử dụng giá trị mặc định là @form. Điều này cũng được giải thích trong câu trả lời ở trên.
BalusC

2
@Roland: nó ẩn một vấn đề khác, nghiêm trọng hơn với cấu hình ứng dụng.
BalusC

54

Nếu bạn gặp khó khăn trong việc ghi nhớ các giá trị mặc định (tôi biết tôi có ...) thì đây là một đoạn trích ngắn từ câu trả lời của BalusC:

Thành phần | Gửi | Làm tươi
------------ | --------------- | --------------
f: ajax | thực hiện = "@ này" | kết xuất = "@ không"
p: ajax | process = "@ này" | cập nhật = "@ không"
p: lệnhXXX | process = "@ form" | cập nhật = "@ không"

Chỉ cần một điều chỉnh nhỏ: giá trị mặc định của processfor p:commandXXX@all. Thêm vào đó, điều này dường như áp dụng cho mọi thành phần hỗ trợ AJAX, chẳng hạn như p:menuitem.
Stephan Rauh

1
Xin chào @StephanRauh, cảm ơn rất nhiều vì đã bình luận. Bạn đã đọc mặc định ở @allđâu? Theo như tôi có thể đọc từ câu trả lời của BalusC @form, tuy nhiên @allnó tương đương với @formtrong quá trình. Điểm hay về các thành phần khác, tôi đoán tôi sẽ phải xem mã nguồn khi có thời gian để xem nó áp dụng thành phần nào, vì tôi không muốn viết một cái gì đó có thể sai
Jaqen H'ghar

1
@ JaqenH'ghar Thomas Andraschko nói với tôi về @allbit. Anh ta phải biết, anh ta đã triển khai lại công cụ AJAX của PrimeFaces gần đây. Sau đó, tôi đã kiểm tra lại nhưng đọc mã nguồn của PrimeFaces và xem các yêu cầu XHR. Tôi hy vọng tôi đã hiểu đúng lúc này vì tôi đã triển khai các yêu cầu AJAX của BootsFaces để hoạt động giống hệt với các yêu cầu AJAX của PrimeFaces.
Stephan Rauh

Sẽ là sai lầm khi nói rằng, mặc định là @all khi HTML không hỗ trợ gửi nhiều biểu mẫu. Các nhà phát triển cần biết giá trị mặc định hiệu quả (vì vậy Thomas có thể thay đổi nó cho phù hợp). Nhân tiện, các mặc định này được xác định không chính xác là null trong Hướng dẫn sử dụng Primefaces 6.2.
Marc Dzaebel

27

Theo quy trình (trong đặc tả của JSF, nó được gọi là thực thi), bạn nói với JSF để giới hạn việc xử lý thành phần được chỉ định, mọi thứ khác chỉ bị bỏ qua.

Cập nhật cho biết phần tử nào sẽ được cập nhật khi máy chủ phản hồi lại yêu cầu của bạn.

@all : Mọi thành phần đều được xử lý / kết xuất.

@this : Thành phần yêu cầu với thuộc tính thực thi được xử lý / kết xuất.

@form : Biểu mẫu chứa thành phần yêu cầu được xử lý / kết xuất.

@parent : Cha mẹ chứa thành phần yêu cầu được xử lý / kết xuất.

Với Primefaces, bạn thậm chí có thể sử dụng các bộ chọn JQuery, hãy xem blog này: http://blog.primefaces.org/?p=1867


2

Xin lưu ý rằng PrimeFaces hỗ trợ các từ khóa JSF 2.0+ tiêu chuẩn:

  • @this Thành phần hiện tại.
  • @all Toàn cảnh.
  • @form Hình thức tổ tiên gần nhất của thành phần hiện tại.
  • @none Không có thành phần.

và các từ khóa JSF 2.3+ tiêu chuẩn:

  • @child(n) con thứ n.
  • @composite Tổ tiên thành phần tổng hợp gần nhất.
  • @id(id) Được sử dụng để tìm kiếm các thành phần bởi id của chúng bỏ qua cấu trúc cây thành phần và các thùng chứa đặt tên.
  • @namingcontainer Container đặt tên tổ tiên gần nhất của thành phần hiện tại.
  • @parent Cha mẹ của thành phần hiện tại.
  • @previous Anh chị trước.
  • @next Anh chị tiếp theo.
  • @root Ví dụ UIViewRoot của chế độ xem, có thể được sử dụng để bắt đầu tìm kiếm từ thư mục gốc thay vì thành phần hiện tại.

Nhưng, nó cũng đi kèm với một số từ khóa cụ thể của PrimeFaces:

  • @row(n) hàng thứ n.
  • @widgetVar(name) Thành phần với widgetVar đã cho.

Và thậm chí bạn có thể sử dụng thứ gọi là "Bộ chọn PrimeFaces" cho phép bạn sử dụng API Selector API. Ví dụ để xử lý tất cả các đầu vào trong một phần tử với lớp CSS myClass:

process="@(.myClass :input)"

Xem:


2
Lưu ý rằng ngay cả JSF2.3 + cũng hỗ trợ hầu hết các từ khóa.
tandraschko
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.