Salesforce chatter in AngularJS part 2

The previous post talked about our custom salesforce chatter component from the angular directive side of things. This bit talks about the service that actually interacts with the chatter rest service.

The service

The directive interacts with an intermediary service that is used to transform form data before sending it to the salesforce chatter rest service. The general method is as follows…

Get the feed

function getFeed (recordId) {
  return getData ({   // 1
    getCacheCallback: getCache(recordId, appConfig.communityId),
    httpConfig: _.extend(httpConfig, {  // 2
      method: 'GET',
      url: service.endPoints.feed.replace('%id', recordId) // 3
  1. In my custom ‘vfRestService’ service, there is a template method called ‘getData’ which handles requests to the chatter service and handles generic stuff. That method (function, whatever), expects to receive a cache key and a config object. The cache key is (surprisingly) used for caching purposes and also to show/hide a loading bar. While there are angular modules out there to handle display of load bars, we implemented our own. I’m gonna write a post about that but basically, the rest of the app uses VisualForce’s remoting manager, so any ajax calls are deferred to the remoting manager, which angularjs can’t hook into, so there’s no way (that I could figure out) to intercept those requests in order to show the loading bar. Anywho…
  2. The httpConfig object extends some defaults with a method and url. The defaults include a flag to disable automatic caching and this…

    headers: { Authorization: ‘Bearer ‘ + appConfig.sessionId }

    In order to interact with the chatter api, an authorisation key needs to be passed along. From the angular app, this is being injected via the ‘appConfig’ object. There’ll be another post about this but in essence, the appConfig object is created as a constant value from the actual visualforce page. Various variables can then be set from that page and made available using DI throughout the app. One of these is the sessionId.

  3. The actual url is created using the recordId passed from the directive.


As I mentioned, this function is responsible for calling the chatter api using the parameters that were passed in. This template function is used since there are some generic things that always happen. There’s always a loadbar element either shown or hidden, and there’s always a promise either returned or rejected. Here it is…

function getData(args) {
  var cache = args.getCacheCallback;
  addLoadBarElement (cache.cacheKey, true); // 1
  return $http(args.httpConfig)
    .then(function (response) {  // 2
    .catch(function(e) {  
      return $q.reject(e);
      if (cache.cacheKey !== null) {  // 3
        addLoadBarElement(cache.cacheKey, false);
  1. When the function is called, add an element to the load bar (explained in a different post).
  2. If successful, return the data. If there was an error, log the error and return the rejected promise
  3. Whatever happens, remove the loading bar element

Post a message

So, firstly, the simplest form of posting data. The required elements are.

  • body: The body of the message, either rich text or just text.
  • feedElementType: for v35 of the chatter api, this needs to be ‘FeedItem’
  • subjectId: the related recordId.

Here’s the code…

var parseMessage = {   
  text: function (message) {
    return {
      messageSegments: [{
        type: 'Text',
        text: message || ''
function postMessage (recordId, message) {
  return getData ({
    getCacheCallback: getCache(recordId, appConfig.communityId,,
    httpConfig: _.extend(httpConfig, {
      method: 'POST',
      url:, // 1
      data: {
        body: parseMessage.text(message),  // 2
        feedElementType: 'FeedItem',
        subjectId: recordId

Here’s a summary

  1. To get the url to post the message to, the community id (if you’re creating a community, which we are) needs to be included. Again, we’re making use of the appConfig constant that is set from the visual force page. This looks like…

    connectURL: ‘/services/data/v35.0/connect/communities/{!networkId}’,

    When the page is loaded, the networkId variable will be set to the community id, which is needed to post data to a particular community. So the final url would be something like…


  2. To get the post data body, a strategy method is called. At present, its only got one strategy for plain text. But this method could easily be extended to accommodate rich text.

Basically, the object to post needs to look like this…

  headers: { Authorization: 'Bearer thesessionid1234' },
  method: 'POST',
  url: '/services/data/v35.0/connect/communities/123communityid123/chatter/feed-elements',
  data: {
    messageSegments: [{
      type: 'Text',
      text: 'the message'
  feedElementType: 'FeedItem',
  subjectId: 'therecordid'

If its successful, it’ll return a valid feeditem that we use to add to the feed accordion (see part 1)

Post a link

The method here is pretty much the same as a message, except that a ‘capabilities’ object needs adding to the data object sent in the http post request.

body: {},
capabilities: {
  link: {
     url: linkUrl,
     urlName: linkName

Not much else ready, use the same url and you’re away!

Post a file

Now the fun bit. To make this work, we made use of the excellent library made available here, (well, some of it). The main bits used are the ‘RequestPart’ and ‘MultipartRequest’ services, available here. These allow you to (fairly) easily construct a multi-part request that salesforce will accept, so that form uploads can be handled. In addition, to this, we also used Restangular, which is a service to easily interact with restful resources.

Construct the Restangular object

Here’s the code

var fileUploader = Restangular.withConfig(function(RestangularConfigurer) {
    cache: false,
    transformRequest: function(data) {
      return data;
  RestangularConfigurer.setDefaultHeaders(_.extend(getFileAuthHeaders(), {
    'Content-Type': 'application/json; charset=UTF-8'

The main bits here ensure that the request is not transformed in any way, overriding angular’s native functionality that alters the data. The base url for the request is set and default headers added, including the authorisation key and the content-type for the entire request. Note that each part of the request also needs to set its own header depending on what it is (json data, octet stream etc)

Create the multi-part request

var boundaryStr = 'boundary_string';  // 1
var req = new MultipartRequest(boundaryStr);

var dataPart = new RequestPart();  // 2
dataPart.addHeader('Content-Disposition', 'form-data; name="feedElement"');
dataPart.addHeader('Content-Type', 'application/json; charset=UTF-8');
dataPart.setBody(getFileMessageBody(recordId, message, 'file upload', fileName));

var filePart = new RequestPart();  // 3
filePart.addHeader('Content-Type', 'application/octet-stream; charset=ISO-8859-1');
filePart.addHeader('Content-Disposition', 'form-data; name="feedElementFileUpload"; filename="' + fileName  + '"');


var bufferView = (new Uint8Array(req.getBuffer())); // 4
addLoadBarElement (loadBarKey, true);
  1. create a boundary string (an arbitrary string) to separate the parts of the request and create a ‘MultipartRequest’ object.
  2. construct a new ‘RequestPart’ object. Set its headers and add the message body (see the bit about posting a message). The content-type header needs to be set to ‘application/json’ When creating a ‘ContentPost’ feed item, the ‘Capabilities’ object needs to look like this.

    capabilities: { content: { description: ‘File upload’, title: ‘Thefilename.whatever’ } }

    When this is done, add the request part to the main multipart request.

  3. Create another request part, used for the file. The header content-type for this needs to be ‘application/octet-stream’ to accept file requests. The headers also need to include the filename and the value ‘feedElementFileUpload’ (this is for v35 remember). Set the body of the part to the fileBuffer passed from the directive. This was the file read from the form as an ArrayBuffer object (see part 1). Add this part to the multi-part request.

  4. Create a new UInt8Array from the multipart request. This is going to be used by Restangular as the data to post to salesforce. Finally, add the loadbar element so progress is monitored.

Post the data

Here’s the code

return fileUploader
    null, {
     'Content-Type': 'multipart/form-data; boundary="' + boundaryStr + '"'
  .then(function (response) {
    return response;
  .catch(function (error) {
    return $q.reject(error);
    addLoadBarElement (loadBarKey, false);

The pertinent bits here are the post function, which accepts the bufferView that was created in the previous step, and the ‘Content-Type’ which specifies what the boundary string for the various parts is. This then returns a promise which is used to return the data or throw an error.


That’s about it. I’m not going to get into the mechanics of the multi-part request or any of that gubbins because quite frankly I don’t understand it. But, hopefully this explained how to create a multi-part request in an angularjs app and then post it into salesforce.

Leave a Reply