Vaadin Flow Access Current RouterLayout (из любого места)

У нас есть класс RouterLayout в качестве фрейма для остальной части нашего приложения, который включает в себя различные неизменяемые компоненты, включая элемент уведомления, который должен оставаться видимым во время навигации.

@CssImport("./styles/shared-styles.css")
public class MainFrame extends Composite<VerticalLayout> implements RouterLayout, PageConfigurator, AfterNavigationObserver {
    
    // central Notification that persists throughout navigation
    private Notification notification;


    // other stuff....

}

Теперь мы пытаемся показать это уведомление из любого места в нашем коде, чтобы все представления, компоненты и подкомпоненты могли отображать простое уведомление.

К сожалению, я не знаю простого способа получить доступ к уведомлению, которое существует внутри RouterLayout, потому что мы не можем получить доступ к уровню макета текущего пользовательского интерфейса. Помещение уведомления в представление (содержимое маршрутизатора) не работает, потому что оно уничтожается при навигации. Попытка использовать шину событий не работает, потому что прослушиватели событий внутри routerlayout не будут вызываться при запуске из содержимого маршрутизатора (насколько я тестировал).

Мы надеемся достичь простого статического класса доступа, который может получить доступ к компоненту уведомления установленного в данный момент маршрутизатора.

public static void showNotification(String text) {
    // something like this
    MainFrame frame = ((MainFrame)UI.getCurrent().getRouterLayout()).showNotification(text);
}

В основном мы не знаем о простом способе взаимодействия с текущим установленным макетом текущего пользовательского интерфейса из любого места внутри нашего приложения, аналогично UI.getCurrent(). Есть ли способ добиться чего-то подобного?


person Benedikt Schmidt    schedule 18.06.2021    source источник
comment
Ваш вопрос практически дублирует stackoverflow.com/questions/67783918/ и stackoverflow.com/questions/60180043/   -  person Tatu Lund    schedule 18.06.2021
comment
Если ваше приложение использует Spring Boot или Java EE CDI, я бы порекомендовал провести рефакторинг разделяемой части в управляемом компоненте и автоматически подключать / внедрять его везде, где это необходимо.   -  person Tatu Lund    schedule 18.06.2021
comment
@TatuLund, если я правильно понимаю, первый вопрос касается распространения информации по нескольким вкладкам одного и того же сеанса, а второй касается доступа к RouterLayout через следующий нижний элемент. Хотя мой вопрос очень похож по теме, меня больше интересовал удобный способ доступа в области пользовательского интерфейса к текущему RouterLayout из любого места внутри приложения, а не только к следующему его дочернему элементу. Хотя обход - это (довольно грязный) способ сделать это и здесь, я бы предпочел иметь решение со статическим доступом к функциям, как UI.getCurrent ()   -  person Benedikt Schmidt    schedule 18.06.2021
comment
Да, это разные аспекты одной истории. И, к сожалению, теперь существует надежный способ доступа с ограниченным пользовательским интерфейсом. Вы можете копировать данные в пользовательский интерфейс с помощью ComponentUtil, как описано Лейфом, но это не сработает, если вам понадобится PreserveOnRefresh. Единственное удобное решение - Spring или CDI, использующие RouterScoped с MainLayout в качестве владельца области видимости.   -  person Tatu Lund    schedule 22.06.2021
comment
Лейфс aproach сделал это за нас, прямо сейчас у нас нет элементов в главном фрейме, которые необходимо сохранить при обновлении, они просто не должны теряться во время навигации. Итак, как описано, мы связываем MainFrame с текущим пользовательским интерфейсом и можем получить доступ к текущему кадру статически из любого места в приложении. Возможно, в будущем появятся лучшие варианты, но пока мы довольны данным подходом.   -  person Benedikt Schmidt    schedule 22.06.2021


Ответы (1)


Я бы не стал напрямую связывать это с концепцией навигации и компоновки роутера. У вас есть функциональность, которая представляет собой одноэлемент в рамках экземпляра пользовательского интерфейса.

Если вы используете Spring или CDI, то это естественно определить как управляемый компонент в области пользовательского интерфейса, который вы можете внедрять везде, где это необходимо.

Другая альтернатива - основывать логику на UI.getCurrent(). Метод ComponentUtil в Flow имеет методы setData и getData, которые вы можете использовать для присоединения ваших собственных пользовательских экземпляров к конкретному экземпляру компонента. Таким образом, вы можете сделать что-то вроде этого:

ComponentUtil.getData(UI.getCurrent(), MainFrame.class).showNotification("Hello");
person Leif Åstrand    schedule 18.06.2021