Skip to content

Instantly share code, notes, and snippets.

@TatuLund
Last active October 2, 2024 11:40
Show Gist options
  • Select an option

  • Save TatuLund/e8dc7e1c7b1504db501e05cd3368370f to your computer and use it in GitHub Desktop.

Select an option

Save TatuLund/e8dc7e1c7b1504db501e05cd3368370f to your computer and use it in GitHub Desktop.
This is an example of LazyComponent for Vaadin 14/23/24. If the content creation of the component takes long. For example data needs to be fetched from the back end and computed, or it is an image whose loading takes time, one may need to produce the component in background process. This example component wraps the process in the Future which cr…
/**
* This is an example of LazyComponent for Vaadin 14/23/24. If the content creation
* of the component takes long. For example data needs to be fetched from the back
* end and computed, or it is an image whose loading takes time, one may need to
* produce the component in background process. This example component wraps the
* process in the Future which creates the component and upon completion adds to
* view. @Push annotation needs to be present in AppShellConfigurator.
*/
package com.example.application.views;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import com.vaadin.flow.component.AttachEvent;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.Composite;
import com.vaadin.flow.component.DetachEvent;
import com.vaadin.flow.component.HasSize;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.progressbar.ProgressBar;
import com.vaadin.flow.function.SerializableSupplier;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.shared.communication.PushMode;
import com.vaadin.flow.theme.lumo.LumoUtility;
@SuppressWarnings("serial")
@Route(value = "lazy-component", layout = MainLayout.class)
public class LazyComponentView extends Div {
Executor executor = Executors.newSingleThreadExecutor();
Random random = new Random();
public LazyComponentView() {
LazyComponent<Grid<String>> div = new LazyComponent<>(executor,
() -> produceGrid());
div.setWidth("800px");
div.setHeight("500px");
div.addClassNames(LumoUtility.BoxShadow.SMALL, LumoUtility.Border.ALL,
LumoUtility.BorderColor.CONTRAST_20);
add(div);
}
public Grid<String> produceGrid() {
try {
// Simulating a long task
Thread.sleep(5000);
} catch (InterruptedException e) {
}
Grid<String> grid = new Grid<>();
List<String> items = IntStream.range(0, 10000)
.mapToObj(i -> "String " + random.nextInt(10000))
.collect(Collectors.toList());
grid.addColumn(item -> item.toString());
grid.setItems(items);
grid.setHeight("100%");
return grid;
}
public static class LazyComponent<T extends Component>
extends Composite<Div> implements HasSize {
CompletableFuture<T> future;
Executor executor;
SerializableSupplier<T> task;
public LazyComponent(Executor executor, SerializableSupplier<T> task) {
this.executor = executor;
this.task = task;
addClassNames(LumoUtility.Display.FLEX);
}
@Override
protected void onAttach(AttachEvent event) {
ProgressBar bar = new ProgressBar();
bar.setIndeterminate(true);
bar.addClassName(LumoUtility.AlignSelf.CENTER);
getContent().add(bar);
if (getUI().get().getPushConfiguration()
.getPushMode() != PushMode.AUTOMATIC) {
throw new IllegalStateException(
"Push updates require Push to be enabled and PushMode.AUTOMATIC");
}
future = CompletableFuture.supplyAsync(task, executor);
future.thenAccept(component -> {
var ui = event.getUI();
if (ui != null) {
ui.access(() -> getContent().replace(bar, component));
}
});
}
@Override
protected void onDetach(DetachEvent event) {
if (future != null && !future.isDone()) {
future.cancel(true);
}
future = null;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment