Search code examples
javajakarta-eevaadinjava-ee-8vaadin-grid

Vaadin 14 LTS Grid refresh after adding new data not working


I'm trying to refresh grid after adding an row into it, but it's not working. Here is my Event Listener on my UI Code : Edited Full code.

Grid<TransactionModel> transactionData = new Grid<>(TransactionModel.class);
try {
    // transactionData.setItems(transactionServices.getTransactionTable());
    List<TransactionModel> transactionList = transactionServices.getTransactionTable();
    ListDataProvider<TransactionModel> transactionDataProvider = new ListDataProvider<>(transactionList);
    transactionData.setDataProvider(transactionDataProvider);
    transactionData.setColumns("id", "transactionTimestamp", "srcAccountId", "dstAccountId", "amount");
    Grid.Column<TransactionModel> idColumn = transactionData.getColumnByKey("id");
    Grid.Column<TransactionModel> srcAccountIdColumn = transactionData.getColumnByKey("srcAccountId");
    Grid.Column<TransactionModel> dstAccountIdColumn = transactionData.getColumnByKey("dstAccountId");
    HeaderRow filterRow2 = transactionData.appendHeaderRow();
    TransactionFilterModel transactionFilterModel = new TransactionFilterModel();

    transactionDataProvider.setFilter(transaction -> transactionFilterModel.find(transaction));
    // Filter srcAccountId
    TextField idField = new TextField();
    idField.addValueChangeListener(event -> {
        transactionFilterModel.setId(event.getValue());
        transactionDataProvider.refreshAll();
    });
    idField.setValueChangeMode(ValueChangeMode.EAGER);
    filterRow2.getCell(idColumn).setComponent(idField);
    idField.setSizeFull();
    idField.getElement().setAttribute("focus-terget", "");
    // Filter srcAccountId
    TextField srcAccountIdField = new TextField();
    srcAccountIdField.addValueChangeListener(event -> {
        transactionFilterModel.setSrcAccountId(event.getValue());
        transactionDataProvider.refreshAll();
    });
    srcAccountIdField.setValueChangeMode(ValueChangeMode.EAGER);
    filterRow2.getCell(srcAccountIdColumn).setComponent(srcAccountIdField);
    srcAccountIdField.setSizeFull();
    srcAccountIdField.getElement().setAttribute("focus-terget", "");
    // Filter dstAccountId
    TextField dstAccountIdField = new TextField();
    dstAccountIdField.addValueChangeListener(event -> {
        transactionFilterModel.setDstAccountId(event.getValue());
        transactionDataProvider.refreshAll();
    });
    dstAccountIdField.setValueChangeMode(ValueChangeMode.EAGER);
    filterRow2.getCell(dstAccountIdColumn).setComponent(dstAccountIdField);
    dstAccountIdField.setSizeFull();
    dstAccountIdField.getElement().setAttribute("focus-terget", "");
    transactionData.setWidth("50%");
} catch (JsonProcessingException | EndpointException ex) {
    Logger.getLogger(MainView.class.getName()).log(Level.SEVERE, null, ex);
}

// Event Listener
submitButton.addClickListener(e -> {
    System.out.println("Submitted !");
    AccountModel submittedModel = new AccountModel();
    if (accountModelBinder.writeBeanIfValid(submittedModel)) {
        try {
            accountServices.registerAccount(submittedModel);
            accountIdTextField.clear();
            nameTextField.clear();
            addressTextField.clear();
            birthDateDatePicker.clear();
            allowNegativeBalanceButtonGroup.clear(); 
        } catch (EndpointException | JsonProcessingException ez) {
            Logger.getLogger(MainView.class.getName()).log(Level.SEVERE, null, ez);
        }
    }
    accountData.getDataProvider().refreshAll(); // <- REFRESH
});

And for service I'm using rest, here is the accountservice code:

public List<AccountModel> getAccountTable() throws JsonProcessingException, EndpointException {
    List<AccountModel> datalog = new JsonResponseReader(restMockvaEndpoint.send(new EndpointRequestBuilder()
            .method("GET")
            .resource("/account")
            .build()
    )).getContentTable(AccountModel.class).getData();
    return datalog;
}

public AccountModel registerAccount(AccountModel accountModel) throws JsonProcessingException, EndpointException{
    AccountModel account = new JsonResponseReader(restMockvaEndpoint.send(new EndpointRequestBuilder()
            .method("POST")
            .content(Json.getWriter().writeValueAsBytes(accountModel), MediaType.APPLICATION_JSON)
            .resource("/account")
            .build())).getContentObject(AccountModel.class);
    return account; 
}

Edited : Add registerAccount.

The problem is when I click submitButton for adding new data, the grid doesn't refresh. Any ideas?


Solution

  • For this to work with a ListDataProvider, you would have to modify the underlying list (add/remove items).

    Now that you call refreshAll(), it just reads the list you passed again, and as it still contains the same items, nothing changes. It does not know to fetch the items from your service again.

    There are a few solutions that I can think of:

    1. Manually add the new item to the list (it will then appear at the end of the grid):

    accountList.add(submittedModel);
    ...
    // This instructs the grid to read the list again
    accountData.getDataProvider().refreshAll();
    

    If your accountServices.registerAccount method returns the newly saved item, you might want to add that one instead.

    2. Set the items again

    You could fetch the items again and set a new data provider. You can just use setItems(...) then, which uses a ListDataProvider under the hood.

    // Run this both when first creating the grid, and again after the new item is saved.
    // This time you don't need to call refreshAll()
    List<AccountModel> accountList = accountServices.getAccountTable();
    accountData.setItems(accountList);
    

    3. Use a lazy data provider

    When you use a lazy data provider, for example from callbacks, then calling refreshAll() executes those callbacks again to fetch new items.

    In this case you need to implement the needed service methods, and it requires a bit more work if you need sorting or filtering.

    this.setDataProvider(DataProvider.fromCallbacks(
            query -> myAccountService.getAccounts(query.getOffset(), query.getLimit()).stream(),
            query -> myAccountService.countAccounts()
    ));