AngularFacesAngularJSJavascriptJSF

AngularFaces: Synchronize Angular Models With JSF Beans

Introducing <a:sync>

Fork me on GitHubThis component is different.

Thus far every AngularFaces component was essentially a JSF component with some AngularJS sugar on top of it. <a:sync> works the other way round. It enables a pure AngularJS application to benefit from the JSF engine. Every time a JSF request is submitted, <a:sync> moves parts of the AngularJS model to the JSF bean’s attributes. A little later, when the response is send to the client, <a:sync> injects JSF bean attributes into the model of AngularJS.

Strictly speaking, the “a” prefix of the library makes <a:sync> sort of a misnomer. It’s not about doing thing in an asynchronous way. It’s about synchronizing AngularJS models with JSF beans.

Update Sept 16, 2014
AngularFaces 2.0 takes a different – and better – approach to adding fuctionality to JSF. This article describes the older version AngularFaces 1.0. However, <a:sync> is also part of the new version. Now it’s called <ngsync>, and synchronizing data from the client back to the server has been postponed to version 2.1 of AngularFaces. Have a look at the tutorial at AngularFaces.com if you’re interested in AngularFaces 2.0 and above.

How it’s used

<a:sync> takes two parameters:

  • value denotes the JSF bean’s attribute.
  • direction can take three values:
    direction="clientToServer" and direction="serverToClient" makes <a:sync> send data in one direction only. To achieve real two-way-synchronization set direction to both, or simply omit the parameter (direction="both" is the default value).

The value attribute also defines the AngularJS model attribute. For the sake of simplicity, only the term following the last dot is used as AngularJS attribute name. For instance,

<a:sync direction="both"
        value="#{amortizationPrinterBean.interestRate}" />

injects the interest rate into $scope.interestRate.

Dealing with objects

Values can be both elementary bean attributes – ints, doubles, strings, just to name a few – and objects. Basically you can synchronize every object that can be serialized by Google’s Gson library. You can send almost every object from the server to the client. However, when it comes to sending data to the server, there’s a catch: type erasure. Gson cannot reconstruct generic data structures such as ArrayList and HashMap. If you need to send such a data structure to the server, you’ll have to wrap it in a non-generic class.

AngularJS bootstrap

AngularFaces has to re-init AngularJS after each request. Unfortunately this means every variable of the scope is lost. Best you simply synchronize every important variable with the back end. <a:sync’s> ability to synchronize entire objects should make this an easy task.

<a:sync> live demo

There’s a tiny live demo at the showcase of AngularFaces. It’s a simple loan calculator. Simple calculations are done on the client. But when it comes to generating the amortization table, storing it in a document management system and exporting it as a PDF file, you’re probably better of with Java. So the amortization table is calculated on the server when the command button is hit.

I mentioned above <a:sync> allowes for pure AngularJS applications. Obviously, “pure” is a little exaggeration. AngularFaces applications want to use JSF, so they need a small JSF skeleton. But you can write an application consisting of an AngularJS part and an JSF part living in peaceful coexistence. They exchange data via <a:sync>, and that’s it. So you’re free to chose a fairly loose coupling via <a:sync> or a much stronger coupling using the other AngularFaces components, such as <a:inputText>.

<f:view xmlns="http://www.w3c.org/1999/xhtml" 
        xmlns:f="http://java.sun.com/jsf/core"
        xmlns:h="http://java.sun.com/jsf/html" 
        xmlns:ng="http://xmlns.jcp.org/jsf/passthrough" 
        xmlns:a="http://beyondjava.net/angularFaces">
  <h:head />
  <a:body ng-app="loanCalculatorApp" 
          ng-controller="loanCalculatorController">
     <h:form ng:name="myform">

        <!-- AngularJS code -->
        interest rate:
        <input type="number" ng-model="interestRate" 
               size="4" maxlength="4" 
               min="0" max="20" />
        % p.a.
        <!-- end of AngularJS code -->

        <a:sync direction="serverToClient"
               value="#{amortizationBean.amortizationPlan}" />
        <a:commandButton 
               action="#{amortizationBean.generateAmortizationPlan}" />
     </h:form> 
   </a:body>
</f:view>

Javascript API

AngularFaces didn’t implement a Javascript API yet, but probably you don’t need it, anyways. In most cases it suffices to render an invisible command button (using CSS, not using rendered='false'!) and to simulate a button click via Javascript.


Further reading

AngularFaces showcase
AngularFaces source code on GitHub


3 thoughts on “AngularFaces: Synchronize Angular Models With JSF Beans

  1. <html>
    
    <f:view xmlns="http://www.w3c.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html" xmlns:ng="http://xmlns.jcp.org/jsf/passthrough"
      xmlns:a="http://beyondjava.net/angularFaces">
      <h:head />
    
      <body class="ng-scope" onload="restoreValues()" ng-controller="dashboardsController" ng-app="dashboardsApp">
    
        <!-- thirdparty libs -->
        <script src="../../Scripts/angular.js"></script>
        <script src="http://showcase.angularfaces.com/resources/AngularFaces/glue.js"></script>
        <script src="../../Scripts/jquery.js"></script>
        <script src="../../Scripts/jquery-plugins.js"></script>
        <script src="../../Scripts/primefaces.js"></script>
        <script src="../../Scripts/validation.js"></script>
        <script src="../../Scripts/beanvalidation.js"></script>
        <script src="../../Scripts/bootstrap.js"></script>
    
    
        <!-- Application libs -->
        <script src="../../app/app.js"></script>
        <script src="../../app/controllers/controllers.js"></script>
        <script src="../../app/services/dashboardService.js"></script>
    
    
        <h:form ng:name="myform">
          <!-- AngularJS code -->
      		dashboard Type:  <input type="string" ng-model="dashboardType" />
          <!-- end of AngularJS code -->
          <a:sync direction="both" value="#{adpiFormBean.dashboardFormBean.dashboardType}"></a:sync>
        </h:form>
      </body>
    </f:view>
    </html>
    

    I also tried to using lt a:body gt tag instead of just lt body gt tag wihout a as prefix. Former don’t calls the onLoad() function and later showing below error
    angular.element(‘body’) => Error: selectors not implemented.

    Although I’m seeing the bean value getting populated in the lt a:sync gt value attribute but its not getting inject into $scope.
    lt a:sync value=”MyDashboards” direction=”both” gtlt /a:sync gt

    Thanks,
    Nitin

    1. AngularFaces requires <a:body>. That’s where most of its magic is implemented. It’s also important to load the Javascript libraries in the correct order. Best you just leave it to AngularFaces. Just omit the imports, as I did in the showcase examples. Most likely that’s what caused the problem.

      <f:view xmlns="http://www.w3c.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
        xmlns:h="http://java.sun.com/jsf/html" xmlns:ng="http://xmlns.jcp.org/jsf/passthrough"
        xmlns:a="http://beyondjava.net/angularFaces">
        <h:head />
      
        <a:body class="ng-scope" ng-controller="dashboardsController" ng-app="dashboardsApp">
          <!-- thirdparty libs -->
          <script src="../../Scripts/bootstrap.js"></script>
      
          <!-- Application libs -->
          <script src="../../app/app.js"></script>
          <script src="../../app/controllers/controllers.js"></script>
          <script src="../../app/services/dashboardService.js"></script>
      
          <h:form ng:name="myform">
            <!-- AngularJS code -->
             dashboard Type:  <input type="string" ng-model="dashboardType" />
            <!-- end of AngularJS code -->
            <a:sync direction="both" value="#{adpiFormBean.dashboardFormBean.dashboardType}"></a:sync>
          </h:form>
        </body>
      </f:view>
      </html>
      
  2. Hi Stephan,

    Thanks a ton for all the help and guidance.

    <a:body> tag works great and does most of the stuff. I tested the above mentioned steps by you and deploy the app in Tomcat and it looks great.

    But we are using Websphere Application Server liberty profile 8.5, which is not allowing me to add javax.faces.jar file, which is required by NGResponseWriter class in order to extend HtmlResponseWriter. So I just implemented the logic for NGResponseWriter class in Javascript itself to make it work with WAS 8.5

    I also added ‘data-‘ as prefix for all the ‘ng-tags’ after removing the prefix ‘a’ from the ‘body’ tag. I was seeing ‘AngularJS hasn’t been initialized properly’ alert message without the ‘data-‘ as prefix.
    Again everything was working as expected when I was using tomcat along with a:body tag even without the ‘data-‘ as prefix to the ‘ng-tags’.

    Thanks for the wonderful example.

    -Nitin Talwar

Leave a Reply

Your email address will not be published.