1
votes

Inside a visual force page (as a container), I have created a custom directive in angular JS but it’s not working. In fact, the directive is not even being called! Though this works perfectly fine in the JSFiddle

Below is the custom directive.When I use this directive in the HTML markup, it never show anything on the console log. I have created multiple directives and seeing the same behavior. I believe there is a bug when using custom directives inside the visualforce container.Has anyone of you have faced the same issue? Any help would be greatly appreciated.

Thanks! -SS

UPDATE

Here is the JSFiddle for Custom directive that works fine but when I use it in visual force page, it doesn’t work.( Even though the directive has a console.log, nothing appears in console. This proves that the directive is not being called) http://jsfiddle.net/ssah13/3y1z5943/

Please note: This directive strips off everything before and after underscore in the OppName. For example: If OppName is “111111_Test_123445" then output is “Test"

Here is the visual force page and a controller:

PAGE:

<apex:page docType="html-5.0" controller="SalesActions">
  <head>
    <script src="//code.jquery.com/jquery-1.11.0.min.js"/>
    <apex:includeScript value="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.min.js"/>
  </head>
        <!-- HTML FOR APP -->
        <!-- To use bootstrap with visualforce everything needs to be wrapped with "bs" class-->
        <div ng-app="salesApp" class="bs">
          <div ng-controller="salesController">

              <div ng-repeat="sfResult in salesforceResponse">
                <table>
                  <tr ng-repeat="opp in sfResult.opportunities">
                    <td>
                      <span opp-name="" input="opp.Name">
                          {{opp.Name}}
                      </span>
                    </td>
                  </tr>
                </table>
              </div>
          </div>
        </div>

      <!-- ACTUAL ANGULAR JS APP : Later on move this to salesworkspace.js-->
    <script type = "text/javascript">
      var ngApp = angular.module('salesApp', []);
      //Opp Name directive
      ngApp.directive('oppName', function () {
          return {
              restrict: 'A',
              scope: {
                  input: '='
              },
              link: function (scope, element, attrs) {
                 console.log('Input: ', scope.input);
                  var input = scope.input;
                  if (!input) {
                      return;
                  }
                  // AccountName_Test_123445
                  if (input.indexOf('_')) {
                      scope.input = input.split('_')[1];
                  }
              }
          };
      });

        ngApp.controller('salesController', ['$scope',
            function($scope) {

                  $scope.salesforceResponse = [];
                  Visualforce.remoting.Manager.invokeAction(
                      '{!$RemoteAction.SalesActions.getAllAccounts}',
                      function(result, event) {
                          if (event.status) {
                            $scope.$apply(function() {  //Use Apply as the scope changed outside Angular Context?
                             $scope.salesforceResponse = result;
                              console.log($scope.salesforceResponse);
                              });
                           } else {
                            console.log(event);
                          }
                        }
                  );
        } //End of function
      ]); //End of Controller method
  </script>
  </apex:page>

CONTROLLER: salesActions.cls

public with sharing class SalesActions {

    public SalesActions() { } // empty constructor

    @RemoteAction
    public static List<accountWrapper> getAllAccounts() {
        List<accountWrapper> accountResponse = new List<accountWrapper>();
        List<account> accs = [SELECT Id, Name, Type, Strategic_Account_Management__c,
                                    (SELECT Id FROM Opportunities) ,
                                    (SELECT Name FROM Contacts)
                              FROM Account
                              Order by Name]; //Add a Filter here. WHERE ownerId = :Userinfo.getUserId();

        Set<Id> accountIds = new Set<Id>();
        for(account acc : accs) {
            accountIds.add(acc.Id);
        }

        Map<Id,Opportunity> oppIdToOpp = new Map<Id,Opportunity>([
                                                SELECT Id,Name, Account.Name, Agency__r.Name, Campaign_EVENT__c,Rate_Type__c,StageName,Amount,CurrencyISOCode,
                                                       Probability,CampaignStartDate2__c,CampaignEndDate2__c,Contact__c,Sales_Notes__c,
                                                (SELECT SplitAmount, SplitOwner.Name,SplitPercentage, Split__c FROM OpportunitySplits)
                                                 FROM Opportunity WHERE AccountId IN :accountIds]// Remove WHERE AccountId =:accountId and Add WHERE account.ownerId=:UserInfo.getId();
                                                 );


        Map<Id,List<Partner>> accountIdToPartners = new Map<Id,List<Partner>>();
        for(Partner p :[SELECT AccountFromId,AccountTo.Name FROM Partner WHERE AccountFromId IN :accountIds]) {
            if(accountIdToPartners.containsKey(p.AccountFromId)) {
                accountIdToPartners.get(p.AccountFromId).add(p);
            } else {
                accountIdToPartners.put(p.AccountFromId, new List<Partner>{p});
            }
        }
        for(Account acc : accs) {
            accountWrapper accWrapper = new accountWrapper();
            accWrapper.account = acc; // This will add all the accounts and related contacts
            accWrapper.opportunities = new List<Opportunity>();
            accWrapper.partners = new list<Partner>();
            if(accountIdToPartners.containsKey(acc.Id)){
                accWrapper.partners = accountIdToPartners.get(acc.Id);
            }
            for(Opportunity opp : acc.Opportunities) {
                accWrapper.opportunities.add(oppIdToOpp.get(opp.Id));  // This will add all the opportunties and opportunitySplits
            }
            accountResponse.add(accWrapper);
        }
        return accountResponse;
    }

    public class accountWrapper {
        public Account account { get; set; }
        public List<Partner> partners { get; set; }
        public List<Opportunity> opportunities { get; set; }
    }
}
1
Can you provide an example that shows it works? I'm having issues getting your code to work. Also, I haven't had issues with Angular and Salesforce yet. - Matthew Green
Without the full code and an error it is hard to figure out the problem. But maybe this article will help: developer.salesforce.com/blogs/developer-relations/2014/07/… - James Ward
I have added a working JSFiddle, visualforce page and controller. Even though the directive has a console.log, nothing appears in console. Seems like there is a bug when using custom directives inside the visualforce container. - ssah13

1 Answers

1
votes

For me this is how I get it to work:

ngApp.directive('testDirective', function () {
  return {
    restrict: 'E',
    scope: {
        input: '='
    },
    template: '<p>{{input}}</p>',
    link: function (scope, element, attrs) {
       console.log('Input: ', scope.input);
        var input = scope.input;
        if (!input) {
            return;
        }
        // AccountName_Test_123445
        if (input.indexOf('_') !== -1) {
            scope.input = input.split('_')[1];
        }
      }
    };
  });

and then in the html:

<test-directive input="opp.Name"></test-directive>

Those are just some small changes. Not entirely sure why it does not work in VF before. In VF I would always try to use directives as elements as VF cannot have those empty attributes as normal HTML can. Then you should define a template or templateUrl in the directive. (You can use VF pages as templates here as well - even with standardControllers or custom controllers firing!)

Oh and of course have a look at ngRemote again as it can help with your AngularJS application on VF.

Hope this helps!

Florian