Skip to content

Traversing the maze of HTML rendering

Geoff Bourne edited this page Jan 10, 2016 · 1 revision

There's a few layers of magic that takes place to ultimately render the DOM of the MinCCY application, as the user sees it.

First, the embedded Tomcat + Spring MVC gets a request for

GET / 

which in controllers/ViewController.java maps to the view called "index"

@RequestMapping("/")
String index() {
    return "index";
}

Spring MVC goes off and looks for things that'll satisfy the view called "index". A feature of Spring Boot it that is has wired in Freemarker template support and it knows to look in the classpath under templates, which originates from src/main/resources/templates in the source structure.

So far the only model attribute (variables that feed into the view, the Freemarker template in this case) I inject is the new, optional deploymentPoweredBy

@ModelAttribute("deploymentPoweredBy")
public MccySettings.DeploymentPoweredBy deploymentPoweredBy() {
    return mccySettings.getDeploymentPoweredBy();
}

but as another case the "login" view injects the CSRF token

@RequestMapping("/login")
ModelAndView loginPage(HttpServletRequest request, HttpServletResponse response, Model model) {
    response.addHeader("x-login", "true");

    CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class
            .getName());

    final ModelAndView modelAndView = new ModelAndView()
            .addObject("csrf", csrf);
    modelAndView.setViewName("login");

    return modelAndView;
}

that becomes a hidden input in the login form:

<input type="hidden" name="${csrf.parameterName}" value="${csrf.token}" />

where ${csrf.parameterName} is a Freemarker variable reference that dips into the model attribute csrf supplied by the Java code above.

Back to the templates, both the rendered "index" and "login" views are basically a mashup of the common pieces (Javascript/CSS references, etc) under templates/ftl-bits

The next major layer, is the DOM-level switch-out driven by the ng-view placeholder in the rendered "index":

    <div class="col-md-10">
        <div class="row" ng-view>

        </div>
    </div>

In js/routes.js I have declared the mapping of routes to views+controllers (an Angular controlle, not the Spring MVC controller shown above in Java land):

 .config(function ($routeProvider) {
    $routeProvider
        .when('/view', {
            templateUrl: 'views/view-containers.html',
            controller: 'ViewContainersCtrl'
        })
        .when('/new-server', {
            templateUrl: 'views/create-container.html',
            controller: 'NewContainerCtrl'
        })
        // ...and more
        .otherwise('/view')
})

Towards the end of this crazy maze, is the use of ng-include directives like

    <div ng-repeat="c in containers" class="panel panel-default" ng-include="'ng-bits/current-container.html'">
    </div>

from views/view-containers.html

One last twist in the DOM snippets inclusion maze is a custom Angular directive here and there, like the mods managements makes use of the following from js/mods.js

.directive('mccyModPanel', function(){

    //... controller stuff

    return {
        templateUrl: 'ng-bits/mod-panel.html',
        restrict: 'A',
        scope: {
            mod: '=mccyModPanel',
            showDelete: '=mccyModPanelShowDelete'
        },
        controller: controller
    }
})

where that templateUrl is specifying an HTML snippet to use as the directive template. To keep myself sane, my convention is to put both ng-include and templateUrl target snippets under static/ng-bits...hence the vague term "bits".

Clone this wiki locally