Single-Page Applications With BootsFaces

Singe-page applications have become tremendously popular in the last couple of years. They are fast, they are responsive and they can save network bandwidth. The first SPAs that caught the attention of the community were based on JavaScript. So nowadays everybody seems to believe you can’t write an SPA with JSF.

But you can. It’s not even difficult. And it pays: the application becomes much more responsive. This article shows two approaches how to do it with BootsFaces. I’m sure you can do the same with other JSF frameworks like PrimeFaces, too, but I didn’t test it yet.

Currently, there are at least two approaches. You can exploit BootsFaces AJAX to do your navigation, or you can add AngularJS to the equation. The latter approach requires you to learn both Angular and JSF, but it may be useful because it allows you to use client-side AngularJS components.

But first things first.

What is a Single Page Application?

A single page application is an application that doesn’t use full-page refreshs for navigation. Instead, SPAs use JavaScript to exchange parts of the DOM tree to navigate to another dialog. That doesn’t necessarily mean there’s no server access. It’s possible to load the entire application at startup time. But that approach doesn’t always work. Little is won when the application is super-fast – but takes five minutes to boot.

So modern SPA frameworks like Angular load HTML snippets when navigating to another dialog. The snippets tend to be small and static, so it’s a fast server request. And it’s a lot faster than non-AJAX navigation. The AJAX request loads a single HTML snippet. Maybe it also loads a small CSS file and a Json object. But that’s it. A non-AJAX request loads every CSS file, every JavaScript file, the entire HTML file and possibly even fonts. That takes a while. Some time ago I had to maintain a JSF application running on Liferay doing 125 request on every page navigation. When we added AJAX, this went down to half a dozen requests. Luckily, most application server don’t add as much overhead. Our showcase application starts 40 requests per navigation, give or take a few. The CombinedResourceHandler of OmniFaces reduces this to 9. AJAX navigation requires only a single request, plus a request for every image on the page.

The second advantage of SPAs are that the browser doesn’t have to re-render the entire page. Nor does it have to run all the JavaScript files. In the case of Angular 1.x, initializing Angular costs a couple of seconds. And that’s only one of your libraries. Initializing the other JavaScript libraries takes some time, too.

We’ve designed BootsFaces to be fast, but even so, switching from traditional navigation to the SPA approach makes the application feel a lot faster.

The simple JSF-only approach

Forget everything you’ve learned about JSF templates. JSF SPAs work the other way round. Instead of embedding your JSF page into a template, the main page actively includes the JSF fragments. Putting it a bit more technical, you replace <ui:composition /> by <ui:include />. Here’s a very simple main page written with BootsFaces 0.8.1:

<html ...>
<h:head />
<h:body>
 </b:container>
  <b:row>
    <b:column span="2">
      <h:form>
        <b:flyOutMenu width="150px">
          <b:navLink value="Start page" 
             update="@form @(.content)"
             onclick="ajax:navigationBean.setPage('start.xhtml')" />
          <b:navLink value="Register yourself" 
             update="@form @(.content)"
             onclick="ajax:navigationBean.setPage('register.xhtml')" />
        </b:flyOutMenu>
      </h:form>
    </b:column>
    <b:column span="10" class="content">
      <ui:include src="#{navigationBean.page}" />
    </b:column>
  </b:row>
 </b:container>
</h:body>
</html>

Let’s examine line 19 first. It’s an include statement which loads a page fragment. The nice thing about JSF include statements is that they don’t have to be static. They are allowed to use EL expressions. So we load the name of the current fragment from the navigation bean, which happens to be a very simple class:

@Named
@SessionScoped
public class NavigationBean implements Serializable {
  private String page="start.xhtml";

  // plus getter and setter
}

The other interesting part are the AJAXified navlinks (lines 9-14 of the XHTML file). That’s a feature of BootsFaces 0.8.1. We haven’t published this version yet, so this post is sort of an announcement post. However, I expect we will publish this version very soon. In the meantime, we’ve published developer snapshots at MavenCentral, so you can already give it a try. See our description on how to get the developer snapshot.

Basically, the AJAXified navlinks don’t do much, either. They call a setter to update the name of the current JSF page fragment. After that, the content area – that’s basically the <ui:include /> – is re-rendered.

The JSF pages to include are not full-blown JSF pages, but only JSF fragments containing the code you want to put into the content area:

<ui:fragment xmlns="http://www.w3.org/1999/xhtml" ... >
  <b:panel title="Registration form" look="primary">
       ...
  </b:panel>
</ui:fragment>

That’s it!

Demo source code is available at my GitHub repository. Feel free to convince yourself!

Troubleshooting

There’s a small but annoying catch. BootsFaces tries to keep the number resource file loaded with each request small. So you have to load every CSS and JavaScript file at startup time. Luckily, that’s easy: add a hidden panel to the index.xhtml and add every component you need:

  ...
  </b:container>
  <h:panelGroup rendered="false">
    <b:inputText />
    <b:switch />
    <b:message />
    <b:messages />
  </h:panelGroup>
</h:body>
</html>

Alternatively, you can use a custom theme. Most custom Bootstrap themes I’ve seen are all-in-one files including the CSS and JavaScript code of every component. Or rather, of most elements: several components of BootsFaces require CSS or JavaScript files that are not part of the Bootstrap distribution files. By the way, you can also include the Bootstrap default theme as custom theme.

Update Jan 14, 2016: What about the history?

I just read Stefan Tilkov’s flame “Why I hate your Single Page App”. It’s a highly recommended read, and it showed me the shortcomings of my approach: there’s no bookmarkable URL, no URL history, no working “back” button. I opened an issue on the BootsFaces bug tracker to solve this problem.

I don’t think it’s a big deal to implement an advanced <b:include /> tag, but until then, I’d like to give you a hint how to solve the problem yourself:

  • Have a look at history.js. That’s a small JavaScript library that allows you to rewrite the current URL. Use this on every AJAX request to add a fragment to the URL. For the sake of simplicity, you can use the name of the JSF file to include as fragment name.
  • Use the PreRenderViewEvent to set the target page within the navigation bean.

Currently, I don’t have the source code at hand, but I’ve done precisely this in the past, so I know you can do it, too.

But there’s also a simpler approach. Well, it’s debatable whether it’s simpler or not, but it doesn’t require you to rewrite the URL yourself. Let AngularJS do the trick for you.

The sophisticated AngularJS approach

Currently, I’m reluctant to recommend AngularFaces because it doesn’t support Angular2 yet. Nonetheless, using the AngularJS router is another interesting approach to turn a JSF application into an SPA.

Like above, forget everything you’ve ever learned about JSF templates. You need to write a start page that actively include JSF page fragments. AngularFaces uses AngularJS 1.3, so the include is done by an ng-view directive:

    <b:container ng-app="navigationApp">
      <div ng-view="">
      </div>
    </b:container>

The AngularJS controller uses a traditional AngularJS router, so there are no surprises here:

var navigationApp = angular.module('navigationApp', [ 'ngRoute',
		'navigationControllers' ]);

navigationApp.config([ '$routeProvider', function($routeProvider) {
	$routeProvider.when('/hidingColumns', {
		templateUrl : '2_layout/hidingColumns.jsf',
		controller : 'EmptyController'
	}).when('/', {
		templateUrl : '1_intro/start.jsf',
		controller : 'EmptyController'
	}).otherwise({
		templateUrl : '99_miscellaneous/other.jsf',
	});
} ]);

When I investigated this approach, I was pretty surprised that JSF isn’t limited to delivering complete JSF pages. It can also render HTML fragments. So the page snippets to be included by the AngularJS router look like so:

<ui:fragment xmlns="http://www.w3.org/1999/xhtml" ... >
  <b:row>
    <b:column col-md="12">
       ...
    </b:column>
  </b:row>
</ui:fragment>

A nice side effect is that these page snippets contain less syntactical clutter than a traditional <ui:composition />.

Using Angular allows you to use client-side components. In this example, I’ve added a navigator widget to the page:

<ui:fragment xmlns="http://www.w3.org/1999/xhtml" ... >
  <b:row>
    <b:column col-md="12">
       ...
    </b:column>
  </b:row>
  
   <navigator up="#keyFeaturesAF" down="ngComponents" right="integration"/>
</ui:fragment>

To navigate to another JSF page (or rather: JSF snippet), you add another fragment to the browser URL. For example, navlinks looks like so:

<b:navLink value="Start"             fragment="#start" />
<b:navLink value="Register yourself" fragment="#register" />

It goes without saying that you should avoid AJAX with the AngularJS approach. I’ve spent a lot of time to enable AJAX with AngularFaces, but still, I believe it’s better to replace AJAX by native AngularJS code.

Beware of the memory leak

There’s a small drawback to any SPAs, including JSF based SPAs. If your JavaScript code contains a memory leak, it grows over time. In particular, it’s very important to destroy jQuery widgets after disposing the part of the DOM they are used by. The PrimeFaces team told me a couple of years ago that they’ve solved their JavaScript memory leaks. Currently, these memory leaks are an open ticket in our BootsFaces bug tracker. I believe the memory leaks isn’t that bad. You can work a long time before noticing. But still, until we’ve solved the issue, you should be aware of the problem. Of course, every non-AJAX navigation or simply pressing the F5 key solves the problem for the next couple of hours.

Wrapping it up

Turning JSF applications into SPAs has many advantages. The applications are faster and much more responsive. There’s less load on your server and the network. And there’s another advantage: most developers who are new to JSF have a hard time to understand the templating concept. My approach to SPAs replaces JSF templates by a technique almost every developer is familiar with: include files. So newbies will need less time to get familiar with your JSF pages.

15 thoughts on “Single-Page Applications With BootsFaces

  1. Vladimir Dvorak

    Hi Stephan, nice article, I really appriciate your work for JSF world. We have been using approach for single page application since 2008-2009 and it works perfectly, having quite big application (~500 pages). It had been based on RichFaces and in 2012 we have migrated it to Primefaces using tag wrappers around common JSF components. I can’t imagine to do such difficult refactorization in any javascript framework…

    Reply
    1. Stephan Rauh Post author

      Thanks for your kind words! Plus, it’s good to learn that my approach works on a large scale, too.

      Well, I guess you’re right with your remark concerning JavaScript. However, currently I spend a lot of time investigating TypeScript and Angular2. I believe TypeScript might be a game-changer. It has got all you need to do a large-scale refactoring: classes, type safety, a powerful module system. Whether it’s going to be commercially successful is another question (and most likely a question of corporate politics). But from a technological point of view, it’s very promising, and it is very attractive to Java programmers. Even to enterprise Java programmers.

      Reply
      1. Vladimir Dvorak

        I’m little doubtfull to use javascript framework for large scale and long-term lived application now. Javascript world is extremely rapid evolving platform and to base such kind of application on some framework that would be possibly abandoned in the future is risky. I have no problem to use it for small application. I think this is one of reasons why the javascript is not adopted by industrial sphere anyway. Another reason is the fact that application logic is exposed on client side, that leads to strong security checks on server side. As I mean there will be always necessity for server side solutions. Btw I would welcome if some kind of bytecode level processing would be adopted in the future on client side since “One language to rule them all” smells .

        Reply
        1. Stephan Rauh Post author

          I guess the new byte code is already there. It’s called “JavaScript”. The idea being that developers use other languages, such das TypeScript, PureScript, CoffeeScript or Dart, and compile to JavaScript. IMHO, TypeScript really look promising. Of course, you’ve mentioned a lot of important points that need to be evaluated first. Some time ago, I’ve written an article about the future of JavaScript as an assembler language.

          Maybe you might be interested in AngularFaces. The idea of AngularFaces is not to expose the entire logic to the client. It’s to smooth out a couple of rough edge of JSF. Validations on the client side make for a more responsive application, and sometime it’s easier to implement a complex validation on the client. Sometimes it’s easier to do it on the server. That’s the key benefit of AngularFaces: it gives you the freedom of choice.

          Reply
  2. Vladimir Dvorak

    Thank you for reference, it is really interesting project. I’m just working on an example application for HotswapAgent based on Deltaspike/JSF/Primefaces, may be I can add AngularFaces to learn it little bit more. I’would like to create some simple skeleton consisting of login and user administration using strict MVC separation. What is strange, I haven’t seen such kind of skeleton application anywhere, may be I’ve missed something.

    Reply
    1. Stephan Rauh Post author

      Just a wild shot: you haven’t seen such a strict MVC separation because it’s difficult to maintain your idea in JSF? No offense intended, it’s just a guess. Also see my article Model-View-Whatever.

      Reply
  3. Vladimir Dvorak

    Ok, thanks again. Back to single page application. I would have one experience with our project. May be you will be interested. We have application with root page split into several areas and each of them uses <ui:include />. Area on the right side of root page can use many (hundreds) different sources (xhtmls). And lets image situation : you want to fix some problem on some page and you cant remember the name of source file. I’ve struggled with it many times since my memory is not masterpiece of nature anyway. Some time ago I’ve created firebug extension – firerunner (https://github.com/skybber/firerunner) that simplifies this task as much as possible. Using this tool you are able to show all sources in firebug and clicking on name the file name you can open source directly in your favourite already running IDE.

    Reply
  4. Anonymous

    Hi there

    Very nice article, i tried as described and it went very well.
    But all the b:commandButton’s I have within the included pages (ui:fragment’s) are not able to invoke anything inside my managed beans.

    Do you have any hints on that?

    Thank you very much,

    Reply
    1. Stephan Rauh Post author

      Thanks! Talking of the view state: the approach I described has the disadvantage that it never updates the internal, hidden viewState field of the JSF page. That’s a potential security leak (replay attacks and CSRF). Please be careful. You might want to add your own finger print sent with each AJAX request in order to protect your application.

      Reply
  5. Emilio

    Hello, first of all, very nice article. I’m about to develop a large scale enterprise app and found your article really useful to implement SPA strategy using JSF.

    Despite JavaScript is the hype of the moment, I’m still not convinced it is the future of enterprise apps.

    I did all the steps you explained in this article but I’m unsure if the page updates only the content part instead of full load. I added couple of links under accordeon component and whenever I click on a link, accordeon is closed, I mean, it returns to its initial state. Are you sure only “content” is being updated?

    Reply
  6. Edem Morn

    Hi,

    I make use of a lot of and to invoke actions when loading my pages. Will that still work with an SPA approach? How do I pass parameters to the page I in include in the ?

    Reply
    1. Stephan Rauh Post author

      Well, you don’t loose anything. SPAs based on BootsFaces or PrimeFaces are just AJAX applications. The only difference is that you’re using AJAX for navigation, too. The traditional approach uses non-AJAX requests.

      You have to keep an eye on the memory consumption of your browser. It’s so easy to introduce memory leaks when updating JavaScript widgets with AJAX. So I’m sure we JSF library developers do it all the time. The PrimeFaces guys took a lot of pains to get rid of the problem a couple of versions ago. We, the BootsFaces team, didn’t hear any complains about memory consumption yet, so chances are both PrimeFaces and BootsFaces work reasonably well with an SPA. However, if you observe excessive memory consumption, please tell us so we can fix it.

      Reply

Leave a Reply

Your email address will not be published.