Xoetrope
View

Introduction tutorial - Dynamic binding - Declaring dynamic bindings
SUMMARY  Dynamic binding allows the developer to use Java callbacks to specify nodes which are to be used in the model. This allows the same page to reflect and update different parts of the model or to update bindings when a list item is selected.

FURTHER READING  Dynamic binding can be a very versatile way of binding to specific nodes in the model. This might be to change the binding once a list item is selected. This deserves a tutorial step in it's own right and should be included in the advanced tutorial in the near future.

The navigation is working fine so now we have to reflect the changes we have made in the data model. We can reuse the same page to update the data model for each of the customers being processed and in order to do this we need to introduce the concept of dynamic binding.

Dynamic binding works in a similar way to event handling insofar as a function is called within the XPage being used. For example, instead of referring to /mortapp/customer/firstname we can now refer to /mortapp/${getCustomerID()}/firstname. The notation ${getCustomerID()} tells the XUI framework to call the getCustomerID() function of the XPage in order to get this portion of the path into the model.

Open the personal.xml file and change the data bindings as follows...

Listing 1 - personal.xml
    ...
<Data>
  <Bind target="firstnameText" source="/mortapp/${getCustomerID()}/firstname" /> 
  <Bind target="surnameText" source="/mortapp/${getCustomerID()}/surname" /> 
  <Bind target="dobText" source="/mortapp/${getCustomerID()}/dob" /> 
  <Bind target="titleList" source="/defaults/titleList" 
  output="/mortapp/${getCustomerID()}/title" />
</Data>
    ...

Now the Personal.java file needs to be amended so as to return the appropriate customer sequence number at the correct time.

Listing 2 - Personal.java
package net.xoetrope.mortgage;

import net.xoetrope.swing.XLabel;
import net.xoetrope.xui.XPage;
import net.xoetrope.xui.data.XModel;
import net.xoetrope.xui.XProjectManager;

public class Personal extends XPage
{
  XLabel titleLabel;
  XModel joint, currentCust;
  String newCust = "1";

  public Personal()
  {
    joint = (XModel)rootModel.get( "xui_state/mortapp/numapplicants" );
    currentCust = (XModel)rootModel.get( "temp/currentCust" );
  }

  public Object getAttribute(String name, String compName) {
    newCust=null;
    boolean isJoint = joint.get().toString().compareTo( "Joint" ) == 0;
    if (name.compareTo("next") == 0) {
      if ( ( isJoint ) && ( currentCust.get().toString().compareTo( "1" ) == 0 ) ) {
        newCust = "2";
        return "personal";
      }
      return "finance";
    }
    else if (name.compareTo("prev") == 0) {
      if ( ( isJoint ) && ( currentCust.get().toString().compareTo("2")==0 ) ) {
        newCust = "1";
        return "personal";
      }
      return "welcome";
    }
    return null;
  }

  public void pageActivated() {
    if ( ( currentCust.get().toString().compareTo( "1" ) == 0 ) )
      titleLabel.setText( "Personal Details (First Applicant)" );
    else
      titleLabel.setText( "Personal Details (Second Applicant)" );
  }
  
  public void saveBoundComponentValues()
  {
    super.saveBoundComponentValues();
    if ( newCust!=null )
      currentCust.set( newCust );
  }

  public void pageCreated() {
    titleLabel = (XLabel) findComponent( "Title" );
  }
  
  public String getCustomerID()
  {
    return "customer" + ( String )currentCust.get();
  }

}

The newCust variable in this code is a little tricky to understand. When the getAttribute function is called we know that a new page is being navigated to, but the saveBoundComponentValues call has yet to be made. So we don't want to update the currentCust node of the model yet. Instead we will keep the new customer number in the class variable newCust and after the bound components have been saved we can update the model.

The NavPanel class needs a slight change to it's navigateToPage function...

Listing 3 - NavPanel.java

    ...
  protected void navigateToPage( String key )
  {
    // The content page has an attribute for the next page.    
    XPage target = ( XPage )( ( XTarget ) 
	pageMgr.getTarget( "content" ) ).getComponent( 0 );
    String dest = ( String )target.getAttribute( key, null );
    target.saveBoundComponentValues();
    if ( dest != null ) {
      XPage newPage = ( XPage )pageMgr.showPage( dest, "content" );
      newPage.setExceptionHandler( new ExceptionHandler( newPage ) );
    }
  }
    ...

Now when data mortapp model is saved it will appear like...

Listing 4 - The saved data
<data id="mortapp"> 
  <data id="customer1"> 
    <data value="Joe" id="firstname" /> 
    <data value="Bloggs" id="surname" /> 
    <data value="14/12/1975" id="dob" /> 
    <data value="Mr" id="title" /> 
  </data> 
  <data id="customer2"> 
    <data value="Josephine" id="firstname" /> 
    <data value="Bloggs" id="surname" /> 
    <<data value="25/02/1972" id="dob" /> 
    <data value="Mrs" id="title" /> 
  </data> 
  <data id="finance"> 
    <data value="250000" id="propvalue" /> 
    <data value="200000" id="mortamt" /> 
  </data> 
</data>

After compiling all edited java code, run the run.bat file and the application will appear as in the screenshot.

Log in or register to download the source code for this step.