Luminate Online utilities for AngularJS 1.x apps.
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
dist/js
grunt
src/coffee
.gitignore
.npmignore
Gruntfile.coffee
LICENSE.md
README.md
bower.json
package.json

README.md

angular-luminate-utils

This library is currently in beta, and significant changes are likely in future versions.

Luminate Online utilities for AngularJS 1.x apps. At its core, this library is a JavaScript wrapper around the Luminate Online REST API, with some helper functions and other magic sprinkled in. The library includes support for all major modern browsers, and it can be used both within and outside of Luminate Online.

Table of Contents

Basic Setup

Before getting started, there are a couple of basic steps you must follow:

  • Create an API Key

    In order to use the Luminate Online API, you must define an API Key for your organization's Luminate Online website. If you haven't already done so, go to Setup -> Site Options -> Open API Configuration, and click "Edit API Keys". The only option you need to worry about on this page is 1. Convio API Key.

  • Whitelist your domain

    For security reasons, API requests are limited to a whitelist of domains defined by your organization. If you haven't already done so, go to Setup -> Site Options -> Open API Configuration, and click "Edit Javascript/Flash configuration". The only options you need to worry about on this page are 1. Allow JavaScript/Flash API from these domains and 2. Trust JavaScript/Flash API from these domains. Add any domains where you will use this library to these lists. As noted on the page, you can use an asterisk as a wildcard if your website has multiple subdomains, e.g. "*.myorganization.com".

Install

npm

npm install angular-luminate-utils

bower

bower install angular-luminate-utils

Or if you're not into package management, just download the latest build under dist.

Including ngLuminateUtils In Your App

Once you've uploaded angular-luminate-utils.min.js to your website, including the library is easy — just add it somewhere below Angular.

<script src="../js/angular-luminate-utils.min.js"></script>

Then, using the library is as simple as injecting the ngLuminateUtils module as a dependency in your app.

angular.module('myApp', ['ngLuminateUtils']);

Configuration With $luminateUtilsConfig

The library is instantiated using the $luminateUtilsConfigProvider. At a minimum, you must set your secure Luminate Online path and your API Key.

angular.module('myApp').config(['$luminateUtilsConfigProvider', function($luminateUtilsConfigProvider) {
  $luminateUtilsConfigProvider.setPath({
    secure: 'https://secure2.convio.net/myorg/site/'
  }).setKey('123456789');
}]);

For organizations using Multilocale in Luminate Online, the setLocale method can be used to define the locale for the current user. Locale is a string comprised of an ISO-639 language code and an ISO-3166 country code. Currently supported values are "en_US", "es_US", "en_CA", "fr_CA", "en_GB", and "en_AU". (Note that the list of possible values varies by organization.)

$luminateUtilsConfigProvider.setLocale('es_US');

Additionally, you can define a list of common parameters to be included in all API requests, e.g. source and sub-source codes, using the setDefaultRequestData method.

$luminateUtilsConfigProvider.setDefaultRequestData('source=MySourceCode');

You can also specify a default request handler to be used by $luminateRest. The provided function will be used prior to any request-level Promise handlers.

$luminateUtilsConfigProvider.setDefaultRequestHandler(function(response) {
  if (response.data.errorResponse && response.data.errorResponse.code === '5') {
    $scope.showLoginDialog();
  }
  return response;
});

To access configuration options after instantiation, simply inject $luminateUtilsConfig.

angular.module('myApp').controller('myCtrl', ['$scope', '$luminateUtilsConfig', function($scope, $luminateUtilsConfig) {
  $scope.luminateUtilsConfig = $luminateUtilsConfig;
  $scope.$watch('luminateUtilsConfig.locale', function(newValue) {
    $scope.myRequestThatDependsOnLocale();
  });
  $scope.setLocale = function(locale) {
    $luminateUtilsConfig.setLocale(locale);
  };
});

API Requests With $luminateRest

The $luminateRest service is the heart of the library. It provides methods for making requests to the Luminate Online REST API, with automatic handling of authentication tokens for methods that require it.

The request method accepts one argument, an options object. It returns a Promise, resolved with the full $http response object.

property description
api Either a full, case-sensitive API servlet name, e.g. "CRConsAPI", or a case-insensitive shorthand with "CR" and "API" removed, e.g. "cons".
data The data string to be sent with the request. api_key, response_format, suppress_response_codes, and v parameters are automatically appended.
formData The FormData object to be sent with the request. api_key, response_format, suppress_response_codes, and v parameters are automatically appended.
requiresAuth A Boolean indicating whether or not the API method being called requires authentication. If true, an auth token is automatically appended to the request data.
contentType The Content-Type for the request, either "application/x-www-form-urlencoded" or "multipart/form-data". If formData is provided, this will default to "multipart/form-data", otherwise "application/x-www-form-urlencoded" is the default.

Examples

Check if the user is logged in:

angular.module('myApp').controller('myCtrl', ['$scope', '$luminateRest', function($scope, $luminateRest) {
  $luminateRest.request({
    api: 'cons', 
    data: 'method=loginTest'
  }).then(function(response) {
    if (response.data.loginResponse && response.data.loginResponse.cons_id && response.data.loginResponse.cons_id > 0) {
      $scope.loggedIn = true;
    } else {
      $scope.loggedIn = false;
    }
  });
}]);

Get the logged in user's constituent record:

$luminateRest.request({
  api: 'cons', 
  data: 'method=getUser', 
  requiresAuth: true
}).then(function(response) {
  if (response.data.getConsResponse) {
    $scope.constituent = response.data.getConsResponse;
  }
});

Submit a donation form:

$scope.submitDonation = function() {
  $luminateRest.request({
    api: 'donation', 
    data: $httpParamSerializer($scope.donationInfo)
  }).then(function(response) {
    if (response.data.errorResponse || (response.data.donationResponse && response.data.donationResponse.errors)) {
      $scope.showDonationError = true;
    } else {
      $scope.showDonationSuccess = true;
    }
  });
};

Upload a TeamRaiser participant's personal page photo using formData:

$scope.photoInfo = {
  method: 'uploadPersonalPhoto', 
  fr_id: '1234', 
  graphic_upload_upload: 'true'
};
// some code is needed here to set $scope.photoInfo.graphic_upload_file to a blob
$scope.submitUpload = function() {
  $scope.showUploadError = false;
  $scope.showUploadSuccess = false;
  var uploadFormData = new FormData();
  angular.forEach($scope.photoInfo, function(val, key) {
    uploadFormData.append(key, val);
  });
  $luminateRest.request({
    api: 'teamraiser', 
    formData: uploadFormData, 
    requiresAuth: true
  }).then(function(response) {
    if(!response.data.uploadPersonalPhotoResponse || !response.data.uploadPersonalPhotoResponse.photoItem) {
      $scope.showUploadError = true
    } else {
      $scope.showUploadSuccess = true;
    }
  });
});

A Note on Third-Party Cookies

Some browsers, such as Internet Explorer and Safari, default to blocking third-party cookies from websites which the user has not visited. This can impact the ability to make some cross-domain requests that involve authentication. For example, if a user visits a website your organization hosts outside of Luminate Online before they ever visit a Luminate Online page, and logs in using the login API method, no session cookie will be set, and on subsequent visits they will not be recognized as logged in. To prevent this issue, it is recommended to use a client-side redirect after successful login to force a session cookie to be set. The login method returns a nonce for just this purpose.

$scope.submitLogin = function() {
  $luminateRest.request({
    api: 'cons', 
    data: $httpParamSerializer($scope.loginInfo)
  }).then(function(response) {
    if (!response.data.loginResponse || !response.data.loginResponse.nonce) {
      $scope.showLoginError = true;
    } else {
      $window.location.href = $luminateUtilsConfig.path.secure + 'EstablishSession?NONCE_TOKEN=' + response.data.loginResponse.nonce + '&NEXTURL=' + encodeURIComponent($location.absUrl());
    }
  });
};

Evaluating Template Tages With $luminateTemplateTag

For those occasions when the REST API does not provide a method for retrieving some information, but a Luminate Online template tag (e.g. S- or E-Tag) exists that meets the need, the $luminateTemplateTag service can be used to evaluate a tag client-side.

The parse method accepts one argument, a template tag. It returns a Promise, resolved with the value of the specified tag.

angular.module('myApp').controller('myCtrl', ['$scope', '$luminateTemplateTag', function($scope, $luminateTemplateTag) {
  $luminateTemplateTag.parse('[[S42:1234:dollars]]').then(function(response) {
    $scope.amountRaised = response;
  });
}]);

Note that template tags must be expressed in bracket syntax, XML syntax is not allowed. Additionally, to protect against XSS attacks, any HTML tags in the template tag string are removed.

Managing Session Variables With $luminateSessionVar

The $luminateSessionVar service provides methods for setting and getting Luminate Online session variables.

angular.module('myApp').controller('myCtrl', ['$scope', '$luminateSessionVar', function($scope, $luminateSessionVar) {
  $luminateSessionVar.set('myVar', 'foo');
}]);

Both the set and get methods return a Promise, resolved with the value of the specified session variable.

$luminateSessionVar.get('myVar').then(function(response) {
  $scope.myVar = response;
});

Note that session variable values passed to the set method must be either a string or a Number. To protect against XSS attacks, any HTML tags are removed. Additionally, any HTML tags in the get method response are removed.

angular.module('myApp').controller('myCtrl', ['$scope', '$luminateSessionVar', function($scope, $luminateSessionVar) {
  $luminateSessionVar.set('myVar', '<div>foo</div>'); // will set myVar to "foo"
}]);

Getting Message Catalog Entries With the $luminateMessageCatalog Service

The $luminateMessageCatalog service allows for retrieving content from the Luminate Online Message Catalog.

The get method accepts one argument, which may be either a single Message Catalog entry bundle and key, or, an array of many bundles and keys. The get method returns a Promise, resolved with an object containing each of the bundles and keys requested.

angular.module('myApp').controller('myCtrl', ['$scope', '$luminateMessageCatalog', function($scope, $luminateMessageCatalog) {
  $luminateMessageCatalog.get('global:name_column').then(function(response) {
    $scope.nameColumnLabel = response.global.name_column;
  });
}]);

If an invalid bundle or key is provided, the get method will fail silently and return an empty string.

angular.module('myApp').controller('myCtrl', ['$scope', '$luminateMessageCatalog', function($scope, $luminateMessageCatalog) {
  $luminateMessageCatalog.get(['global:name_column', 'friendraiser:this_does_not_exist', 'this_does_not_exist_either:foo_bar']).then(function(response) {
    $scope.nameColumnLabel = response.global.name_column;
    $scope.myEntry = response.friendraiser.this_does_not_exist; // will be ""
    $scope.myOtherEntry = response.this_does_not_exist_either.foo_bar; // will be ""
  });
}]);

Note that for performance reasons, Message Catalog entries are cached the first time they are retrieved for each locale. To reset the cache, use the flushCache method.

angular.module('myApp').controller('myCtrl', ['$scope', '$luminateMessageCatalog', function($scope, $luminateMessageCatalog) {
  $luminateMessageCatalog.flushCache().get('global:name_column').then(function(response) {
    $scope.nameColumnLabel = response.global.name_column;
  });
}]);

Including Reusable Content With the luminate-reusable Directive

The luminate-reusable directive can be used to render the content of a reusable PageBuilder page. The pagename attribute identifies the page to be rendered.

<luminate-reusable pagename="'reus_badges'"></luminate-reusable>

The directive can be referenced as an element, or as an attribute.

<div luminate-reusable pagename="'reus_badges'"></div>

Template tags can be used for dynamic pagenames.

<div luminate-reusable pagename="'reus_[[S1:home_stateprov]]_message'"></div>

Including File With the luminate-include Directive

The luminate-include directive can be used to render the content of a file from the Luminate Online filesystem. The filename attribute identifies the file to be rendered.

<luminate-include filename="'foo/bar/badges.html'"></luminate-include>

The directive can be referenced as an element, or as an attribute.

<div luminate-include filename="'foo/bar/badges.html'"></div>

Template tags can be used for dynamic filenames.

<div luminate-include filename="'foo/bar/[[S1:home_stateprov]]-message.html'"></div>

Browser Support

Browser support is largely dependent upon the version of AngularJS being used in your app, but for the most part, all major modern browsers are supported. See the AngularJS FAQ for more information. Note that cross-domain requests can only be made in those browsers with support for Cross-Origin Resource Sharing (CORS). For Internet Explorer specifically, this means IE10+.

Reporting Issues

Should you encounter any issues when using this library, please report them here, using the "Issues" tab above. If you have general questions about the library, or about the API in general, the fastest way to get answers is to use the Luminate Online section on https://community.blackbaud.com.