Multiple FXML with Controllers, share object

Solution 1:

FXML is a simple form of MVC pattern. FXML file is a view, Controller is obvious, what's missed? The model -- a place where you store all data relative to your current view and, thus, which you can use to share Country data between controllers.


1. One of the possible approach to introduce model is "context". Let's consider a case, then you have only one model for the whole project so you can have a global context in a form of Singleton

public class Context {
    private final static Context instance = new Context();

    public static Context getInstance() {
        return instance;
    }

    private Country country = new Country();

    public Country currentCountry() {
        return country;
    }
}

Your SampleController will have next changes:

@Override
public void initialize(URL url, ResourceBundle rb) {
    Context.getInstance().currentCountry().setCountry("Belgium");
}

And SubController1 can access it the same way:

@Override
public void initialize(URL url, ResourceBundle rb) {
    System.out.println(Context.getInstance().currentCountry().getCountry());
}

2. Another way is to pass context to SubController1 then you load it's xml. It will work better if you don't want to have application global model. So create similar Context class but without instance fields, and:

public class Sub1Controller implements Initializable {
    private Context context;
    public void setContext(Context context) {
        this.context = context;
        // initialize country dependent data here rather then in initialize()
    }
}

Setting context in SampleController:

Context currentContext = new Context();

@Override
public void initialize(URL url, ResourceBundle rb) {
    currentContext.currentCountry().setCountry("Belgium");
}

@FXML
private void handleButtonAction(ActionEvent event) throws IOException {
    URL url = getClass().getResource("Sub1.fxml");

    FXMLLoader fxmlloader = new FXMLLoader();
    fxmlloader.setLocation(url);
    fxmlloader.setBuilderFactory(new JavaFXBuilderFactory());

    pContent.getChildren().clear();
    pContent.getChildren().add((Node) fxmlloader.load(url.openStream()));
            // here we go
    ((Sub1Controller)fxmlloader.getController()).setContext(currentContext);
}

Solution 2:

by using the Flow API of DataFX you can inject data in your controller instances by using CDI:

  • http://www.guigarage.com/2014/03/datafx-8-nighthacking/
  • http://www.guigarage.com/2013/12/datafx-controller-framework-preview/
  • http://www.javafxdata.org