There is no doubt that AngularJS has been one of the hottest front end frameworks around for quite some time now and there is a fair bit of interest in it from the APEX community too.

I thought I'd walk through a simple example of how to render some data on an APEX page using AngularJS. I'd like to create a page to represent an Agile project board for user stories.

agile

What we need is:

  • An API/Server Process to supply us with some data.
  • A page containing the required AngularJS directives to render model data in the UI.
  • A controller to retrieve data from an API and update our model.

For the API, I've created a REST module within my APEX workspace. This will supply story card data. You could use an application process to supply your data, but this may result in a slightly more complicated HTTP request from the AngularJS side.

rest_service

In my page, I have created a region with some HTML defined as the source.

 <div ng-app="demoApp">
    <div ng-controller="demoController">
        <div ng-repeat="column in columns" class="col-md-3">
            <div class="panel panel-default">                          
                <div class="panel-heading">{{column.status}}</div>
                <div class="panel-body">
                    <div ng-repeat="card in cards | filter:column.status" class="panel panel-info">
                        <div class="panel-heading">{{card.title}}</div>
                        <div class="panel-body">{{card.description}}</div>
                    </div>
                </div>
            </div>
        </div>
    </div> 
</div>

There are various AngularJS directives in play here.

  • ng-app : Bootstraps the application.
  • ng-controller : Instantiates my controller.
  • ng-repeat : Iterates over array data in my model.
  • {{}} (aka ng-bind) : Used to bind model data to my view.

Now I pull in my dependencies. I'm just doing this in the page properties for now (I'm also using Bootstrap to style the cards, this is optional).

file_url

All that's left now is to define my controller. I've added another REST endpoint in order to retrieve a list of statuses for my columns. I've placed this in the Function and Global variable declaration section of the page for demo purposes.

angular.module('demoApp', ['ngRoute']);

angular.module('demoApp')
    .controller('demoController', function ($scope, $http) {
        $http.get('modern/agile/statuses').then(function (response) {                              
            $scope.columns = response.data.items;             
        });      

        $http.get('modern/agile/cards').then(function (response) {                              
            $scope.cards = response.data.items;             
        });
    });

It's also an option to use an apex.server.process call with an application process to retrieve your data, but deviating from Angular's $http object to make your call means that $scope.$apply is required in order to let Angular know to update it's bindings.

angular.module('demoApp', ['ngRoute']);

angular.module('demoApp')
    .controller('demoController', function ($scope, $http) {
        $http.get('modern/agile/statuses').then(function (response) {                              
            $scope.columns = response.data.items;             
        });

        apex.server.process(
            'get_cards', 
            {},
            {
                type: 'GET'
            }
        ).done(function(data) {         
            $scope.$apply(function () {
                $scope.cards = data;
            });
        });
    });

$scope in AngularJS represents the model. Model data is bound to it's corresponding view references in AngularJS automatically. In other words, simply updating $scope in your controller after making your API call will change the HTML on the page. For APEX developers used to using jQuery to update the DOM as part of their AJAX workflow, this may seem like magic!

That's all you need to render data using AngularJS in APEX. It may be that if you work with a lot of application processes or REST modules that the Angular approach is a good option for heavily customised and dynamic regions.

Feel free to check out the demo page here.