Non-Infobus communication between Rich UI handlers

You might organize your application by separating the user interaction, as expressed in one Rich UI handler, from the back-end processing of business data, as expressed in a second Rich UI handler. This topic outlines some mechanisms, aside from the Infobus, by which handlers communicate.

Pushing data from the embedding handler

In the simplest case, the embedding handler can invoke a function in the embedded handler:
Handler EmbeddingHandler type RUIHandler 
   { onConstructionFunction = onConstructionFunction }

   embeddedHandler EmbeddedHandler;
   
   function onConstructionFunction()
      myString STRING = "Received from somewhere";
      embeddedHandler.function01(myString);
   end
end 

Using delegates

You can cause the embedded handler to invoke a function in the embedding one. In this case, the embedding handler updates the value that is assigned to a delegate in the embedded handler. A delegate is a variable that references a function of a specific type; that is, the variable provides access to a function that has a specific set of characteristics.

To see the relationships, consider the following EGL Delegate part, which defines a function that has no parameters or return value:
delegate switchPart() end

The next example shows how to toggle between two Web pages. Here is the embedded handler, Page2, which declares the delegate named switch:

handler Page2 type RUIHandler { onConstructionFunction = myFirstFunction, 
                                initialUI = [content] }
	
	content Box{children = [secondLabel, button], columns = 1};
	secondLabel TextLabel{text = "page2!"};
	button Button{text="switch back to first page", onClick ::= switchToFirst};
	
	//declaration of a delegate
	switch switchPart{};
	
	function myFirstFunction()
	end
	
	function switchToFirst(e Event in)
		 switch();  
	end	
end

When switch() is invoked inside the switchToFirst, the logic that runs is in the embedding handler, Page1, which assigns its own function to the delegate:

handler Page1 type RUIHandler 
  { onConstructionFunction = myFirstFunction, initialUI = [page] }
	
	 page Box{ columns = 1, children = [firstLabel, button]};
	 firstLabel TextLabel{text = "page1!"};
	 button Button{text = "switch to page 2", onClick ::= switchTo2};	
	
	 page2 Page2{};	
		
	 function myFirstFunction()
	    page2.switch = switchBack;  
	 end
	
	 function switchTo2(e Event in)
		  page.children = [page2.content];
	 end			
	
	 function switchBack()
		   page.children = [firstLabel, button];
   end
end

Using delegates to navigate to pages

An extension of the previous example is to define a page handler (MainHandler) that controls the user's subsequent navigation to Web pages. This is a page-by-page flow of events, as is the traditional approach to Web applications. You can start with an approach like this, keeping in mind that Rich UI lets you update parts of a Web page in response to a runtime event.

In this example, the Delegate part takes a string and has no return value:
delegate SwitchToPagePart( TargetPage STRING in) end

Three Rich UI handlers are involved. Here is the output of the first, ButtonHandler, which shows the available options:

Output of ButtonHandler

Note that switchFunction is a delegate and that its invocations refer to logic that is in MainHandler, which is shown later:
handler ButtonHandler type RUIHandler{initialUI = [button1, button2, button3]}
   switchFunction SwitchToPagePart;
   button1 Button{text = "Go To Main Page", onClick::= toMain};
   button2 Button {text = "Stay Here"};
   button3 Button{text = "Go to TextField", oncLick::=toText};
   
   function toMain(e Event in)
		   switchFunction("MainHandler");
   end

   function toText(e Event in)
		   switchFunction("TextFieldHandler");
   end
end

Here is the output of the second handler, TextFieldHandler:

Output of TextFieldHandler

Note that this Rich UI handler also declares a delegate that is based on SwitchToPagePart, and that the user can specify the Web page to present next, even though this handler cannot detect what Web pages are available:
handler TextFieldHandler type RUIHandler
   {initialUI = [instructions, Field1, myButton]}

   // a delegate
   switchFunction SwitchToPagePart;
   instructions TextLabel {text = "Type a page name and click the button."}; 
   Field1 Textfield{width = 200};
   myButton Button{text = "Go to the specified page", onClick ::= handleEvent};

   function handleEvent(e Event in)
      switchFunction(Field1.text);
   end
end
MainHandler displays the text "Click to see your options," but can display a splash screen. This example shows that code, including the logic that displays content that is stored in other handlers:
handler MainHandler type RUIHandler{initialUI = [mainBox]}

   mainBox Box{columns = 1, children = [mainLabel]};
   mainLabel TextLabel{
      text = "Click to see your options.", 
      onClick::= mainEvent};
   buttonHandler ButtonHandler{switchFunction = switchTo};
   textFieldHandler TextFieldHandler{switchFunction = switchTo};
	
   function switchTo(target string in)
      case (strlib.upperCase(target))
         when ("TEXTFIELDHANDLER")
            mainBox.children = [textFieldHandler.instructions,
                                textFieldHandler.Field1, 
                                textFieldHandler.myButton];
         when ("BUTTONHANDLER")
            mainBox.children = [buttonHandler.button1, 
                                buttonHandler.button2, 
                                buttonHandler.button3];
         when ("MAINHANDLER")
            mainBox.children = [mainLabel];
      end
   end

   function mainEvent (e Event in)
      switchTo("ButtonHandler");
   end
end

Notifying the embedding handler after a service call

The embedded handler might not have widgets, but it can call a service. As noted in "Accessing a Service in Rich UI," service invocation in Rich UI is always asynchronous, which means that the requester—the Rich UI handler—continues running without waiting for a response from the service. The user can still interact with the user interface while the Rich UI handler waits for the service to respond. After the invocation, the service completes a task and (in most cases) responds to the requester by invoking a function that you code in the Rich UI handler. That function is called a callback function.

From within the callback function, the embedded handler might notify the embedding handler. Consider the following EGL Delegate part, which defines a function that has no parameters or return value:
delegate notifyPart() end
This example shows an outline of an embedded handler:
handler MyModel type RUIHandler { onConstructionFunction = myFirstFunction }
   //declaration of a delegate
   notify notifyPart{};

   function myFirstFunction()
      call myService.myOperation(12) returning to myCallback;
   end
	
   function myCallback(returnValue STRING)
      notify();
   end	
end
As before, the embedding handler assigns its own function to the delegate:
handler MyHandler type RUIHandler { onConstructionFunction = myFirstFunction }

   theModel MyModel;

   function myFirstFunction()
      theModel.notify = myNotification();
   end

   function myNotification()
      // respond, perhaps by accessing details from the embedded handler
   end	
end

Feedback