AngularFaces: Calling AngularJS Controllers via a:angularButton

Fork me on GitHubThis article concentrates on the AngularJS side of an AngularFaces application.

The standard AngularJS approach to calling a controller function is adding an ng-submit attribute to the <form> tag. In a JSF application, this isn’t a good idea. It might make Angular intercept button clicks intended to be send to the server.

To avoid the problem, AngularFaces offers the <a:angularButton> tag.

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. Have a look at the tutorial at AngularFaces.com if you’re interested in AngularFaces 2.0 and above.


I’ll demonstrate the a:angularButton with a simple example:

AngularFaces: Calling AngularJS Controllers via <a:angularButton>

The first button calls an Angular controller function without parameters. The second button passes the last name as a parameter to a function. After filling the input fields an clicking the second button, the page looks this way:

AngularFaces: Calling AngularJS Controllers via <a:angularButton>

Let’s start with the AngularJS controller function. It consists of a single function – howdy() – taking a parameter and showing a message box. If the function is called without a parameter, the message box simply says “Hello Angular”. Otherwise the user is greeted.

function userBeanController($scope) {
  $scope.howdy = function(name) {
  if (name)
    alert("Howdy, " + name + "!");
  else
    alert("Howdy, Angular!");
  }
}
var app = angular.module('userBeanApp', []);

The view is defined like so:

  <a:body ng-app="userBeanApp" ng-controller="userBeanController">
    <h:form ng:name="myform" >
      <h:panelGrid columns="3">
        <a:inputText value="#{userBean.firstName}"/>
        <a:inputText value="#{userBean.lastName}"/>

        <a:angularButton value="Howdy!" 
                         ng-function="howdy" />
        <a:angularButton value="Howdy {{firstName}} {{lastName}}!" 
                         ng-function="howdy($scope.lastName)" />
        <h:outputText value=""/>
        <h:outputText value="calls howdy();"/>
        <h:outputText value="calls howdy('{{lastName}}');"/>
      </h:panelGrid>
    </h:form>
    <h:messages />
  </a:body>

The angular buttons must have an attribute ng-function. This refers to a function in the Angular controller (i.e. userBeanController in our example) which is called when the button is clicked. Other than that, the button is almost a standard Primefaces button and takes almost every attribute allowed by Primefaces. I only omitted the JSF related attributes (i.e. action and actionListener) and onclick.

You can also pass parameters to the function. The function is executed within the controller, giving you access to the controller scopes variables:

<a:angularButton ng-function="howdy($scope.lastName)" />

Alternatively you can use Angular’s double curly braces to pass a model value:

<a:angularButton ng-function="howdy('{{lastName}}')" />

Maybe you noticed the input fields don’t have a label. AngularFaces tries to guess the label from the variable name. Camel cases and underscores are treated as blanks. This may come in handy for rapid prototyping.

Oh, and there’s also a JSF controller class. It isn’t that important in our present example, but of course you can’t do without.

@ManagedBean
@RequestScoped
public class UserBean implements Serializable {
   @NotNull
   @Size(min=3, max=20)
   String firstName;
   
   @NotNull
   @Size(min=1, max=20)
   String lastName;
}

AngularFaces brings most of the annotations to the client. @NotNull is translated to a JSF required="true" attribute, and @Size(max=20) limits the width of the input field and the number of characters you can type. More precisely, the attributes maxlength and size are set to 20.

Conclusion
The AngularFaces project has just started, and there’s a lot to do. But even so I suppose it might be useful for many use cases. Feel free to clone my GitHub repository and get familiar with AngularFaces.

Maybe I should add on final word: AngularFaces is not a mature project yet. You may use it, but at own risk.


Further reading:
AngularFaces’ source code. You can participate with the project by forking AngularFaces and sending me a pull request.
live demo of AngularFaces on OpenShift.

3 thoughts on “AngularFaces: Calling AngularJS Controllers via a:angularButton

  1. Pingback: AngularFaces: Calling AngularJS Controllers via...

  2. sebastien

    When i first saw angularJS, i also thought a interaction with JSF. But may be what would be very cool would be to write JSF implementation that depending of the bandwidth, user preferences etc, would run the server code on the client side (backing beans, EJBs and even related libs) for instance by compiling the code both in java and javascript and implementing a framework to call a method locally or remotely depending where is the code. We could even imagine with datachannels that the JS is executed on peers. Yes i’m day dreaming… but that would be a nice evolution to the client/server model no ? :)

    Reply
    1. Stephan Rauh

      GWT already contains a Java-to-Javascipt cross-compiler, porting a lot of beans to the client. Vaadin is a version of GWT leaving most of the logic on the server. So we know it’s possible to implement your dream, at least partially. However, I suppose it’s not possible to use the existing Java infrastructure. Re-implementing EJB in Javascript sounds like a chore to me. But it might be possible to port AngularJS to the server, and to create a new infrastructure supporting both the client programming model and the server programming model.

      Reply

Leave a Reply

Your email address will not be published.

CAPTCHA Image

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>