Preserving Contents of Embedded Applications on Refresh

It is possible to have embedded applications preserve their contents on refresh, much as one can do with normal Vaadin applications, using the @PreserveOnRefresh annotation. However, due to the nature of embedded Vaadin applications, there are a few changes to how annotations are used when embedding components.

Using @PreserveOnRefresh When Embedding

In the normal annotation case, the @PreserveOnRefresh annotation is added to the Component that the user wants to preserve. When preserving embeddable web components, the @PreserveOnRefresh annotation is added to the WebComponentExporter class. The preserving then affects all embedded instances produced by that exporter.

@PreserveOnRefresh
public class EmbeddedComponentExporter
        extends WebComponentExporter<EmbeddedComponent> {
    public EmbeddedComponentExporter() {
        super("embedded-component");
    }

    @Override
    protected void configureInstance(
            WebComponent<EmbeddedComponent> webComponent,
            EmbeddedComponent component) {
    }
}

If you want to have two versions of the web component, one that is preserved and one that is not, you can simply export the same Component twice under different tags:

@PreserveOnRefresh
public class EmbeddedComponentExporter1
        extends WebComponentExporter<EmbeddedComponent> {
    public EmbeddedComponentExporter1() {
        super("embedded-component-1");
    }

    @Override
    protected void configureInstance(
            WebComponent<EmbeddedComponent> webComponent,
            EmbeddedComponent component) {
    }
}

public class EmbeddedComponentExporter2
        extends WebComponentExporter<EmbeddedComponent> {
    public EmbeddedComponentExporter2() {
        super("embedded-component-2");
    }

    @Override
    protected void configureInstance(
            WebComponent<EmbeddedComponent> webComponent,
            EmbeddedComponent component) {
    }
}

Preserving the Identity of an Embedded Application

Since embedded Vaadin applications live on pages that are not themselves usually Vaadin applications, the embedded web component backed by a server-side Vaadin Component uses a generated ID to link those two facets together. When the custom tag on the client side is upgraded as a Vaadin Web Component and connected to the Component on the server side, it sends an identifier to the server, so that Vaadin can match the two components.

Each embedded web component generates an identifier for itself, which consists of its tag plus a running counter. For example, two <embedded-component> web components on a page might have identifiers EmbeddedComponent-0 and EmbeddedComponent-1. In order to guarantee that a web component instance is uniquely preserved and its state does not leak to other instances of that web component, the generated ID is combined with the window name, and the state is stored to the user’s session. This enables the storing and restoring of a user’s web components inside a web location.

However, since the identifier is essentially a running counter, if an instance of a web component is embedded on two locations within the embedding application, it is possible for the states to get "mixed".

Say the user is at location example.com/location-1, where an instance of embedded-component is embedded. Now, if the user were to navigate to example.com/location-2 and that page also had an instance of embedded-component embedded, the preserved state would be displayed on the embedded-component in the new location location-2.

If you want the state of the embedded web component to be shared between pages, you do not need to do anything. However, since the identification is a running number, having multiple instances of the same component on different pages might yield unexpected behavior.

In order to make sure that the state is preserved in the way you want, you can assign an explicit id attribute to the web component to get consistent behavior.

Controlling the Identity

Assign an id attribute to the embedded web component to be explicit about its identity. The manually assigned id will be used in place of the generated component identifier, providing a consistent identity for the embedded web component.

<div>
    <embedded-component id="uniquely-preserved"></embedded-component>
</div>

The id can then be used to make sure that either the state is preserved across locations, or it is not preserved. If you want to have the component’s state be preserved across locations, assign the same id to the web component in both locations:

<!-- location-1 -->
<div>
    <embedded-component id="cross-preserved"></embedded-component>
</div>

<!-- location-2 -->
<div>
    <embedded-component id="cross-preserved"></embedded-component>
</div>

On the other hand, if you want to make sure that the state is preserved only within a particular location, assign different id attributes to the web component instances in different locations:

<!-- location-1 -->
<div>
    <embedded-component id="location-1-preserved"></embedded-component>
</div>

<!-- location-2 -->
<div>
    <embedded-component id="location-2-preserved"></embedded-component>
</div>