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
SiimSiim 

Javascript remoting

Hi there,

I'm not able to make my javascript remoting trial work.

My requirement: I want to save coordinate results i get from geocoding to my account.

I want to use CLIENT SIDE google geocoding to display an inline google map but i also want to save the coordinates.I am trying to use Javacript remoting to save the coordinates. Can i call the apex function directly in $(document).ready(function() as shown below?

My page:

<apex:page standardController="Account" extensions="testJS">

<head>
<!--
<apex:includeScript value="{!URLFOR($Resource.BuzzJS, 'buzz_js/jqueryui/js/jquery-1.4.4.min.js')}" />-->
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> 
<script type="text/javascript"> 
    //var j$ = jQuery.noConflict(); 
$(document).ready(function() {
  
  var myOptions = {
    zoom: 15,
    mapTypeId: google.maps.MapTypeId.ROADMAP,
    mapTypeControl: false
  }
  
  var map;
  var marker;
  
  var geocoder = new google.maps.Geocoder();
  var address = "{!Account.BillingStreet}, " + "{!Account.BillingCity}, " + "{!Account.BillingPostalCode}, " + "{!Account.BillingCountry}";
  
  var infowindow = new google.maps.InfoWindow({
    content: "<b>{!Account.Name}</b><br>{!Account.BillingStreet}<br>{!Account.BillingCity}, {!Account.BillingPostalCode}<br>{!Account.BillingCountry}"
  });

  geocoder.geocode( { address: address}, function(results, status) {
    if (status == google.maps.GeocoderStatus.OK && results.length) {
      if (status != google.maps.GeocoderStatus.ZERO_RESULTS) {
      
        //create map
        map = new google.maps.Map(document.getElementById("map"), myOptions);
      
        //center map
        map.setCenter(results[0].geometry.location);
        
        //create marker
        marker = new google.maps.Marker({
            position: results[0].geometry.location,
            map: map,
            title: "{!Account.Name}"
        });
        
        var latitude = results[0].geometry.location.lat();
        var longitude = results[0].geometry.location.lng();
        alert("Latitude:- "+latitude);
        alert("Longitude:- "+longitude);
        alert("{!account.Name}");
        testing(latitude,longitude,"{!account}");
        
        //add listeners
        google.maps.event.addListener(marker, 'click', function() {
          infowindow.open(map,marker);
        });
        google.maps.event.addListener(infowindow, 'closeclick', function() {
          map.setCenter(marker.getPosition()); 
        });
        
      }
      
    } else {
      $('#map').css({'height' : '15px'});
      $('#map').html("Oops! {!Account.Name}'s billing address could not be found, please make sure the address is correct.");
      resizeIframe();
    }
  });
  
  function resizeIframe() {
    var me = window.name;
    if (me) {
      var iframes = parent.document.getElementsByName(me);
      if (iframes && iframes.length == 1) {
        height = document.body.offsetHeight;
        iframes[0].style.height = height + "px";
      }
    }
  }
  
    function testing(var lat,var long,var acc) {
        testJS.setLatLong(lat,long,acc,function(result, event) {
        // callback function logic 
        if(event.status && event.result)
            alert("Update successful");
        }, {escape:true})
        
    } 
});
</script>

<style>
#map {
  font-family: Arial;
  font-size:12px;
  line-height:normal !important;
  height:250px;
  background:transparent;
}
</style>

</head>
<body>
<div id="map"></div> 
</body>
</apex:page>

 

My controller is as follows:

 

global class testJS {
    public final Account acct;
    // The extension constructor initializes the private member
    // variable acct by using the getRecord method from the standard
    // controller.
    public testJS (ApexPages.StandardController stdController) {
        this.acct = (Account)stdController.getRecord();
    }
    public testJS(){}
    @RemoteAction
    global static void setLatLong ( Decimal lat, Decimal lon,Id accId) {
        Account acc = [select id, lat__c,lon__c from Account where id =:accid limit 1 ];
        acc.lat__c = lat;
        acc.lon__c = lon;
        update acc;
    }
}

 

 Am i missing something in implementing the javascript Remoting? Any help would be much appreciated. Many thanks, Siim

Best Answer chosen by Admin (Salesforce Developers) 
SiimSiim

 

Your replies helped me to debug the code better. In fact the error was in the javascript, 

 

function testing(lat,long,acc) {
        testJS.setLatLong(lat,long,acc,function(result, event) {
        // callback function logic 
        //if(event.status)
            console.log("Update successful");
        }, {escape:true})
        
    }

 My function declaration should have been like

function testing(lat,long,acc) { instead of function testing(var lat,var long,var acc) {

My stupid mistake.Hope his post helps someone. 

 

Thanks you  Starz26 for your prompt replies.

Siim


All Answers

Starz26Starz26

Do you have an extension or controller that : {!Account.Name} gets the values from?

 

Here is a working version of my remoting:

 

Remote Class:

 

public without sharing class FieldTravelRemote {

public FieldTravelRemote(FieldTravel controller) {

    }    


          
        @RemoteAction
        public static testWrapper findIHO(ID i){
            system.debug(i);
            testWrapper t;    
                
            Implementation_Hand_Off__c iho = [Select ID, name, FSA_Type__c, Opportunity_Name__r.AccountID, FSA_Number__c, 
                            total_cartridge_volume__c, Opportunity_name__r.lab_support_of_project__c,
                            Opportunity_name__r.nursing_support_of_project__c,
                            Opportunity_name__r.administration_support_of_project__c,
                            Opportunity_Name__r.access_to_dept_for_this_project__c,
                            primary_operators__c,Opportunity_Name__r.Account.BillingPostalCode, Opportunity_Name__r.Account.ShippingPostalCode,
                            nurse_driven_protocols_used_ED_CC__c From Implementation_Hand_Off__c WHERE ID = :i];
                        t = new testWrapper(iho);
                system.debug(t);
                                system.debug(iho);
                // Account a = [Select ID, Name, BillingCity From Account where ID = :theID];
                return t;
        }

        private class testWrapper{
                
                string lab {get;set;}
                string nurse {get;set;}
                string admin {get;set;}
                string access {get;set;}
                string operators {get;set;}
                decimal distance {get;set;}
                
                        public  testWrapper(Implementation_Hand_Off__c i){
                                
                                lab = i.Opportunity_Name__r.lab_support_of_project__c;
                                nurse = i.Opportunity_Name__r.nursing_support_of_project__c;
                                admin = i.Opportunity_Name__r.administration_support_of_project__c;
                                access = i.Opportunity_Name__r.access_to_dept_for_this_project__c;
                                operators = i.primary_operators__c;
                                
                                if(i.Opportunity_Name__r.Account.BillingPostalCode == NULL && i.Opportunity_Name__r.Account.ShippingPostalCode != Null){
                                        distance = howFar(i.Opportunity_Name__r.Account.ShippingPostalCode);
                                }else if(i.Opportunity_Name__r.Account.ShippingPostalCode == NULL && i.Opportunity_Name__r.Account.BillingPostalCode != Null){
                                        distance = howFar(i.Opportunity_Name__r.Account.BillingPostalCode);
                                }else{
                                        distance = 0;
                                }               
                        
                        }

                private decimal howFar(String z){
                
                    ID uID = UserInfo.getUserID();    
                User u = [Select PostalCode from User Where ID = :uID limit 1];
                string uz = u.PostalCode;    
                        
                        googleMaps gm = new googleMaps(z,uz);
    
            return gm.distance;
                
                
                }


        }

        

}

 Java script that calls it:

 

            FieldTravelRemote.findIHO(i,function(result, event){

                if(event.type =='exception'){
                    alert('Event: ' + event.message);
                }else{
                    var dist = result.distance == 0 ? "No Valid Zip on Account Record" : "This Account is " + result.distance + " miles from you"
                    icon.src=resourceAddy + 'DataTables-1.8.2/examples/examples_support/details_close.png';
                    anOpen.push( theRow );
                    oTable.fnOpen(theRow, 
                        "<form > " +
                        "<div id='map_test" + i +"' ></div><div id='map_error" + i +"'>The address: <br />" + addy + " <br />is not valid!</div>" +
                        "<div id='addDataContainer'><div id='addDataTitle'><h1>" + dist + "</h1></div>" +
                        "<div id='addDataColOne' class='addData'>" +
                        "<table><tr><td>Lab Support:</td><td>" + result.lab + "</td></tr>" +
                        "<tr><td>Nursing Support:</td><td>" + result.nurse + "</td></tr>" +
                        "<tr><td>Admininstration Support:</td><td>" + result.admin + "</td></tr>" +
                        "<tr><td>Access To Departments:</td><td>" + result.access + "</td></tr>" +
                        "<tr><td>Primary Operators:</td><td>" + result.operators + "</td></tr>" +
                        "</div><div id='addDataColTwo' class='addData'>THIS IS COLUMN 2</div></div></form>","info_row");

                    mapinitialize(addy, i);            
                    return true;
                }       
            });

 you can use the {! notation but only if the class (not remote) is able to return that variable, just like you would use it anywhere else on the page outside of the javascript.

 

Notice that in the remote class, I had to put in a contructor for the calss. All the examples I have seen do not have that but it would not let me save without it....

SiimSiim

Hi,

Thanks for your reply.In my case i call my @remote action function directly in the javascript not from the page on load using the

$(document).ready(function()

.

 

However am not sure if this is valid and . To your point i use an extension and have 2 controllers:

public testJS (ApexPages.StandardController stdController) {
        this.acct = (Account)stdController.getRecord();
    }
    public testJS(){}

 

I tried to compare other javascript examples i got on the web and yours too.but i dont seem to find any syntax error or something wrong with the way i called my JS function.

 

The page works but as soon as i add the javascript remoting, the google map is not longer loaded and i suspect its my JS remoting call which is wrong in some way.

 

Has anybody tried to save the coordinates to salesforce objects using client side geocoding?If yes, what was the approach?

 

Thanks,

Siim

Starz26Starz26

I too call my remote from the javascript..... (I only posted the exact part that calls it.

 

Here is my Google maps class.

 

for my use case, I have row of data, when a row is selected it opens up a detail section and calls the javascript. The Java uses the address of the clicked row to geocode and draw a google map of the address in the detail section....

 

public class googleMaps {

/** 

Code adapted from:
http://www.bulkified.com/How+to+use+the+Google+Maps+API+in+Salesforce.com

Google API is at

http://code.google.com/apis/maps/documentation/distancematrix/

There is a limit so may need to be on request only.
**/

    public String duration {get;set;}
    public Integer travelTime {get;set;}
    public Decimal distance {get;set;}

    public googleMaps(
            String address1,
            String address2) {
                
        String jsonResults = getJsonResults(address1, address2);
        jsonResults = formatJsonResults(jsonResults);
        updateJsonSections(jsonResults);
    }

    public String getJsonResults(
            String address1,
            String address2) {
        
        HttpRequest req = new HttpRequest();
        Http http = new Http();
        
        req.setMethod('GET');
        
        String url = 'https://maps.googleapis.com/maps/api/distancematrix/json'
            + '?origins=' + address1
            + '&destinations=' + address2
            + '&mode=driving'
            + '&sensor=false'
            + '&language=en'
            + '&units=imperial';
        
        system.debug('URL is = ' + url);    
        req.setEndPoint(url);
        
        HTTPResponse resp = http.send(req);
        
        String jsonResults = resp.getBody().replace('\n', '');

        return jsonResults;
    }
    
    public String formatJsonResults(String value) {
        
        system.debug('json initial value is = ' + value);
        
        value = value.replace('{', ', ');
        value = value.replace('}', ', ');
        value = value.replace('[', ', ');
        value = value.replace(']', ', ');
        value = value.replace('"', '');
        system.debug('json final value is = ' + value);
        return value; 
          
    }
    
    public void updateJsonSections(
        String jsonResults) {
        
        List<String> jsonSections = jsonResults.split(', ');
        system.debug('JSON section are = ' + jsonSections);
        for (Integer i = 0; i < jsonSections.size(); i++) {
            jsonSections[i] = jsonSections[i].trim();
            system.debug('JSON Section ' + i + ' is = ' + jsonSections[i]);
            if (jsonSections[i].contains('duration :')) {
                duration = parseDuration(jsonSections[i + 1]);
                travelTime = parseTravelTime(duration);
            }
            
            if (jsonSections[i].contains('distance :')) {
                distance = parseDistance(jsonSections[i + 1]);
            }
        }
    }

    public Decimal parseDistance(String value) {
        value = value.replace('text : ', '');
        value = value.replace(' mi', '');
        value = value.replace(' ft', '');
        value = value.replace(',', '');
        value = value.trim();
        
        return Decimal.valueOf(value);
    }
    
    public String parseDuration(String value) {
        value = value.replace('text : ', '');
        
        return value;
    }
    
    public Integer parseTravelTime(String value) {
    
        Integer tmpMinutes = 0;
    
        List<String> durationNodes = value.split(' ');
        String prevDurationNode = '';
        
        for (String durationNode : durationNodes) {
            if (durationNode == 'day' || durationNode == 'days') {
                tmpMinutes += Integer.valueOf(prevDurationNode) * 1440;
            }
            if (durationNode == 'hour' || durationNode == 'hours') {
                tmpMinutes += Integer.valueOf(prevDurationNode) * 60;
            }
            if (durationNode == 'min' || durationNode == 'mins') {
                tmpMinutes += Integer.valueOf(prevDurationNode);
            }
            
            prevDurationNode = durationNode;
        }
    
        return tmpMinutes;  
    }

}

 

Starz26Starz26

Also,

 

The result returned is not true or false in your example it is Null or void. So I believe the reason you are not getting your alert is due to:

 

if(event.status && event.result)
            alert("Update successful");
        }, {escape:true})

I believe you are using the event wrong....

 

event.status should = True or success or something.... The result object is the results returned from the remote class... the results are not event.results rather it should be result.{FieldName or Value}

 

 

SiimSiim

Hi again,

You gave a very good exampe using Server side google geocoding. Since i am not sure how salesforce  behaves in terms of ip requests when it comes to server side requests and web service? if i have say 250 users and all of them use the the page more than 10 times a day, i would surely exceed the Google API limit which is 2500. That's why i want to use client side geocoding to save the coordinates and reuse it later on.

 

My goal is to simply save the latitudes and longitudes values i get in the javascript call to the Google Javascript API using

results[0].geometry.location.lat(); 
results[0].geometry.location.lng();

, to the account fields.

 

 I even tried remvoing the condition 

if(event.status)
            alert("Update successful");
        }, {escape:true})

before displaying my alert but it does not help.

 

Is there any other way to save values generated in javascript directly to salesforce object fields in visualforce? 

Thanks,

Siim

Starz26Starz26

pass the ID of the account into the remote class and update the account record from there...

 

 

 

Test for a value in the field on the record, if not there,  call the geocode class from the remote, get the results, then perform a dml within the remote class to update the fields.

 

If you want to store information on the records themselves then you will have to do this server side. If you want to store them locally, you will need to create a cookie, and check for that...

 

Once you are in the remote class you can do dml etc with the passed parameters and not need to use the javascript client side to update the record as you can do it all from within the remote class.

 

If I am not quite getting your idea of "save the results" please be more specific as to where you want to save them, how they will be reused, etc. Especially when it comes to multiple users at once.

SiimSiim

 

Your replies helped me to debug the code better. In fact the error was in the javascript, 

 

function testing(lat,long,acc) {
        testJS.setLatLong(lat,long,acc,function(result, event) {
        // callback function logic 
        //if(event.status)
            console.log("Update successful");
        }, {escape:true})
        
    }

 My function declaration should have been like

function testing(lat,long,acc) { instead of function testing(var lat,var long,var acc) {

My stupid mistake.Hope his post helps someone. 

 

Thanks you  Starz26 for your prompt replies.

Siim


This was selected as the best answer