quarkus-fx icon indicating copy to clipboard operation
quarkus-fx copied to clipboard

Inject @FXMLLoader with a qualifier to bind it to a specific view

Open Eng-Fouad opened this issue 1 year ago • 3 comments

Currently, one can use @FxView on a controller to link resources (fxml, css, bundles) to it which will be constructed on startup. Then inject FxViewRepository to access it, something like:

@FxView("login")
@Singleton
public class LoginController {
    public void prepareLogin(){...}
}

@FxView("core")
@Singleton
public class CoreController {

    @Inject FxViewRepository fxViewRepository;
    @FXML BorderPane root;
    
    @FXML
    void initialize() {
         if (!isLoggedIn()) {
             var loginViewData = fxViewRepository.getViewData("login");
             root.setCenter(loginViewData.getRootNode());
             loginViewData.<LoginController>getController().prepareLogin();
         }
    }
}

or inject FXMLLoader to load the view on demand:

@FxView("core")
@Singleton
public class CoreController {

    @Inject FXMLLoader fxmlLoader;
    @FXML BorderPane root;
    
    @FXML
    void initialize() {
         Parent loginRoot = fxmlLoader.load(getClass().getResourceAsStream("/login.fxml"));
         root.setCenter(loginRoot);
         fxmlLoader.<LoginController>getController().prepareLogin();
    }
}

It would be nice to be able to inject FXMLLoader and bind it to a view using a qualifier (making @FxView a qualifier?), something like:

@FxView("core")
@Singleton
public class CoreController {

    @Inject @FxView("login") FXMLLoader fxmlLoader;
    @FXML BorderPane root;
    
    @FXML
    void initialize() {
         Parent loginRoot = fxmlLoader.load();
         root.setCenter(loginRoot);
         fxmlLoader.<LoginController>getController().prepareLogin();
    }
}

Eng-Fouad avatar Oct 08 '24 05:10 Eng-Fouad

Why don't you directly inject LoginController in the CoreController ?

CodeSimcoe avatar Oct 15 '24 06:10 CodeSimcoe

Why don't you directly inject LoginController in the CoreController ?

Maybe it is not a good example what I provide. What I mean is to create a new view and not use the existing instance in FxViewRepository.

It could be better define different annotation and not to use @FxView, something like:

@FxView("core")
@Singleton
public class CoreController {

    @Inject @FxViewLoader("message-dialog") FXMLLoader messageDialogFxmlLoader;
    
    @FXML
    void onButtonClicked() {
         Dialog<?> messageDialog = messageDialogFxmlLoader.load(); // no need to invoke setLocation() nor setResources()
         messageDialogFxmlLoader.<MessageDialogController>getController().setMessage("Hello World");
         messageDialog.showAndWait();
    }
}

@Dependant
public class MessageDialogController {

    // ...
    
    public void setMessage(String message) {
         // ...
    }
}

Eng-Fouad avatar Oct 15 '24 06:10 Eng-Fouad

I'll have a look next !

CodeSimcoe avatar Oct 17 '24 17:10 CodeSimcoe