Using Play 2.1.0, I have a Java controller with an action responsible to render arbitrary html views.
For example:
class HtmlClientViews extends Controller {
public static void getView(String viewName) {
return ok(/*How to render the view programmatically?*/)
}
}
And in my views I have a view named account.html.scala.
I have a route like:
GET /htmlclient/*viewName controllers.HtmlClientViews.getView(viewName)
If I make a request like /htmlclient/account.html I want to render the view named account.html.scala
I haven't tried yet to use Java reflection mechanisms for this, but would like to know what is the most effective way to achieve this.
You can do it with:
reflections, like in Play Authenticate usage sample, there it's used for selecting different view depending on detected language
If you have known number of views you can use simple switch statement in controller to return view a,b,c or d.
Also as in case no. 2 - you can use matching statement in the view to include sub-view depending on some variable.
Related
In my view I have a StyledText on which I want to open the default eclipse find/replace-dialog (The one that appears in the editor on Ctlr+F).
Therefore I want to instantiate and run the FindReplaceAction but my problem is that this action needs a ResourceBundle as a parameter and I have no idea what this is used for and where I can get it from...
I wonder whether this is actually the way to accomplish this functionality or if there is a way to register my view (that implements IFindReplaceTarget) globally in eclipse to recieve the Ctrl+F shortcut for opening the dialog
You should be able to participate in the standard Find/Replace code by having your view respond to a request for the IFindReplaceTarget in the getAdapter method of your main ViewPart class and setting up the find and replace action.
The adapter is something like:
#SuppressWarnings("unchecked")
#Override
public <T> T getAdapter(Class<T> required) {
if (IFindReplaceTarget.class.equals(required)) {
return (T) ... your find replace target class
}
... other adapters
}
Note: Older versions of Eclipse don't use Generics for this method.
Set up the FindReplaceAction with something like:
ResourceBundle bundle = ResourceBundle.getBundle("my.package.Messages");
FindReplaceAction findReplaceAction = new FindReplaceAction(bundle, "find_replace_action_", this);
findReplaceAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_FIND_AND_REPLACE);
IActionBars actionBars = getViewSite().getActionBars();
actionBars.setGlobalActionHandler(ActionFactory.FIND.getId(), findReplaceAction);
The resource bundle needs a Messages.properties file with contents like:
find_replace_action_label=&Find/Replace...
find_replace_action_tooltip=Find/Replace
find_replace_action_image=
find_replace_action_description=Find/Replace
I've studied all popular GUI patterns - MVP,MVC,MVVM and finally I decided to implement MVP (Supervising Controller). So I have the following OBJECTS(!). Stage<-View<->Model. It's important Stage!=View, it is another object. Between view and model data binding. Besides I have a presenter(controller) which handles all events and works with view and model, so View<-ViewInterface<-Controller->Model.
The problem is now how to get references to labels, textAreas etc in view. Javafx allows to use #FXML annotation to inject these components to controller. However, using MVP I need these components in View, as all logic for view is in View and I don't need them in controller. The only solution I know is:
public class MyView{
private Button button;
public MyView(){
...
button=(Button) root.lookup("#myButton");
}
}
That is to get references by their ID. However I don't like it. Or I do something wrong or I understand something wrong but I think a better solution exist. Please, help me to find it.
JavaFX has been designed to work with the MVC pattern. Hence it is much easier to use MVC than MVP. In MVP Presenter is responsible for formatting the data to be displayed. In JavaFX, it is done automatically by View. Here's a quick overview of JavaFX MVC:
Model - the domain data / data structure that you work with in your application (e.g. Person, Employer, Coursework, etc)
View - the UI definition of the application and its Model. The preferred way of creating a view is via an FXML file, which is essentially the View in JavaFX MVC.
Controller - the bridge between Model and View. The code is typically isolated in XController class (where X is the name of the FXML View). The instance of Controller is automatically injected by FXMLLoader or can be done manually in case you require a custom Controller. The Controller class will have access to UI (View) elements in order to be able to manipulate different properties and also the Model, so that it can perform operations based on the UI (View) input.
To sum up, in JavaFX you don't need to have class View, the View definition should be entirely in the FXML file. All UI elements should be injected with #FXML into your Controller class. If you absolutely have to use MVP, then AWT/Swing or MVP4j - http://www.findbestopensource.com/product/mvp4j might be a better option.
For more detailed explanation please have a look at the official Oracle tutorial for JavaFX: http://docs.oracle.com/javase/8/javafx/get-started-tutorial/jfx-overview.htm
If you require help building UI using FXML: http://docs.oracle.com/javase/8/javafx/api/javafx/fxml/doc-files/introduction_to_fxml.html
This tutorial covers basics of MVC in JavaFX and how each component communicates with others: http://code.makery.ch/library/javafx-8-tutorial/part1/
As an Android developer, I always use MVP pattern in my applications. MVC compared to MVP seems so old to me, so when I started working on a new Java app, I felt a little bit lost.
Here there is my solution:
Initial steps
In fxml files create the UI, without specifying a controller, because you don't need one.
Create the Java interfaces (IView, IPresenter and so on..)
Implement the IPresenter interface in the Presenter class, as you would do normally (do http requests, query a DB..)
Now the interesting part:
Adapting your view to MVP pattern
Let's see some code:
Create your GUI (for example a Main GUI) and implement your View interface
public class MainGUI extends Application implements MainContract.View {
public static void main(String... args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws IOException {
//here we will load fxml or create the ui programmatically
}
//method from view interface
#Override
public void onServerResponse(String message) throws IOException {
//update the view
}
Now the last step:
Communicating with the presenter
To do this, we first create an istance of our presenter:
private MainContract.Presenter presenter;
public MainGUI() {
presenter = new MainPresenter(this);
}
this is, of course, the MainContract.View implemented in the MainGUI class
Now we have to get a reference to the view components
private ComboBox<Double> mySimpleList;
#Override
public void start(Stage primaryStage) throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("layout_main.fxml"));
Parent root = loader.load();
mySimpleList= (ComboBox<Double>) loader.getNamespace().get("mysimplelist_id");
...
primaryStage.setScene(new Scene(root, -1, -1));
primaryStage.show();
I prefer using fxml files instead of creating the ui by code, but the logic behind is identical.
Set the items
...
mySimpleList.setItems(ValuesFactory.getMyValues());
And the listener
...
mySimpleList.valueProperty().addListener(simpleListListener);
What is simpleListListener?
A simple ChangeListener, where we finally call a presenter method
simpleListListener = (ChangeListener<Double>)
(observable, oldValue, newValue) -> presenter.doTheLogic(newValue);
This is an easy scenario, but in principle this is how we can use MVP Pattern with JavaFX. I also understand that it isn't the definitive solution, so I hope that one day there will be more docs where I can learn more about this argument!
Let me know if I wasn't clear in some part of the code
I am getting my feet wet with javafx. This is what I am doing.
FXML Views
DI Controllers
Weld-SE Managed Services and Models
Trying to confine UI to FXML
Trying keep the Controllers thin
Problem:
While trying to code the UI, most static UI is confined inside the fxml. But there are scenarios where I find my self adding, removing, showing, hiding elements etc.
I find myself doing this inside the controller as fx lets me configure controller method in the view which it will call on a particular action / event. All this code deals with Dynamic UI building / manipulating and belongs inside the view layer. But, it ends up in controller making the controllers fat.
javafx provides javascript integration. This is one possible way to abstract that view manupulation code away. But this would add not so perfect javascript into the mix.
How would I abstract the code away in java or fxml so that I don't break the Thin Controller Paradigm ?
EDIT
#assylias
Agreed, I have thought about this and this way that java class and fxml together become a reusable widget. But then, how do I wire this into FXML. FXML doesn't understand anything but a controller. Let say I wire this view class into fxml using fx:controller and not name it controller. So I have something like this.
This view class has nothing but view manipulation code. Then I would create another controller class. But then I would expect to somehow fill the form data into this controller. This should only happen when the user has submitted the form. So in a way, I need to tell javafx somehow that UI manipulation request / event is different from actual data manipulation request / event.
Your thoughts, sorry if it was verbose. Tried to articulate it in as few words as I could.
I think the easiest solution to this is to remember that the controller specified in FXML is a view controller. It's purpose is to contain code to modify and update the view, not to contain traditional MVC controller code or business logic.
For example, in a project I'm currently working on, I'm using JavaFX with Akka Actors. The application is written in scala. The JavaFX view controllers contain any code necessary to modify the view. One screen contains a login form. When the user clicks the login button, the view controller simply creates a message containing the username and password, and sends that message to the actor responsible for doing business logic. If that actor determines there is an error then it will send a message back to the view controller, and the view controller can decide what sort of updates need to be made on the screen.
I've found that using akka actors with JavaFX greatly simplifies coding the application for at least two reasons.
Because using an actor system mandates sending messages between actors, there is a natural boundary between presentation code and business code. The messages that are passed back and forth form this natural boundary.
Using actors completely replaces the complexity of working with threads/tasks. It completely eliminates the need to code javafx.concurrent.Task's for long running processes.
How about putting your view manipulation code in Main Class ?
Main Class :
public class SampleJavaFXApp extends Application{
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource(
"SampleUI.fxml"));
Parent root = (Parent) loader.load();
Controller controller = loader.getController();
viewManipulationLogic(controller);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
// view manipulation logic
private void viewManipulationLogic(Controller controller) {
controller.getBlueButton().setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent arg0) {
System.out.println(" I am just about button!");
}
});
}
Controller :
public class Controller implements Initializable {
#FXML
private Button blueButton;
public Button getBlueButton() {
return blueButton;
}
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
//real data manipulation
}
}
cons : You need getters for all Nodes u want to manipulate , in controller class.
Im trying to understand how the Passive View design pattern works for simple web apps.
Can someone provide a simple example of this pattern using these requirements:
View is a JSP that prints HELLO WORLD!
Data is persisted in the data store as "hello world", call to retrieve data can be a stub
Provide example files for pieces (presenter, view, etc) and denote which piece of the pattern each file represents.
No frameworks/DSLs should be used other than jstl/el (which are optional)
Thanks
UPDATE 1: Adding my understanding of how this would be structured.
// Presenter; responsible for multiple "rendtions" of a particular view (show, index, edit, summary, etc.)
public class HelloWorldPresenter {
private HttpServletRequest request;
private DataStore dateStore;
public HelloWorldPresenter(HttpServletRequest request) {
this.request = request;
this.dataStore = DataStoreUtil.getDataStore(request);
// Do a bunch of other inits that all getXXXModels() will use
}
public getShowModel() {
HelloWorldShowModel model = new HelloWorldShowModel();
String tmp = makeLoud(this.dataStore.getMyData()); // Stub method
model.setText(tmp);
return model;
}
private String makeLoud(String str) {
return str.toUpperCase() + "!";
}
}
// Model used by view
public class HelloWorldShowModel {
private String text;
public getText() { return this.text };
public setText(String text) { this.text = text; }
}
// View
show.jsp
<c:set var="model" value="new HelloWorldPresenter.getShowModel()"/>
${model.text} -> HELLO WORLD!
or
<% HelloWorldShowModel model = new HelloWorldPresenter(request).getShowModel() %>
<%= model.getText() %>
The things I'm unsure about are:
How the Presenter would be exposed to the View (JSP) since the View shouldnt know about the presenter. I may be mixing semantics though, and the HelloWorldShowModel (which is acting as a "ViewModel" of sorts, is what shouldnt know about the Presenter).
Should I even have the HelloViewShowModel abstraction, or should I simply have a method getText() on my Presenter which is called within the JSP to get the requested text.
If I do have multiple "views" for a resource (ex. Show, Index, Edit, Summary, etc.), should I have multiple Presenters? How should this logic be broken up? Multiple presenters that inherit from a Shared presenter? Should each presenter only be responsible for returning one ViewModel?
I've read through Fowlers articles as well as a number of other write-ups - the problem (for me) is they are written in the context of .NET apps, and I dont understand how all their objects get wired up.
I hope this will aleve concerns of me being "lazy" and looking for a "hand-out" answer :)
With the requirements you state I would say the pattern can't be implemented. If you consider the view to be a JSP then there are no means a controller could actively set any values of UI components. (To me this is the core of the pattern: the controller actually updates the view actively by setting values of input / output UI components, not the other way round (view getting fields from a model object). This can't be done with the above techniques as a JSP has no means to be accessesd this way.
It could be implemented in a web environment based on Javascript though. Consider your view being the DOM and your controller being a Javascript component. The JS controller has direct write access to the DOM and therefore could update single fields actively like the pattern suggests. To update / get the model the JS controller could talk to a server-side system e. g. based on a REST API via Ajax.
A plain templating solution like JSP cannot be used to offload all logic to controller, at least in real world cases. I think this kind of thing can be achieved with JSF.
If you want to learn about how things are done I recommend you to take a look at Spring MVC. It's source code can teach you a lot.
I'm just learning how the Play 2.0 framework. So I have a quite basic question: I just want to take a URL parameter and display it in the view. How do you do that?
I created the URL pattern:
GET /test/:id controllers.Application.testOutput(id: Long)
And an apporoptiate methode in Application:
public static Result testOutput(long id) {
return ok(
views.html.test.render(id)
);
}
How do I call the id variable form the view? I know how to call methodes defined in the model in the view, but I don't know how to display the id variable in the view. Is it the right way to pass the id variable to the render methode?
I'd like to understand the underlying concept, so an detailed explanation to the answer would be great!
Our test URL will be http://localhost:9000/greeter?message=hello and this will output a text/plain response with the content of the parameter message (ie hello). First, let's define the route
GET /greeter controllers.Greeter.say(message: String)
Then, create a Greeter controller (I use Java)
package controllers;
import play.*;
import play.mvc.*;
// This lets you call the template without the views.html prefix
// import views.html.*;
import views.txt.*;
public class Greeter extends Controller {
public static Result say(String message) {
return ok(greeter.render(message));
}
}
You can see that ok() calls a scala function defined in the file app/views/greeter.scala.txt Here is the content of that file (the first line defines the message parameter of type String used inside the function
#(message: String)
I'm the content. Note that you can place
anything you want here. Scala expressions
begin with the '##' character. For example
next line contains the content of message:
#message
In this case I used .txt for file extensions because I wanted plain text response. If you want to produce HTML output, simply make a .scala.html file
The client request is handled by the Play router, which in turn forwards it to some action (which is a method inside a Controller)
GET /greeter Greeter.say
From the Play doc
The last part of a route definition is the Java call. This part is
defined by the fully-qualified name of an action method. The action
method must be a public static void method of a Controller class. A
Controller class must be defined in the controllers package and must
be a subclass of play.mvc.Controller.
You can add a Java package before the Controller class name if it
isn’t defined directly under the controllers package. The controllers
package itself is implicit, so you don’t need to specify it
Inside the action, you can get the parameters via the param object or directly by the method signature:
public static void say(String what) {
...
}
and you can pass objects to the template via render(what) like you do in your sample.
Finally your template can access those object with the ${what} syntax.
EDIT This is the Play 1.x way of doing things. I didn't notice your tag, but still hope this helps. Play2 uses the new Scala template engine, here is the guide. It seems you must declare your parameters at the beginning of the template, then you can access them via the #what syntax. That's because the template is now a compiled Scala function, so it can do type checking at compile time and things like this. You pass parameters to this function with render(what) (like you do) . I personally don't use Play2.0 myself: it's a big improvement from the technical point of view, at the cost of being less intuitive and more verbose. I don't think that simpler projects benefit from these improvements
In Play 2 templates are just plain functions, so you can call them as you would call any function.