Di valueChangeListener
chúc chỉ được gọi khi biểu mẫu được gửi và giá trị đã gửi khác với giá trị ban đầu. Do đó, nó không được gọi khi chỉchange
sự kiện HTML DOM được kích hoạt. Nếu bạn muốn gửi biểu mẫu trong change
sự kiện HTML DOM , thì bạn cần thêm một biểu mẫu khác <f:ajax/>
không có trình xử lý (!) Vào thành phần đầu vào. Nó sẽ tạo ra một biểu mẫu gửi chỉ xử lý thành phần hiện tại (như trong execute="@this"
).
<h:selectOneMenu value="#{bean.value}" valueChangeListener="#{bean.changeListener}">
<f:selectItems ... />
<f:ajax />
</h:selectOneMenu>
Khi sử dụng <f:ajax listener>
thay vì valueChangeListener
, nó sẽ được thực thi theo mặc định trong change
sự kiện HTML DOM . Các UICommand
thành phần bên trong và các thành phần đầu vào đại diện cho một hộp kiểm hoặc nút radio, nó sẽ được thực thi theo mặc định chỉ trong click
sự kiện HTML DOM .
<h:selectOneMenu value="#{bean.value}">
<f:selectItems ... />
<f:ajax listener="#{bean.ajaxListener}" />
</h:selectOneMenu>
Một sự khác biệt lớn khác là valueChangeListener
phương thức được gọi trong thời gian cuối của PROCESS_VALIDATIONS
giai đoạn. Tại thời điểm đó, giá trị đã gửi chưa được cập nhật trong mô hình. Vì vậy, bạn không thể lấy nó bằng cách chỉ truy cập thuộc tính bean được liên kết với thành phần đầu vào value
. Bạn cần phải có được nó bằng cách ValueChangeEvent#getNewValue()
. Giá trị cũ bằng cách này cũng có sẵn bởi ValueChangeEvent#getOldValue()
.
public void changeListener(ValueChangeEvent event) {
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
}
Các <f:ajax listener>
phương pháp được gọi trong INVOKE_APPLICATION
giai đoạn. Tại thời điểm đó, giá trị đã gửi đã được cập nhật trong mô hình. Bạn chỉ có thể lấy nó bằng cách truy cập trực tiếp vào thuộc tính bean được liên kết với thành phần đầu vào value
.
private Object value;
public void ajaxListener(AjaxBehaviorEvent event) {
System.out.println(value);
}
Ngoài ra, nếu bạn cần cập nhật một thuộc tính khác dựa trên giá trị đã gửi, thì nó sẽ không thành công khi bạn đang sử dụng valueChangeListener
vì thuộc tính cập nhật có thể bị ghi đè bởi giá trị đã gửi trong UPDATE_MODEL_VALUES
giai đoạn tiếp theo . Đó chính xác là lý do tại sao bạn thấy trong các ứng dụng / hướng dẫn / tài nguyên JSF 1.x cũ mà a valueChangeListener
có trong cấu trúc như vậy được sử dụng kết hợp với immediate="true"
và FacesContext#renderResponse()
để ngăn điều đó xảy ra. Xét valueChangeListener
cho cùng , việc sử dụng để thực hiện các hành động kinh doanh thực sự luôn là một cách giải quyết / hack.
Tóm tắt: Chỉ sử dụng valueChangeListener
nếu bạn cần chặn trên chính sự thay đổi giá trị thực tế. Tức là bạn thực sự quan tâm đến cả giá trị cũ và giá trị mới (ví dụ: ghi lại chúng).
public void changeListener(ValueChangeEvent event) {
changeLogger.log(event.getOldValue(), event.getNewValue());
}
Chỉ sử dụng <f:ajax listener>
nếu bạn cần thực hiện một hành động kinh doanh trên giá trị mới được thay đổi. Tức là bạn đang thực sự quan tâm đến việc chỉ những giá trị mới (ví dụ để cư một danh sách thả xuống thứ hai).
public void ajaxListener(AjaxBehaviorEvent event) {
selectItemsOfSecondDropdown = populateItBasedOn(selectedValueOfFirstDropdown);
}
Nếu bạn thực sự cũng quan tâm đến giá trị cũ trong khi thực hiện một hành động kinh doanh, thì hãy quay trở lại valueChangeListener
, nhưng xếp nó vào INVOKE_APPLICATION
giai đoạn.
public void changeListener(ValueChangeEvent event) {
if (event.getPhaseId() != PhaseId.INVOKE_APPLICATION) {
event.setPhaseId(PhaseId.INVOKE_APPLICATION);
event.queue();
return;
}
Object oldValue = event.getOldValue();
Object newValue = event.getNewValue();
System.out.println(newValue.equals(value));
}
logger.trace( "setting changeTypes from {} to {}", this.changeTypes, changeTypes );
. Nó có vẻ như bạn có thể sử dụng các giá trị cũ và mới thu được trong thời trang đó để làm logic kinh doanh trực tiếp trong setter cũng như khai thác gỗ đơn giản, nhưng tôi không biết nếu điều này sẽ gây ra tác dụng phụ ...