1

Below is the functionality my code achieves currently

  1. Get the customer site . If customer site exists then check if latitude and longitude exist and if all is true then open the Locator with given latitude and Longitude.
  2. If customer site exists but Latitude and Longitude does not exist but customer city , state and zip code exist so geocode the address using remoting javascript and open the Locator after geocoding the site and retreiving the latitude and Longitude with it.

  3. If the customer site does not exist and Latitude and Longitude and also no city or state exist and it is not possible to geocode the site then open default location.

Below code achieves that in angular controller but as you can see it has many callbacks and if else statements. My main objective is to reduce the callbacks and if else statements and make it more faster and modular. How can I achieve this in angular. any help would be appreciated. My code I wrote is given below

     var pageRef = "/apex/LeadLocator?";
                $scope.CustomerSite.loaded = false;
                console.log( "5-"+$scope.CustomerSite );
                if($scope.CustomerSite && $scope.CustomerSite.lat && $scope.CustomerSite.lon && $scope.CustomerSite.lat !== 0 && $scope.CustomerSite.lon !== 0)
                {
                    pageRef += 'lat='+$scope.CustomerSite.lat; 
                    pageRef += '&lon='+$scope.CustomerSite.lon; 
                    jQ("#handlebars-action-geocode").html( jQ("#task-completed-template").html() );
//                    jQ("#handlebars-action-locator").html( jQ("#task-executing-template").html() );
                    //$window.location.href  = pageRef;
                } 
                else if( $scope.CustomerSite && ( !$scope.CustomerSite.lat || !$scope.CustomerSite.lon || ($scope.CustomerSite.lat == 0 && $scope.CustomerSite.lon == 0)))
                {
                    // Execute additionl geoCoding on this site
                    if($scope.CustomerSite.SiteStreet && $scope.CustomerSite.SiteCity && $scope.CustomerSite.SiteCountryCode && $scope.CustomerSite.SitePostalCode )
                    {
                        LeadLocatorPreProcessorControllerV2.geoCodeSite($scope.CustomerSite.SiteStreet + ' ,' + $scope.CustomerSite.SiteCity + ' ,' + $scope.CustomerSite.SiteCountryCode + ' ,' + $scope.CustomerSite.SitePostalCode, function(result, event){
                            if (event.status) {
                                if(result && result.AddressLat && result.AddressLon)  
                                {  
                                    LeadLocatorPreProcessorControllerV2.UpdateAddrGeoCodingInfo( $scope.CustomerSite.AddressID, result.AddressLat, result.AddressLon, function(){
                                        if (event.status) {
                                            pageRef += 'lat='+result.AddressLat; 
                                            pageRef += '&lon='+result.AddressLon; 
                                            jQ("#handlebars-action-geocode").html( jQ("#task-completed-template").html() );
//                                            jQ("#handlebars-action-locator").html( jQ("#task-executing-template").html() );
                                            //$window.location.href  = pageRef;
                                        } else if (event.type === 'exception') {
                                            document.getElementById("responseErrors").innerHTML = event.message + "<br/>\n<pre>" + event.where + "</pre>";
                                        } else {
                                            document.getElementById("responseErrors").innerHTML = event.message;
                                        }
                                    });
                                } 
                            } else if (event.type === 'exception') {
                                document.getElementById("responseErrors").innerHTML = event.message + "<br/>\n<pre>" + event.where + "</pre>";
                            } else {
                                document.getElementById("responseErrors").innerHTML = event.message;
                            }
                        });               
                    }
                }
            };
2

I usually create a factory/service and keep the controller as thin as possible.The main reason is, angular controller's main work is to maintain the ViewModel and rather than worrying about the business logic it has to perform after fetching the records.

It is recommend to move most of the post logics(big ones) to the factory/service which improves clarity,maintainability and promotes separation of concern.

In most of my vf pages, I usually have DataService factory which inturn contains all the remote action methods which does CRUD opertion and use $q service which is an light weight implementation of Q promise library in angular.

Here's an sample to use factory which also uses $q(Promises);

(function() {

    "use strict";

    angular.module('myApp', [])
    .controller('TestController', function($scope,AccountRemoteService) {
        $scope.loadingImg = false;

        $scope.fetchAccount = function(accId) {
            $scope.loadingImg = true;

            // METHOD 1: chaining in the controller
            AccountRemoteService.getAccount(accId)
            .then(function(data){

                //do something here

                //get attachments of the acount record
                AccountRemoteService.getAccountAttachments(accId)
                .then(function(data){
                    $scope.loadingImg = false;
                    //do something here
                })
                .catch(function(error){
                    $scope.loadingImg = false;
                    //do something here
                });

            })
            .catch(function(error){
                $scope.loadingImg = false;
                //do something here
            });


            // METHOD 2: Chaining within service callback
             AccountRemoteService.getAccount(accId)
            .then(function(data){
                $scope.loadingImg = false;

                //do something here
                // build the view with the data passed

            })
            .catch(function(error){
                $scope.loadingImg = false;
                //do something here
            });

        };

    });
    .factory('AccountRemoteService',function($q){
        var accountFactory = {
            "getAccount":getAccount,
            "getAccountAttachments":getAccountAttachments
        };

        METHOD 1:

        function getAccount(recId){
            var defer = $q.defer();

            AccountController.getAccount(recId,function(event,result){
                if(event.status){
                    defer.resolve(result);
                }
                else if(event.type === 'exception'){
                    defer.reject(event.message);
                }
            },{escape:false});

            return defer.promise;
        }

        function getAccountAttachments(parentId){
            var defer = $q.defer();

            AccountController.getAttachments(parentId,function(event,result){
                if(event.status){
                    defer.resolve(result);
                }
                else if(event.type === 'exception'){
                    defer.reject(event.message);
                }
            },{escape:false});

            return defer.promise;
        }


        METHOD 2:

        function getAccount(recId){
            var defer = $q.defer();

            AccountController.getAccount(recId,function(event,result){
                if(event.status){
                    // do not resolve here will do it later 
                    getAccountAttachments(recId,defer)
                }
                else if(event.type === 'exception'){
                    defer.reject(event.message);
                }
            },{escape:false});

            return defer.promise;
        }


        function getAccountAttachments(parentId,defer){           

            AccountController.getAttachments(parentId,function(event,result){
                if(event.status){
                    // resolve and send the required data to the controller to build the view
                    defer.resolve(result); 
                }
                else if(event.type === 'exception'){
                    defer.reject(event.message);
                }
            },{escape:false});

        }

        return accountFactory;

    });

})();

Look at the below links it will help you out in understanding service concepts:

1.http://onehungrymind.com/angularjs-sticky-notes-pt-1-architecture

2.https://www.airpair.com/javascript/posts/services-in-angularjs-simplified-with-examples

3.http://viralpatel.net/blogs/angularjs-service-factory-tutorial

1

Haven't tried it but a quick Google revealed this Premote GitHub project that offers:

Javascript Remoting in Visualforce has an ugly api. Premote fixes this by letting you wrap your Remote Action calls in a promise based on Q.

As you may already know, using promises allows the deeply nested callbacks to be flattened and other things like parallel requests to be coded simply.

  • Yes I know about promises but the problem I am facing is my structure and how to cut the if- else statements and callbacks which are there in these statements because they are making the code complex and bulky I already have the code build up but using promise in this is what I want to know to remove the callbacks – user5129806 Sep 21 '16 at 19:52
  • @user5129806 You can create several separate well named functions for all the && and || logic pieces that reference $scope so the main logic flow is clearer. – Keith C Sep 21 '16 at 20:18

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.