I'm quite new to Visualforce so i just want to know what would be a good approach to solving this improvement i have to make in an org.

I want to make a Visualforce page to attach it on the accounts main page, with 2 text fields 1 for City and 1 for Postal Code.

I have a file with all PC of Spain. What we want to acomplish is that when we type the PC we can see the City and vice versa. If some City has more than 1 Postal code we want to show them all.

The Visualforce page is quite easy since it's only 2 text labels and 2 text fields. But I'm quite confused on how to approach the controller. So i would like to know what are the tips that more experienced people could give me about this.

Edit: I found out this website http://www.zippopotam.us/ wich is pretty useful to get the information , so there's no need to neither create a new object or upload some files.

Thanks for your time.


I suggest you to follow the below approach

  1. Create a List Custom Setting. Use the name field to store the Postal Code. Create another field to store the City Name.
  2. Upload your file of Postal Code and City Name mapping to this Custom Setting.
  3. In your VF page, add a action support on the Postal Code for the event onchange.
  4. Call a Controller function which queries the custom setting based on the Postal Code entered and returns the City.
  5. Update the City variable in Controller with the value from the custom setting.
  • 1
    Hello, i really liked that idea but i just found this zippopotam.us, i think this is better than creating the Custom List. What do you think? – Alexander Gimenez Feb 10 '15 at 14:41
  • 1
    Yes, that should work out well as well. – RajeshShah Feb 11 '15 at 4:02

I finally acomplished to make it work as an apex page by itself, now i only need to make the button trigger update the original Zip cope field, wich is the struggle i'm having at the moment. I will copy my code here in case somebody needs in the future :) Since i find this really useful (It maybe needs some modifications to adapt your organization)

  <apex:page controller="zipcodeGeonames">  
  <apex:form > 
  <apex:pageBlock >
  <apex:actionRegion id="lookupRegion" >
     <apex:outputLabel value="Enter 5 digit zip code " for="inputzip" />
     <apex:inputText value="{!zipValue}" id="inputzip" />
     <apex:outputLabel value="Enter Country " for="inputCountry" />
     <apex:inputText value="{!inputCountry}" id="inputCountry" />
     <!-- The rerender attribute causes addressList to be re-rendered when the button is clicked -->
     <apex:commandButton action="{!lookupList}" value="Lookup!" rerender="addressList" />

<apex:pageBlockSection >
    <apex:pageBlockTable id="addressList" var="z" value="{!zipList}" >
        <apex:column >
            <apex:facet name="header">Zip Code</apex:facet>            
                <input type="radio" name="Postal Lookup" value="{!z.zipCount}" onclick="javascript:sendZipSelection(this.value);" />
        <apex:column >
            <apex:facet name="header">Country</apex:facet>
        <apex:column >
            <apex:facet name="header">City</apex:facet>
        <apex:column >
            <apex:facet name="header">State</apex:facet>            


And here's the controller :

public with sharing class zipcodeGeonames {

// Constructor
public zipCodeGeonames() {
    zipValue = '';
    inputCountry = '';
    zips = new List<zipInfo>();    

public class zipCodeException extends Exception {}

// zipValue property is used by VF page and is the zipcode entered by user (required)
public string zipValue {
    get { return zipValue; }
    set { zipValue = value; }
// Country input by user (optional)
public string inputCountry {
    get { return inputCountry; }
    set { inputCountry = value; }

//  VF page calls this with the user's selection.  If this example is used in an app then this function interface to the remainder of the app  
public void zipSelection() {
    string value = Apexpages.currentPage().getParameters().get('myParam');
    system.debug('zipSelected is '+Apexpages.currentPage().getParameters().get('myParam')); 

public List<zipInfo> zips;
public zipInfo z = new zipInfo();       
public List<zipInfo> zipList {
    get { 
        return zips; 
    set { zipList = value; }            

// This class holds the details for each zipcode looked up 
public class zipInfo {
    private string zip;
    private string city;    
    private string state;
    private string country;
    private integer zipIndex;       

    // Properties for VF page
    public string zipCity {
        get {return city;}
    public string zipZip {
        get {return zip;}
    public string zipState {
        get {return state;}
    public string zipCountry {
        get {return country;}
    public integer zipCount {
        get {return zipIndex;}

    // Public functions to set private member variables
    public void setzipCity(string value){
        city = value;
    public void setzipZip(string value){
        zip = value;
    public void setzipState(string value){
        state = value;
    public void setzipCountry(string value){
        country = value;
    public void setzipIndex(integer value){
        zipIndex = value;


// Helper function to print 'zips' (the zipcode list)
private void printZipList()
    integer counter = 0;
    while (zips.size() > counter) {
        system.debug('zips['+counter+'] = '+zips[counter]);

public PageReference lookupList()
    boolean found = false;
    integer zipListIndex = 0;
    zips.clear();                   // Remove results from previous lookups 
    string geonamesEndpoint = 'Http://api.zippopotam.us/es/'+zipValue;
    system.debug(LoggingLevel.Error, 'Calling endpoint='+geonamesEndpoint);

    HttpRequest req = new HttpRequest();
    HttpResponse res = new HttpResponse();
    Http http = new Http();

    try {
        res = http.send(req);
        if (res.getStatusCode() != 200) {
                throw new zipCodeException(res.getStatus());
    } catch (zipCodeException e) {
        system.debug(LoggingLevel.Error, 'Error HTTP response code = '+res.getStatusCode()+'; calling '+geonamesEndpoint );
        return null;

    JSONParser parser = JSON.createParser(res.getBody());
    System.JSONToken token;
    string text;

    parser.nextToken();     // Eat the first { 
    parser.nextToken();     // eat the postalcodes token
    parser.nextToken();     // eat the array [
    System.debug(parser.gettext());    // eat the START_OBJECT {

    while((token = parser.nextToken()) != null) {
        // Parse the object
        if ((token = parser.getCurrentToken()) != JSONToken.END_OBJECT) {
            text = parser.getText();
            if (token == JSONToken.FIELD_Name && text == 'country abbreviation') {
                found = true;
            } else if (token == JSONToken.FIELD_Name && text == 'state') {
                found = true;
            } else if (token == JSONToken.FIELD_Name && text == 'place name') {
                found = true;
            } else if (token == JSONToken.FIELD_Name && text == 'postalcode') {              
                found = true;
           // System.debug(parser.getCurrentToken());
        } else {                // Got to an end object so append it to the list
            if (found) {                        // Only do this if we extracted info we wanted.
                zipListIndex ++;
                zips.add(z);                    // add a reference to the list
                z = new zipInfo();              // allocate more memory to store the next object 
                found = false;                  // reset
            // advance to next object
            token = parser.nextToken();
            if (token == JSONToken.END_ARRAY) {             // we reached end of array of objects representing zipcodes
    return null;


The original code I obtained was from here:

https://scotthung.wordpress.com/2014/10/08/how-to-zip-code-lookup-in-a-salesforce-trigger/ So much thanks to Scott Thung!

I adapted the code to make it use the Zippopotamus API. The code Now is set to ignore the Country and use allways Spain but you just have to modify a few lines of code to make it work for your country too or for every supported by the API!

I hope this helps someone to get out of the situation I was few weeks ago!

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.