Skip to content

Add web view page

Vasco Ramos edited this page Sep 15, 2020 · 7 revisions

If you want to create an entirely new base schema (a view), you first need to add a base template name <name>.scala.html to app > views. You also need to make sure that you have an endpoint on JAVA code that handles your request and returns this web view (the "backend" process is similar to create a REST API endpoint).

If you just want to create a new UI stage, based on an already defined view, follow these steps:

  1. Create an endpoint (and register it) that returns the base view you want to use.

  2. At app > assets > javascripts, create the controller and view associated with your new UI stage (the view JS file handles the stuff UI related and the controller handles the stuff Backend related).

  3. At app > assets > templates, create a file named <name>.handlebars where you'll insert the UI code that will be dynamically added to the main div container of your base web view.

  4. After all these files are ready, you need to make sure the framework knows the path to everything you created, so you'll need to add the paths to your view and controller javascript files in the file app > assets > javacripts > main.js.

  5. Finally, you'll need to add the RegExp handler that will assemble the resources you need (variables and controllers) at app > assets > application > application.js.

Example

This example is going to be divided into two big parts: the creation of a new view from scratch and the creation of a UI component (through handlebars).

Let's take as an example the creation of a dashboard page, given the fact that we need to create a new base-view from scratch.

NOTE: if you just want to create a new UI component, with handlebars, jump to the second part.

Creation of a new (base) view

To create a new view to use as a base to new UI stages, you first need to add the HTML template. So, add your view structure to a file named home.scala.html, for the sake of this example, at app > views:

<!DOCTYPE html>

<html>
    <head>
        <meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<!-- Tell the browser to be responsive to screen width -->
	<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">

	<title>BIcenter</title>

	<!-- Boostrap Select2 -->
	<link rel="stylesheet" media="screen" href="@routes.Assets.versioned("lib/select2/select2.min.css")">

	<!-- Font Awesome -->
	<link rel="stylesheet" media="screen" href="@routes.Assets.versioned("lib/font-awesome/css/font-awesome.min.css")">
	<!-- PNotify -->
	<link rel="stylesheet" media="screen" href="@routes.Assets.versioned("lib/pnotify/pnotify.css")">
	<link rel="stylesheet" media="screen" href="@routes.Assets.versioned("lib/pnotify/pnotify.nonblock.css")">
	<!-- query-builder -->
	<link rel="stylesheet" media="screen" href="@routes.Assets.versioned("lib/jQuery-QueryBuilder/css/query-builder.default.min.css")">

	<link rel="shortcut icon" type="image/png" href="@routes.Assets.versioned("images/favicon.png")">

	<!--DataTable dependencies -->
	<link rel="stylesheet" media="screen" href="@routes.Assets.versioned("lib/datatables/dataTables.bootstrap.min.css")">
	<link rel="stylesheet" media="screen" href="@routes.Assets.versioned("lib/datatables/buttons.dataTables.min.css")">

	<!-- jQuery UI -->
	<link rel="stylesheet" media="screen" href="@routes.Assets.versioned("lib/jquery-ui/jquery-ui.css")">

	<!-- Boostrap DateTime-Picker -->
	<link rel="stylesheet" media="screen" href="@routes.Assets.versioned("lib/bootstrap-datetimepicker/bootstrap-datetimepicker.min.css")">

	<!-- iCheck -->
	<link rel="stylesheet" media="screen" href="@routes.Assets.versioned("lib/iCheck/all.css")">
	<link rel="stylesheet" media="screen" href="@routes.Assets.versioned("lib/iCheck/square/blue.css")">

	<!-- Main CSS: Bootstrap + AdminLTE + Custom css -->
	<link rel="stylesheet" media="screen" href="@routes.Assets.versioned("stylesheets/main.min.css")">
    </head>
    <body style="height:auto;" class="skin-darkblue-light fixed home-page">
        <script type="text/javascript" src="@routes.Assets.versioned("lib/mxgraph2/js/mxClient.js")"></script>
	<script type="text/javascript" src="@routes.Assets.versioned("editor/editor.js")"></script>
	<script type="text/javascript" src="@routes.Assets.versioned("editor/graph.js")"></script>

	<div class="container">
	    <div module="HeaderModule">
	        @header()
	    </div>

	    <div module="MainModule">
	        <div controller="HomeController"></div>
		</div>

		<div class="navbar-fixed-bottom">
		    @footer()
		</div>
	    </div>

	    <script type="text/javascript" data-main="@routes.Assets.versioned("javascripts/main")" src="@routes.Assets.versioned("lib/requirejs/require.min.js")"></script>
    </body>
</html>

After creating the template, you now need to create an endpoint to return this view and register it in the system.

So, to create the endpoint you add a new controller at app > controllers or add a function to an existent controller. In this example we will create a new controller called HomeController.java:

public class HomeController extends Controller {
    @Security.Authenticated(Secured.class)
    public Result index() {
        return ok(views.html.home.render());
    }
}

And, then, to register it, add to:

  1. conf > routes:
...

GET               /home                    controllers.HomeController.index()

...
  1. app > controllers > Application.java > javascriptRoutes():
public Result javascriptRoutes() {
    response().setHeader(Http.HeaderNames.CONTENT_TYPE, "text/javascript");
    return ok(JavaScriptReverseRouter.create("jsRoutes",
        ...,

        routes.javascript.HomeController.index(),

        ...
    ));
}

Creation of a UI component (handlebars)

Once the URL for the base view is configured, the next step is to create the functional files that handle frontend and backend of the UI element. So, we will create a folder home at app > assets > javascripts. Inside this folder create tho files: homeController.js and homeView.js.

The homeController.js is responsible to handle the backend operations and should follow a structure similar to this:

define('HomeController', ['Controller', 'HomeView', 'Router', 'Institution', 'Task', 'Alert', 'jquery', 'jsRoutes', 'jquery-cookie'], function (Controller, HomeView, Router, Institution, Task, Alert, $, jsRoutes) {
    const HomeController = function (module) {
        Controller.call(this, module, new HomeView(this));
    };

    // Inheritance from the superclass
    HomeController.prototype = Object.create(Controller.prototype);
    const _super_ = Controller.prototype;

    HomeController.prototype.initialize = function ($container) {
        _super_.initialize.call(this, $container);

	this.getTasks();
    };

    HomeController.prototype.getTasks = function () {
        const context = this;
	Institution.getInstitutions(function (institutions) {
	    context.view.loadInstitutions(institutions);
	});
    };

    return HomeController;
});

On the other hand, the homeView.jsis responsible for frontend interactions and should follow a structure similar to:

define('HomeView', ['jquery', 'View'], function ($, View) {
    const HomeView = function (controller) {
        View.call(this, controller, 'home');
    };

    // Inheritance from super class
    HomeView.prototype = Object.create(View.prototype);
    const _super_ = View.prototype;

    HomeView.prototype.initialize = function ($container) {
        _super_.initialize.call(this, $container);
    };

    HomeView.prototype.loadInstitutions = function (institutions) {
        const html = JST['home']({
	    institutions: institutions
        });
    	this.$container.html(html);
	this._loadViewComponents();
    };

    return HomeView;
});

As can be seen in this last code snippet, we "import" a web (HTML) structure from 'home'. This refers to the file home.handlebars that must be placed at app > assets > templates. Hence, we will create this exact file in the specified location with the following content:

<div class="main-div">
    <div class="title">
        <h1><b><i class="fa fa-hospital-o"></i> Dashboard: Resources</b></h1>
    </div>

    <div id="institutions" view-element="institutions" class="row">
        {{#institutions}}
            <div class="institution col-lg-4">
                <div class="panel panel-default">
                    <div class="panel-heading">
                        <h3 class="panel-title"><b>{{name}}</b></h3>
                    </div>
                    <div class="panel-body">
                        <ul class="treeview-menu" data-widget="tree">
                            <!-- Tasks -->
                            <li class="treeview menu">
                                <a name="tasks">
                                    <i class="fa fa-folder"></i> <span>Tasks</span>
                                    <span class="pull-right-container">
                        	        <i class="fa fa-angle-left pull-right"></i>
                    		    </span>
                                </a>
                                <ul class="treeview-menu">
                                    {{#tasks}}
                                        <li>
                                            <a <i class="fa fa-file-text-o"></i>
                                                <span>{{name}}</span>
                                            </a>
                                        </li>
                                    {{/tasks}}
                                    <li>
                                        <form class="sidebar-form">
                                            <div class="input-group">
                                                <input name="taskName" class="form-control" placeholder="Create a new task..."/>
                                                <span class="input-group-btn">
                                    		    <button type="submit" class="btn btn-flat">
                                      		        <i class="fa fa-plus-circle"></i>
                                    		    </button>
                                		</span>
                                            </div>
                                        </form>
                                    </li>
                                </ul>
                            </li>

                        </ul>
                    </div>
                </div>
            </div>
        {{/institutions}}
    </div>
</div>

The next step is to tell the system where the newly-created resources are. So, at app > assets > javacripts > main.js add the following:

requirejs.config({
    baseUrl: '/assets/javascripts',
    paths: {
        ...,

        // Home
	'HomeController': 'home/controllers/homeController',
	'HomeView': 'home/views/homeView',

        ...
    },
    ...
});

var DEBUG = true;

require(['Application'], function (Application) {
    window.app = new Application();
});

Last, but not least, we have to create the RegExp handler, as said earlier, so the system know what controllers and tools to load in the specific UI stage, at app > assets > application > application.js:

define('Application', ['jquery', 'Router', 'Module', 'jsRoutes', 'Svg', 'Institution', 'adminLTE', 'custom.jquery'], function ($, Router, Module, jsRoutes, Svg, Institution) {
    ...

    Application.prototype.initialize = function () {
        var self = this;

	// Configure router
	Router.config({mode: 'history'});

	// Add routes
	Router
            .add(new RegExp(jsRoutes.controllers.login.Login.index().url.substr(1), 'i'), function () {
	        console.log("LOGIN PAGE");
	    })
            ...
            .add(new RegExp(jsRoutes.controllers.HomeController.index().url.substr(1), 'i'), function () {
	        console.log("homepage");

	        self.loadControllers('MainModule', ['HomeController']);
	    });
    };

    ...

    return Application;
});

With this, we will be able to have a web page similar to this image, based on an entirely new HTML template: Final web page