modal-dialogreturn-valuevaadin23

Cannot get value from Vaadin Dialog


From the Grid context menu I am getting an Object (Book) which I need to open in the editing form. However, some books are multi-volume series and I need to choose one volume. For this purpose I have written another class extending com.vaadin.flow.component.dialog.Dialog

    public class VolumeSelector extends Dialog {
    
    private final Series series;
    private final Button done;
    private final ListBox<Book> selection;

    private Book selectedBook;

    public VolumeSelector(Series series) {
        this.series = series;
        this.setModal(true);
        selection = new ListBox<>();
        List<Book> books = new ArrayList<>();
        books.add(series);
        books.addAll(series.getVolumes());
        selection.setItems(books);
        selection.addComponents(series, new Hr());
        selection.setRenderer(new ComponentRenderer<>(
            book -> new Text(book.getTitle())));
        selection.setValue(series);
        this.add(selection);
        done = new Button("Done",
            (e) -> {
                this.selectedBook = selection.getValue();
                this.close();
            });
        this.getFooter().add(done);
        
        this.setModal(true);
        this.setCloseOnOutsideClick(false);
        this.setCloseOnEsc(true);
        Button closeButton = new Button(new Icon("lumo", "cross"),
                (e) -> {
                    this.selectedBook = null;
                    this.close();
                });
        closeButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
        closeButton.onEnabledStateChanged(true);
        this.getHeader().add(closeButton);
    }

    /**
     * @return the selectedBook
     */
    public Book getSelectedBook() {
        return selectedBook;
    }    
}

Now from the context menu I am calling the following function:

@SuppressWarnings("SleepWhileInLoop")
private Book selectVolume(Series series) { 
    VolumeSelector vs = new VolumeSelector(series);
    this.doneWithBookSelection = false;
    vs.addOpenedChangeListener(
       event -> {
           if(!event.isOpened()) {
               this.doneWithBookSelection = true;
               
           }
       }
    );
    vs.open();
    while(!doneWithBookSelection) {
        try {
            Thread.sleep(500);
        } catch (InterruptedException ex) {
        }
    } 
    return vs.getSelectedBook();
}

The dialog won't show up in this case. If I remove (comment out) while loop, dialog does shows up, but only after function returns null from the function. Therefore, I can't get the value. Can anyone please tell me what I am doing wrong and how to fix it.


Solution

  • I did resolve this problem by adding PropertyChangeSupport to the class.

        private final transient PropertyChangeSupport propertyChangeSupport = new java.beans.PropertyChangeSupport(this);
    

    And in the the context menu I put this code:

            propertyChangeSupport.addPropertyChangeListener("selectedBook", new BookEditor());
        this.editBookMenuItem = addItem("Edit book info",
                event -> event.getItem().ifPresent((Book book) -> {
                    if (book instanceof Series) {
                        selectVolume((Series) book);
                    }
                    else {
                        this.setSelectedBook(book);
                    }
                }));
    

    And farther down in the code I added the following:

        public void setSelectedBook(Book selectedBook) {
        org.garik.encyclopedia.model.Book oldSelectedBook = this.selectedBook;
        this.selectedBook = selectedBook;
        propertyChangeSupport.firePropertyChange("selectedBook", oldSelectedBook, selectedBook);
    }
    
    private void selectVolume(Series series) {
        VolumeSelector vs = new VolumeSelector(series);
        vs.addOpenedChangeListener(
                event -> {
                    if (!event.isOpened()) {
                        setSelectedBook(vs.getSelectedBook());
    
                    }
                }
        );
        vs.open();
    }
    
    private class BookEditor implements PropertyChangeListener {
    
        public BookEditor() {
        }
    
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            Book book = (Book) evt.getNewValue();
            if (book != null) {
                BookPanel bookPanel = config.getBookPanel();
                bookPanel.setBook(book);
                bookPanel.open();
            }
        }
    }
    

    Everything is working as expected now. Dialog is opened and it does return the value I am looking for.