В моем предыдущем посте я упомянул типичный случай использования, когда нам нужно программно проверить, является ли текущая транзакция грязной, и уведомить пользователя об этом, прежде чем что-то делать. Например: «У вас есть несохраненные изменения, которые будут потеряны, вы хотите продолжить?».
Предположим, что нам нужно уведомить пользователя о грязных транзакциях во многих местах приложения, при переходе от одного представления к другому, при нажатии кнопки «Поиск», при вызове метода бизнес-службы и т. Д. Итак, в каждом отдельном сценарии нам нужно выполнить разные вещи после того, как пользователь подтверждает, что он хочет продолжить. Это означает, что наш слушатель диалога должен каким-то образом знать, о чем идет речь и что делать дальше.
Решением может быть добавление пользовательского атрибута к компоненту af: dialog, указывающего на функцию, которая будет вызываться, когда пользователь нажимает «Да» в диалоговом окне:
01
02
03
04
05
06
07
08
09
10
11
|
< af:popup id = "pDirtyTransaction" contentDelivery = "lazyUncached" > < af:dialog title = "Warning" type = "yesNo" closeIconVisible = "false" id = "dDirtyTransaction" dialogListener = "#{theBean.dirtyTransactionDialogListener}" > < af:outputText value = "You have unsaved changes, do you want to continue?" id = "ot1" /> < f:attribute name = "dialogHandler" value = "" /> </ af:dialog > </ af:popup > |
В этом случае слушатель диалога может выглядеть так:
1
2
3
4
5
6
7
8
|
public void dirtyTransactionDialogListener(DialogEvent dialogEvent) { Map attrs = dialogEvent.getComponent().getAttributes(); Consumer<Boolean> dialogHandler = (Consumer) attrs.get( "dialogHandler" ); if (dialogHandler != null ) { dialogHandler.accept(dialogEvent.getOutcome() == DialogEvent.Outcome.yes); attrs.put( "dialogHandler" , null ); } } |
Здесь мы ожидаем, что атрибут dialogHandler указывает на объект, реализующий функциональный интерфейс Consumer .
В наших утилитах есть метод, показывающий всплывающее окно с диалогом:
01
02
03
04
05
06
07
08
09
10
|
public static void showDirtyTransactionPopup(Consumer dialogHandler) { if (dialogHandler != null ) { JSFUtil.findComponent( "dDirtyTransaction" ).getAttributes(). put( "dialogHandler" ,dialogHandler); } RichPopup popup = (RichPopup) JSFUtil.findComponent( "pDirtyTransaction" ); popup.show( new RichPopup.PopupHints()); } |
Давайте использовать этот подход в простом сценарии. В нашем потоке задач View1 и View2 есть два вида деятельности. Пользователь нажимает кнопку для перехода от одного вида к другому. Во время навигации нам нужно проверить, не является ли текущая транзакция грязной, и спросить пользователя, хотят ли они продолжить. Мы можем использовать мощь лямбда-выражений Java 8 и реализовать слушатель действия кнопки следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
public void buttonActionListener(ActionEvent actionEvent) { if (Utils.isTransactionDirty()) { Utils.showDirtyTransactionPopup((yesOutcome) -> { //the code below will be invoked by the dialog listener //when the user clicks a button on the dialog if ((Boolean) yesOutcome) { //the user has agreed to proceed, //so let's rollback the current transaction Utils.getCurrentRootDataControl().rollbackTransaction(); //and queue an action event for this button again new ActionEvent(actionEvent.getComponent()).queue(); } }); } else //just navigate to View2 Utils.handleNavigation( "goView2" ); } |
На основе этой техники мы могли бы реализовать декларативный компонент, служащий в качестве диалога с динамическим содержимым и динамическим обработчиком.
Это оно!
Опубликовано на Java Code Geeks с разрешения Евгения Федоренко, партнера нашей программы JCG . См. Оригинальную статью здесь: Реализация динамического обработчика диалогов с функциональным программированием
Мнения, высказанные участниками Java Code Geeks, являются их собственными. |