7

Background

I am starting to build more and more apps with angular, inside of a Visualforce container. Since many of the database services rely on some apex logic, the services layer uses JavaScript remoting. The challenge that I'm facing is app modularity. Namely, there are angular modules that act as building block UI components/widgets that I can reuse in different places throughout my instance.

I've addressed the modularity on the angular side by creating a directory structure for my apps, which breaks them out into reusable pieces by component feature. If I have an Ask a Question publisher action for example, that gets its own directory in my filesystem and version control, that contains its own controllers, directives, HTML partials, etc. We then use requirejs and grunt to compile and bundle pieces together into different static resources for use on different VF pages.

Challenge

The problem is on the Visualforce side. There is no equivalent requirejs, that allows me to custom bundle JS remoting methods into a controller based on an feature config. I have a few options as I see it, and there may be more I'm not seeing:

  • Make all remoting calls global, such that they can be called like any other static method from apex. This allows me to just use a method from another controller. It does not allow me to eliminate creating an @RemoteAction for some function in a new controller, but at least most of the logic can be abstracted to avoid redundant code.
  • Abstract as much logic as possible out of the controllers and move them to helper classes with static methods
  • Create a single controller for all of my Angular apps, with a ton of remote actions. I would assume this would incur a performance hit?

What's the optimal architecture here?

4

I suggest option 4: create REST resources for your apps. I would do one per object, each in their own class. This allows for a nice separation of concerns (keeping your controllers focused on the page), promotes modular design, and makes it easier to test and maintain.

| improve this answer | |
  • While I agree on separation of concerns, I wonder how performant an apex REST service would be compared to remoting? Ever tested this? – greenstork Sep 16 '14 at 15:53
  • I have not tested it yet, but it's on my to-do list. – Mike Chale Sep 17 '14 at 10:35
  • Mike, I just wanted to follow up to say this is the route that we went and it's working great. – greenstork Apr 24 '15 at 15:48
  • Hey guys, I'm an interface developer brand new to the Force.com platform and relatively new to Java(ish) code/Apex on the server side. I'm helping to architect the front end for an experience driven by SF. I have two questions relating to this solution: 1. Would/could these REST resources be available from a third-party app (not called from within VF page)? 2. Would these REST services be written directly inside of Apex controllers? – chrisjordanme May 20 '15 at 18:45
2

An awkward part, to me, is having the VF component or page specify a VF Controller in its controller attribute just for one or more of the angular services its angular controller uses. It seems like the view (VF component or page) shouldn't have to know about the service layer implementation details.

I would hesitate to go global. If you are in a managed package it is then available in the subscriber org.

I would go with the approach of having a controller that delegates to helper classes. Each @RemoteAction would have a single line that is that delegation.

There is an interesting approach in this answer, where a component contains the single controller and assigns all of the available methods to JavaScript variables.

If you are using ngForce you could create a Controller extension for the ngForceController and modify the ngForce.component to specify it:

<apex:component controller="ngForceController" extensions="MyRemoteActions">

Apex:

public MyRemoteActions(ngForceController cont) {}
public MyRemoteActions() {
    this(null);
}

@RemoteAction
public static MyObject getObject(String ident) {
    return MyObjectService.getObject(ident);
}

The interesting thing about this approach is that you don't have to use just the one controller. You could break up each service into its own controller extension (very simplistic example follows).

<apex:component controller="ngForceController" extensions="MyContacts,MyOpportunities">

Then from your angular ContactService:

vfr.send('MyContacts.get')(contactId)
   .then(...

And from your angular OpportunityService:

vfr.send('MyOpportunities.get')(oppId)
    .then(...

The controller extension approach has the added benefit of making the JavaScript a bit more semantically consistent.

| improve this answer | |
  • 1
    This is a great answer, thanks for sharing. We ended up shifting over to REST API and REST services because this means that the page doesn't require a controller scope. This is working well for us so far. I will likely add this as an answer. – greenstork Apr 24 '15 at 15:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.