Reid Carlberg

Connected Devices, salesforce.com & Other Adventures

Tag Archives: visualforce

Refactoring Visualforce Controllers for Lightning Components

1

You might remember Mo Tester, the package that helps you Experiment Faster on Force.com. I’m tweaking it for some Lightning Component stuff (spoiler alert) and ran into this.  (Posting to the Lightning Newbie Notes too.)

The following code won’t compile. You’ll get a handy Return type does not support AuraEnabled error because — wait for it — the @AuraEnabled annotation doesn’t support PageReference return types.

@AuraEnabled
public PageReference createMoTester1() {
    SmartFactory.FillAllFields = true;
    LAB_Mo_Tester_1__c t = (LAB_Mo_Tester_1__c) 
           SmartFactory.createSObject('LAB_Mo_Tester_1__c');
    insert t;
    return new PageReference('/'+t.id);
}

You need to refactor your Visualforce controller to have two methods, one for your existing code, one for your new Lightning Component.  Also, the @AuraEnabled method needs to be static.

public PageReference createMoTester1() {
    Id myMo = LAB_CreateDataHelper.getNewMoTester1Id();
    return new PageReference('/'+myMo);        
}    

@AuraEnabled
public static Id getNewMoTester1Id() {
    SmartFactory.FillAllFields = true;
    LAB_Mo_Tester_1__c t = (LAB_Mo_Tester_1__c) 
           SmartFactory.createSObject('LAB_Mo_Tester_1__c');
    insert t;  
    return t.id;                
}

Note that in this case, based on the way my test classes are structured, this didn’t affect my code coverage. It was 100% before, it’s 100% after.

Incidentally, not supporting PageReference return types is perfectly logical when you think about it.  PageReferences are a Visualforce thing after all.

Also note that, yes, I’m bewildered by my choice of method names here, too.  Also, the original package doesn’t seem to use this method.  And the test coverage in the package didn’t include coverage for the StandardController and StandardSetController dependent constructors. What was I thinking???

Looking at old (ish) code is fun.

Update 2/23/15 — I did use the button, on the list view.  I just didn’t inspect hard enough.  Phew & Sheesh!mo-tester-button-found

 

Also the method has to be static.  Whoops!

AngularJS & Remote Actions: The Simplest Possible Visualforce Page

3

The other day, spurred on by Mr. Ward’s Building Salesforce1 Mobile Apps with Visualforce, AngularJS, and Bootstrap, I became curious about whether or not I could mix Remote Actions in with his code, and it turns out I can.  And more than that — it turns out to be pretty sweet!

I’ve included a video demo at the bottom of the post and you can install these pages into your developer edition from this unmanaged package.  Note that once you install these into your org, you’ll want to add them to your Mobile Navigation in order to see the Salesforce1 #awesomesauce.  Code is also on github.

The foundations of Remote Actions are simple.  You create an Apex class that performs the operation you want, and then use a @RemoteAction annotation to expose a particular method to the JavaScript Remoting framework.

global class SampleRemoteActionPageController {
    @RemoteAction
    global static List myContacts() {
        return [select id, name, email from Contact Order By LastModifiedDate DESC LIMIT 200];
    }
}

You then create a simple page that calls that remote action.

<apex:page controller="SampleRemoteActionPageController" docType="html-5.0">
 <apex:stylesheet value="//cdn.jsdelivr.net/webjars/bootstrap-sf1/0.1.0-beta.6/css/bootstrap-namespaced.css"/>
 <apex:includeScript value="//ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.11/angular.min.js"/>
 
 <script>
 var app = angular.module("ngApp", []); 
 app.controller("ContactCtrl", ["$scope", function($scope) {
   $scope.contacts = [];
 
   $scope.getContacts = function() {
     Visualforce.remoting.Manager.invokeAction(
     '{!$RemoteAction.SampleRemoteActionPageController.myContacts}', 
     function(result, event) {
       $scope.contacts = result;
       $scope.$apply();
     }); 
     }
   }]);
 </script>
 <div class="bootstrap" ng-app="ngApp" ng-controller="ContactCtrl" >
 
 <h1 align="center">Click The Button</h1>
 <button ng-click="getContacts()" class="btn btn-lg btn-default btn-block">Get Contacts</button> 
 
 <p>
 <ul>
 <li id="{{current.Id}}" ng-repeat="current in contacts" ng-class-even="'rowEven'">{{current.Name}}</li>
 </ul>
 </p>
</div>
</apex:page>

I love the simplicity and flexibility I’m seeing here.

Just for fun, I also created a demo using the new Remote Objects functionality that’s still in developer preview.  It also works well in both the desktop browser and Salesforce1 mobile app.  Checkout the video below!

 

%d bloggers like this: