javazkzul

Send data from one composer to another


I have and application with two zuls: index.zul and popup.zul.

index.zul shows a button, that opens a window onClick. In that window, popup.zul shows a textbox the user can type a value into. Once the user clicks the confirm button, the window is closed.

How can I get the entered value back to index.zul to display it there?

IndexComposer.java

public class IndexComposer extends SelectorComposer<Component> {
   private static final long serialVersionUID = 1L;

   @Wire
   private Window popupWindow;

   @Listen("onClick = #btn")
   public void button() {
       Window win = (Window) Executions.createComponents("popup.zul", 
                                                         getSelf().getParent(),
                                                         null);
       win.doModal();
   }
}

index.zul

<zk>
   <div apply="co.id.test.master.test.IndexComposer">
      <label id="lbl" />
      <button id="btn" label="Open popup" />
   </div>
</zk>

PopupComposer.java

public class PopupComposer extends SelectorComposer<Component> {
    private static final long serialVersionUID = 1L;

    @Wire
    private Window popupWindow;

    @Wire
    private Textbox txt;

    @Listen("onClick = #close")
    public void closePopup() {
        System.out.println(txt.getValue());
        popupWindow.detach();
    }
}

popup.zul

<zk xmlns:h="http://www.w3.org/1999/xhtml">
   <window id="popupWindow" title="Coffee Order" border="normal" mode="modal">
       <div apply="co.id.test.master.test.PopupComposer">
           <textbox id="txt" />
           <button id="close" label="close" />
       </div>
   </window>
</zk>

Solution

  • One way to do it is to use EventQueues. They are a way to send events across different parts of your application without the need to have a target component that bot the sender and receiver have to know (like with the "normal" Events.sendEvent()).

    Here is a simple example to get you started. Note that I have not tested this, and that I used APPLICATION scope, which is kind of the nuclear option. For your example, DESKTOP should be enough. Please read about EventQueues a bit.

    public class IndexComposer
        extends SelectorComposer<Component>
    {
        public IndexComposer()
        {
            EventQueues.lookup("MyEventQueueName", EventQueues.APPLICATION, true)
                       .subscribe(e -> {
                           String data = (String) e.getData();
                           // update your UI element
                       });
        }
    
        @Listen("onClick = #btn")
        public void button()
        {
            Window win = (Window) Executions.createComponents("popup.zul", getSelf().getParent(), null);
            win.doModal();
        }
    }
    
    public class PopupComposer
        extends SelectorComposer<Component>
    {
        @Wire
        private Window  popupWindow;
    
        @Wire
        private Textbox txt;
    
        @Listen("onClick = #close")
        public void closePopup()
        {
            popupWindow.detach();
            EventQueues.lookup("MyEventQueueName", EventQueues.APPLICATION, true)
                       .publish(new Event("", null, txt.getValue()));
        }
    }