Proposal for improving nested controller interaction in JavaFX 2.2

Greg Brown greg.x.brown at
Tue Feb 21 07:36:24 PST 2012

A recent thread in the discussion forum ( revealed a shortcoming in how nested controllers are currently handled in FXML. The problem is that it is not easy to access nested controllers from an including controller. This is particularly problematic when attempting to use FXML for code modularization. While the including controller can access the root element of an included document, it is not possible to access that document's controller. This effectively makes it impossible to access any application-specific functionality defined by the include.

To resolve this issue, I would like to propose the following solution. A new abstract Controller class will be defined in the javafx.fxml package. This class will supersede the existing Initializable interface. The public API for this class will be as follows:

public abstract class Controller {
    public URL getLocation() { ... }
    protected void setLocation(URL location) { ... }

    public ResourceBundle getResources() { ... }
    protected void setResources(ResourceBundle resources) { ... }
    public Map<String, Controller> getIncludes() { ... }
    public void initialize() { ... }

The "location" and "resources" properties mirror the values passed to the current Initializable#initialize() method. The initialize() method itself has been updated to take no arguments. This allows us to more easily add additional initialization properties in the future without breaking API compatibility. Further, since "controller" is an implicit variable in the document's namespace as of JavaFX 2.1, script code can access these properties as "controller.location" and "controller.resources" (something that is not currently possible).

The getIncludes() method is the key feature. It allows extending classes to access functionality defined by included controllers. The map keys are the IDs of any <fx:include> elements, and the values are the controllers defined by the included documents. When combined with bi-directional binding feature we will hopefully be adding in 2.2, this makes it much easier to get data into and out of dialogs. 

For example, the following markup defines a basic dialog for editing a simple contact record:

<Scene fx:id="scene" fx:controller="examples.fxml.dialog.DialogSceneController" 
        <TextField text="#{}"/>
        <TextField text="#{}"/>
        <TextField text="#{}"/>
        <Button text="OK" onAction="#handleOKButtonAction"/>

Note that the values of the text fields are bound to the properties of the Contact, which is itself defined as a property of the dialog's controller. The controller for the application's main window might invoke code such as this to populate and show the dialog:

protected void handleEditButtonAction() {
    // Get the selected contact
    Contact contact = contactChoiceBox.getSelectionModel().getSelectedItem();
    // Populate the dialog with the contact information
    DialogSceneController dialogSceneController = (DialogSceneController)getIncludes().get("dialog");
    // Show the dialog
    Stage dialogStage = new Stage();

Calling setContact() on the dialog's controller causes the UI elements to be populated with the values from the contact record. Because the fields are bound bi-directionally, when the dialog closes, the contact record will contain the updated values from the dialog.

I have prototyped this and done some preliminary testing and I think it works well. I would be interested to hear what others think.


More information about the openjfx-dev mailing list