0

I have a Wicket component which is listening for some event (IEvent). If such event arrives, I want to re-render the component with a changed model. There are no active controls on the page, like AjaxLink, which can trigger the re-rendering.

Is there a way to refresh such kind of component?

I was thinking to somehow trigger an AJAX request from the onEvent method and add an AjaxBehavior to the mentioned component. But I don't know, how to trigger the AJAX request.

public class PersonPanel extends Panel implements Observer {

    private WebMarkupContainer wrapper;

    public PersonPanel(String id) {
        super(id);

        setDefaultModel(new CompoundPropertyModel<PersonInfo>(getModel()));

        wrapper = new WebMarkupContainer("wrapper");
        wrapper.setOutputMarkupId(true);
        add(wrapper);

        wrapper.add(new Label("personID"));
        // some more content
    }

    private IModel<PersonInfo> getModel() {
        return new LoadableDetachableModel<PersonInfo>() {
            @Override
            protected PersonInfo load() {
                // model loading logic
            }
        };
    }

    @Override
    public void onEvent(IEvent<?> event) {
        logger.debug("\n   Person Panel received an Event: " + event.getPayload());

        // Re-rendering of "wrapper" should be triggered from here.
    }

    @Override
    public void update(Observable observable, Object o) {
        send(this, Broadcast.EXACT, "Observable cache has changed.");
    }
}
Vít Kotačka
  • 1,472
  • 1
  • 15
  • 40

2 Answers2

1

Here is the solution, thanks to hint from martin-g, solved via WebSockets. See the methods update and onEvent, plus added WebSocketBehavior on the component:

public class PersonPanel extends Panel implements Observer {

    private WebMarkupContainer wrapper;

    public PersonPanel(String id) {
        super(id);

        setDefaultModel(new CompoundPropertyModel<PersonInfo>(getModel()));

        wrapper = new WebMarkupContainer("wrapper");
        wrapper.setOutputMarkupId(true);
        add(wrapper);

        wrapper.add(new Label("personID"));
        // some more content

        add(new WebSocketBehavior() {
        });

        observableCache.addObserver(this);
    }

    private IModel<PersonInfo> getModel() {
        return new LoadableDetachableModel<PersonInfo>() {
            @Override
            protected PersonInfo load() {
                // model loading logic
            }
        };
    }

    @Override
    public void onEvent(IEvent<?> event) {
        if (event.getPayload() instanceof WebSocketPushPayload) {
            WebSocketPushPayload wsEvent = (WebSocketPushPayload) event.getPayload();
            wsEvent.getHandler().add(wrapper);
        }
    }

    @Override
    public void update(Observable observable, Object o) {
        WebSocketSettings webSocketSettings =
            WebSocketSettings.Holder.get(getApplication());
        WebSocketPushBroadcaster broadcaster =
            new WebSocketPushBroadcaster(webSocketSettings.getConnectionRegistry());
        broadcaster.broadcastAll(
                getApplication(),
                new WebSocketMessage("WebSocket message from the PersonPanel."));
    }

}

You can find a full running example project, implemented in Wicket 8 and Gradle on Bitbucket:

Vít Kotačka
  • 1,472
  • 1
  • 15
  • 40
0

At the send side you can pass the AjaxRequestTarget with the payload of the event.

send(getPage(), Broadcast.DEPTH, new MyPayload(target));

and then on the receive side:

MyPayload payload = (MyPayload) event.getPayload();
payload.getTarget().add(this);
martin-g
  • 17,243
  • 2
  • 23
  • 35
  • Yes, that's my idea - but how do I create the `AjaxRequestTarget`? – Vít Kotačka Jun 08 '17 at 10:48
  • In what conditions you broadcast the event ? Usually this happens in some action method (like `#onClick(AjaxRequestTarget)`, `#onUpdate(AjaxRequestTarget)`), so you already have the `target` around. If this is not an Ajax request then you don't need to add it anywhere because the whole page will be re-rendered. – martin-g Jun 08 '17 at 13:10
  • I've updated the code snippet - you can see the method `update` now, which implements the `java.util.Observer` interface. So, the event is broadcasted from the component itself as reaction to some "Wicket-external" event. The only remaining step is to refresh the component, without full page reload. – Vít Kotačka Jun 08 '17 at 13:30
  • In that case you need to use web sockets. – martin-g Jun 08 '17 at 15:59