简体   繁体   中英

Vaadin: textField disappear after clicking in the grid EDIT button

I have the code shown below which represents a view with two main functionalities:

  1. A simple form that adds a new Object
  2. A grid that represents Objects in the database

I recently added the grid Edit functionality and then something strange happened. After I click the Edit button some of my textFields that are in the form section disappear.

I've noticed that those fields use binder object to set some validation or conversion (those that doesn't stay visible). How can I fix this?

package com.jg.marketing.web;

import com.jg.marketing.DAO.Receiver;
import com.jg.marketing.repository.ReceiverRepo;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.dependency.StyleSheet;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.grid.editor.Editor;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.binder.Binder;
import com.vaadin.flow.data.converter.StringToIntegerConverter;
import com.vaadin.flow.data.validator.IntegerRangeValidator;
import com.vaadin.flow.data.validator.StringLengthValidator;
import com.vaadin.flow.router.Route;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Collection;
import java.util.Collections;
import java.util.WeakHashMap;

@Route("receivers")
@StyleSheet("/css/style.css")
public class ReceiverGui extends VerticalLayout {

    private ReceiverRepo receiverRepo;

    @Autowired
    public ReceiverGui(ReceiverRepo receiverRepo) {
        this.receiverRepo = receiverRepo;

        // Receivers grid
        Grid<Receiver> grid = new Grid<>(Receiver.class);
        grid.setItems(receiverRepo.findAll());
        grid.setColumns("id", "sapNumber", "score", "city", "postCode", "street", "streetNumber", "phoneNumber", "materials");
        grid.getColumnByKey("id").setWidth("30px");
        grid.getColumnByKey("score").setWidth("55px");
        grid.getColumnByKey("city").setAutoWidth(true);
        grid.getColumnByKey("postCode").setWidth("50px");
        grid.getColumnByKey("street").setAutoWidth(true);
        grid.getColumnByKey("streetNumber").setAutoWidth(true);
        grid.getColumnByKey("phoneNumber").setAutoWidth(true);

        // Grid editor
        Binder<Receiver> binder = new Binder<>(Receiver.class);
        Editor<Receiver> editor = grid.getEditor();
        editor.setBinder(binder);
        editor.setBuffered(true);

        // Editor status message
        Div validationStatus = new Div();
        validationStatus.setId("validation");

        // Add new Receiver horizontal layout
        TextField textFieldSapNumber = new TextField("SAP", "wpisz numer");
        binder.forField(textFieldSapNumber)
                .withConverter(new StringToIntegerConverter("Niepoprawny numer"))
                .withValidator(new IntegerRangeValidator("Niepoprawny zakres numeru SAP! 70000000 - 79999999", 70000000, 79999999))
                .withStatusLabel(validationStatus)
                .bind("sapNumber");
        grid.getColumnByKey("sapNumber").setEditorComponent(textFieldSapNumber);

        TextField textFieldScore = new TextField("Realizacja %", "np.: 99.99 ");
        textFieldScore.setWidth("100px");

        TextField textFieldCity = new TextField("Miasto", "wpisz miasto");
        binder.forField(textFieldCity)
                .withValidator(new StringLengthValidator("Wprowadź nazwe miasta o długości od 2 do 25 znaków", 2, 25))
                .withStatusLabel(validationStatus)
                .bind("city");
        grid.getColumnByKey("city").setEditorComponent(textFieldCity);

        TextField textFieldPostCode = new TextField("Kod pocztowy", "np.: 12-345");
        textFieldPostCode.setWidth("120px");
        binder.forField(textFieldPostCode)
                .withValidator(new StringLengthValidator("Wprowadź kod rozdzielony myślnikiem wg. wzoru: 12-345", 6, 6))
                .bind("postCode");
        grid.getColumnByKey("postCode").setEditorComponent(textFieldPostCode);
        // TODO PostCode validation

        TextField textFieldStreet = new TextField("Ulica", "wpisz ulicę");
        TextField textFieldStreetNumber = new TextField("Nr budynku", "np.: 125 B");
        textFieldStreetNumber.setWidth("120px");
        TextField textFieldPhoneNumber = new TextField("Nr kontaktowy", "podaj nr telefonu");
        HorizontalLayout addNewReceiverSection = new HorizontalLayout(textFieldSapNumber, textFieldScore, textFieldCity, textFieldPostCode, textFieldStreet, textFieldStreetNumber, textFieldPhoneNumber);

        // Add edit buttons column
        Collection<Button> editButtons = Collections
                .newSetFromMap(new WeakHashMap<>());

        Grid.Column<Receiver> editorColumn = grid.addComponentColumn(receiver -> {
            Button edit = new Button("Edytuj");
            edit.addClassName("edit");
            edit.addClickListener(e -> {
                editor.editItem(receiver);
                textFieldSapNumber.focus();
            });
            edit.setEnabled(!editor.isOpen());
            editButtons.add(edit);
            return edit;
        });

        editor.addOpenListener(e -> editButtons.stream()
                .forEach(button -> button.setEnabled(!editor.isOpen()))
        );
        editor.addCloseListener(e -> editButtons.stream()
                .forEach(button -> button.setEnabled(!editor.isOpen()))
        );

        Button save = new Button("Save", e -> editor.save());
        save.addClassName("save");

        Button cancel = new Button("Cancel", e -> editor.cancel());
        cancel.addClassName("cancel");

        // Add a keypress listener that listens for an escape key up event.
        // Note! some browsers return key as Escape and some as Esc
        grid.getElement().addEventListener("keyup", event -> editor.cancel())
                .setFilter("event.key === 'Escape' || event.key === 'Esc'");

        Div buttons = new Div(save, cancel);
        editorColumn.setEditorComponent(buttons);

        editor.addSaveListener(
                event -> validationStatus.setText("Poprawnie zaktualizowano wpis"));
        add(validationStatus, grid);

        // Submit new receiver button
        Button buttonAddReceiver = new Button("Dodaj", new Icon(VaadinIcon.PLUS));
        buttonAddReceiver.addClickListener(buttonClickEvent -> {
            final Receiver receiverToAdd
                    = new Receiver(Integer.parseInt(textFieldSapNumber.getValue()),
                    Double.parseDouble(textFieldScore.getValue()),
                    textFieldCity.getValue(),
                    textFieldPostCode.getValue(),
                    textFieldStreet.getValue(),
                    textFieldStreetNumber.getValue(),
                    textFieldPhoneNumber.getValue()
            );
            receiverRepo.save(receiverToAdd);

            // Refresh grid data
            grid.setItems(receiverRepo.findAll());

            // Open notification
            Notification notification = new Notification("Dodano nowego odbiorcę!", 3000);
            notification.open();
        });

        add(addNewReceiverSection);
        add(buttonAddReceiver);
        add(grid);
    }

}
HorizontalLayout addNewReceiverSection = new HorizontalLayout(
    textFieldSapNumber, textFieldScore, textFieldCity, textFieldPostCode, 
    textFieldStreet, textFieldStreetNumber, textFieldPhoneNumber
);

This line is the problem. Your implementation of the grid editor is absolutely fine, but you forgot the fact that any Vaadin Component can never be added twice to any UI simultaneously!

You must never reuse components like that. Always create a new Instance, if you want to show "the same" component twice. Meaning you should use separate Input Field instances for the editor and for your newReceiverSection.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM