function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Craig Glencross 1Craig Glencross 1 

findnearbywarehouses example from Visualforce Workbook does not work

I have been following along with the (workbook_vf.pdf) Visualforce Workbook
Version 6, Spring ’15.  There is one section called Visual Force and Apex in Action that will create a web page that shows a Google map of nearby warehouses.

I have followed all of the code examples in the workbook but the page:/apex/FindNearbyWareshouses will not render the Google map.  The page is just blank.

I also viewed the
      Develop > Pages > Completed_FindNearbyWarehousesPage
that comes with the Enhanced Warehouse Data Model (see page 25 of the workbook) and it will not work either.

Can someone please try this example in the workbook and see if they can get it to work?  I think it would be very valuable to be able to see how all the pieces work together.
Sagar PareekSagar Pareek
Have you added google.com under remote site settings?
Craig Glencross 1Craig Glencross 1
I added a Remote Site as you suggested )I don't think the workbook mentioned that) but still have no luck.
New Google.com added

The area of the example that is not firing is:

 alert('1');
        // Fire the initialize function when the window loads
        google.maps.event.addDomListener(window, 'load', initialize);
        alert('2');
Craig Glencross 1Craig Glencross 1
For the code snippet below I get a alert box for the 1 but not for the 2:
          alert('1');
        // Fire the initialize function when the window loads
        google.maps.event.addDomListener(window, 'load', initialize);
        alert('2');
Craig Glencross 1Craig Glencross 1
I think the issue is with how Salesforce is allowing (or not allowing) the code to access the Google js methods.  I have minimized the calls to the apis as listed and this also will not work:

    <script>
        function initialize() {
                var obj = document.getElementById("map-canvas")
                alert(obj.id);
                 var mapProp = {center:new google.maps.LatLng(51.508742,-0.120850),    zoom:5,  mapTypeId:google.maps.MapTypeId.ROADMAP };
                 var map=new google.maps.Map(obj ,mapProp);
                 alert('leaving init');
        }    
    </script>

    <body onload="initialize()" >
        <div id="map-canvas" style="width:500px;height:280px;padding:10px;border:1px solid black ;"> </div>
    </body>



I have tried to access the google api methods these ways but none have worked:
     <apex:includeScript value="{!$Resource.googleMapsAPI}" />
  or
     <script src="http://maps.googleapis.com/maps/api/js"></script> 


 
Craig Glencross 1Craig Glencross 1
Aftrer days of suffering I have found out it is an issue with how the Static Resource is being referenced. The protocol has to be of type secure (https).  I don't know if this is
  •    a new requirement of Salesforce since they created the example
  •    an issue with my Development license

My fix that seems to work is to replace the reference to the Static Resource with a script hosted on googleapis.com
  Replace this line 
         <apex:includeScript value="{!$Resource.googleMapsAPI}" />
  With
         <script src="https://maps.googleapis.com/maps/api/js"></script> 


 
L3nL3n
Thank you Craig. It worked for me after using the new link. It seems like the global resource of google API isn't working.

The workbook did mention that for production environment, you need an API key. But in development, it's supposed to work.
 
Sankalita BhattSankalita Bhatt
Thanks a ton Craig. Your solution just saved me (and I'm sure I am not the only one) days of trial and error effort! We truely expect better from Salesforce, after all this is the very first VF developer guide that any beginner will attempt reading.
Venkat AmiyaVenkat Amiya
Thanks a ton Craig! After replacing the script it worked fine without even creating a Remote Site Detail
david roberts UKdavid roberts UK
I am having similar problems.
I wondered how to diagnose thisas Alerts weren't working.
I listed the accounts and they're being returned.
I tried https://maps.googleapis.com as a remote site.
Then I used Craig's implification. It worked!
The Alerts now worked.
I added alert(navigator.geolocation.getCurrentPosition(function(position));
and the map stopped working and Alerts stopped working.

That's enough for my addled brain at the moment...
 
david roberts UKdavid roberts UK
I used console.log extensively to track this down. Great tool!
I've restructured the code a little to help debugging.
I shrunk the map using style="width:500px;height:280px;....etc while using the console.
There's also a debug switch to overide the geolocation while testing for results.
You can also un-comment the apex pageblock list of results to see what warehouses are found.
I've added a range parameter as I'm a long way from San Francisco but it'll be useful as something passed into this controller from my vf page (eventually).
Don't forget to put in your Google API Key.

Here's the code...

vf page:

<apex:page sidebar="false" showheader="false" 
    standardController="Warehouse__c" recordSetVar="warehouses" 
    extensions="WarehouseUtils">
    
    <!-- from https://developer.salesforce.com/docs/atlas.en-us.202.0.workbook_vf.meta/workbook_vf/vf_action_findwarehouses_intro.htm -->

<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=YOUR-KEY-HERE"> </script>

<!--&Sensor no longer required: https://developers.google.com/maps/documentation/javascript/error-messages#sensor-not-required -->


    
    <!-- Set the map to take up the whole window -->
    <style>
        html, body { height: 100%; }
        .page-map, .ui-content, #map-canvas { width: 100%; height:100%; padding: 0; }
        #map-canvas { height: min-height: 100%; }
    </style>

<!-- java scripts... -->
<script>
    
    //global variables
    var lat, lon, range;
    
        function initialize() {
            
            // Set default values for the map if the device 
            // doesn't have geolocation capabilities. 
            // This is San Francisco:
            lat = 40; //37.77493;
            lon = -122.419416;
            range = 5000; //this will be sent in from a vf page
            // Logicom HQ
            //lat = '52.063421';
            //lon = '-0.730755';
            console.log('Range='+range);
            
            //navigator.geolocation
            //based on https://developer.mozilla.org/en-US/docs/Web/API/Geolocation/getCurrentPosition
            var options = {
              enableHighAccuracy: true,
              timeout: 5000,
              maximumAge: 0
            };
            
            function NavSuccess(pos) {
              console.log('Your current position is:');
              lat = pos.coords.latitude; //copy to globals
              lon = pos.coords.longitude;
            };
            
            function NavError(err) {
              console.warn('ERROR(' + err.code + '): ' + err.message);
            };
            
            
            if (navigator.geolocation){
                console.log('we have geolocation');
                navigator.geolocation.getCurrentPosition(NavSuccess, NavError, options);
                console.log('Latitude : ' + lat + ' Longitude: ' + lon);
                
                //remote invoke the Apex Class method findNearbyWarehouses...
                //@RemoteAction ---  global static List<Warehouse__c> findNearbyWarehouses(String lat, String lon, Strin range) {          
                Visualforce.remoting.Manager.invokeAction(
                    '{!$RemoteAction.WarehouseUtils.findNearbyWarehouses}', 
                    lat, lon, range,
                    function(result, event) {
                        //console.log('status='+event.status);
                        if (event.status) {
                            console.log(result);
                            //alert('result='+result.length);
                            for(var i=0; i<result.length ; i++) {               
                                console.log(result[i]);
                            }//for
                            console.log('result='+result.length);
                            
                            //debug switch to ignore geolocation
                            var ignore = false;
                            if (ignore){
                                lat = 37.77493;
                                lon = -122.419416;
                                range = 20;
                            }//ignore
                            
                            createMap(lat, lon, result);
                        } else if (event.type === 'exception') {
                            //exception case code
                        } else {
                            console.log(event.type);
                        }
                    }, 
                    {escape: true}
                ); //invoke action
            }
            else //we don't have geolocation so...
            {
                console.log('we do not have geolocation');
                var result = [];
                createMap(lat, lon, result);
            }//have geolocation?
            
            
        }   //initialize 
    
    
    function createMap(lat, lon, warehouses){

        var obj = document.getElementById("map-canvas")
        
        //MK : var mapProp = {center:new google.maps.LatLng(52.063421,-0.730755),    zoom:5,  mapTypeId:google.maps.MapTypeId.ROADMAP };
        //San Francisco: lat = 37.77493; lon = -122.419416;
        
        
        var mapProp = {center:new google.maps.LatLng(lat,lon),    zoom:10,  mapTypeId:google.maps.MapTypeId.ROADMAP };
        var map=new google.maps.Map(obj ,mapProp);
        // Set a marker for the current location
        var currentPosition = new google.maps.LatLng(lat,lon);
        console.log('currentposn...'+currentPosition);
        var positionMarker = new google.maps.Marker({
            map: map,
            position: currentPosition,
            icon: 'https://maps.google.com/mapfiles/ms/micons/green.png'
        });
        
        // Keep track of the map boundary that holds all markers
        console.log('mapBoundary...');
        var mapBoundary = new google.maps.LatLngBounds();
        //console.log(mapBoundary.getNorthEast()+','+mapBoundary.getSouthWest());
        mapBoundary.extend(currentPosition);
        
        
        console.log('markers...'+warehouses.length);
        if (warehouses.length>0) {
            // Set markers on the map from the @RemoteAction results
            var warehouse;
            for(var i=0; i<warehouses.length ; i++) {
                warehouse = warehouses[i];
                //console.log(warehouses[i]);
                setupMarker();
            }
        }//results to display
        map.fitBounds(mapBoundary);
        
         // setupMarker function goes here
        function setupMarker(){ 
            var warehouseNavUrl='http://www.virtualworlds.co.uk';
            //alert('setupMarker');
            //console.log('setupMarker');
            
            // Determine if we are in Salesforce1 and set navigation 
            // link appropriately
            try{
                if(sforce.one){
                    console.log('SF1');
                    //alert('SF1');
                    warehouseNavUrl =
                        'javascript:sforce.one.navigateToSObject(\'' + 
                        warehouse.Id + '\')';
                }
            } catch(err) {
                console.log(err);
                warehouseNavUrl = '\\' + warehouse.Id;
            }
            console.log('url'+warehouseNavUrl);
    
            var warehouseDetails =
                '<a href="' + warehouseNavUrl + '">' +
                warehouse.Name + '</a><br/>' +
                warehouse.Street_Address__c  + '<br/>' +
                warehouse.City__c + '<br/>'  +
                warehouse.Phone__c;
            
            // Create a panel that appears when the user clicks on the marker
            var infowindow = new google.maps.InfoWindow({ 
               content: warehouseDetails
            });
            
           
            // Add the marker to the map
            var marker = new google.maps.Marker({
                map: map,
                position: new google.maps.LatLng( 
                    warehouse.Location__Latitude__s, 
                    warehouse.Location__Longitude__s)
            });
            
            
            mapBoundary.extend(marker.getPosition());
           
            // Add the action to open the panel when its marker is clicked
            google.maps.event.addListener(marker, 'click', function(){
                infowindow.open(map, marker);
            });
            
        }//setupMarker
        
    }//createmap
    
</script>
    

<!-- list returned accounts as cross check 
<apex:pageblock>  
    
    <apex:pageBlockSection id="listAccs" title="List of names" columns="1">
    <apex:repeat value="{!warehouses}" var="c">
        <apex:outputText value="{0} at {1},{2}" >
        <apex:param value="{!c.Name}"/>
        <apex:param value="{!c.Location__Latitude__s}"/>
            <apex:param value="{!c.Location__Longitude__s}"/>
            
            </apex:outputText>
    </apex:repeat>
</apex:pageBlockSection>
</apex:pageblock>
-->

    <!--  All content is rendered by the Google Maps code
      This minimal HTML just provides a target for GMaps to write to.

    An alternative style which has smaller map (useful when using console for debugging): style="width:500px;height:280px;padding:10px;border:1px solid black ;font-family: Arial;"
-->

    <body onload="initialize()" >
        <div id="map-canvas" style="border:1px solid black ;font-family: Arial;"> </div>
    </body>    
    
</apex:page>
---------------------------------------------------------------
...and the util class:
global with sharing class WarehouseUtils {

    public WarehouseUtils(ApexPages.StandardSetController controller) { }

    // Find warehouses nearest a geolocation
    @RemoteAction
    global static List<Warehouse__c> findNearbyWarehouses(String lat, String lon, String range) {

    // Initialize results to an empty list
    List<Warehouse__c> results = new List<Warehouse__c>();

    // If geolocation parameters are invalid, use San Francisco
    if(String.isBlank(lat) || String.isBlank(lon)) {
        lat = '47.793731';
        lon = '-122.395002';
    }
    if (range=='0') {range = '50';}
system.debug('range='+range);
    // SOQL query to get the nearest warehouses
    String queryString =
   'SELECT Id, Name, Location__Longitude__s, Location__Latitude__s, ' +
       'Street_Address__c, Phone__c, City__c ' +
   'FROM Warehouse__c ' +
   'WHERE DISTANCE(Location__c, GEOLOCATION('+lat+','+lon+'), \'mi\') < '+range+
   ' ORDER BY DISTANCE(Location__c, GEOLOCATION('+lat+','+lon+'), \'mi\') ' +
   'LIMIT 500';
system.debug(queryString);
        
    // Run the query
    results = database.Query(queryString);

    system.debug('#results='+results.size());

    // Return the query results
    return(results);
}


}

...enjoy.