# Landmarks Service API example

This section presents the full source code of a working sample widget for the Landmarks Service. You can download the `wgz` package for this widget from section Example widgets.

For general information about creating widgets, see section Widget component files.

### Info.plist

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Nokia//DTD PLIST 1.0//EN" "http://www.nokia.com/NOKIA_COM_1/DTDs/plist-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>DisplayName</key>
        <string>LandmarksSample</string>
        <key>Identifier</key>
        <string>com.nokia.widget.sapi.landmarks.sample</string>
        <key>Version</key>
        <string>1.0</string>
        <key>MainHTML</key>
        <string>landmarks-sample.html</string>
    </dict>
    </plist>

### landmarks-sample.html

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
    <head>
        <meta http-equiv="content-type" content="text/html; charset=utf-8">
        <script type="text/javascript" src="js/landmarks-sample.js" charset="utf-8"></script>
        <script type="text/javascript" src="js/common.js" charset="utf-8"></script>
    </head>
    <body onload='setup()' bgcolor="#ddeeff">
        <form>
            <h3>Landmarks Service API Sample Widget</h3>
            <input type="button" onclick="addCategory('img1');" value="AddCategory"><img id="img1" src="pic/blank.png" width="25" height="25" align="center"><br>
            <input type="button" onclick="addLandmark('img2')" value="AddLandmark"><img id="img2" src="pic/blank.png" width="25" height="25" align="center"><br>
            <input type="button" onclick="getListDatabases('img3')" value="GetListDatabases"><img id="img3" src="pic/blank.png" width="25" height="25" align="center"><br>
            <input type="button" onclick="getListCategories('img4')" value="GetListCategoriesSync"><img id="img4" src="pic/blank.png" width="25" height="25" align="center"><br>
            <input type="button" onclick="getListCategoriesAsync('img5')" value="GetListCategoriesAsync"><img id="img5" src="pic/blank.png" width="25" height="25" align="center"><br>
            <input type="button" onclick="getListLandmarks('img6')" value="GetListLandmarksSync"><img id="img6" src="pic/blank.png" width="25" height="25" align="center"><br>
            <input type="button" onclick="getListLandmarksAsync('img7')" value="GetListLandmarksAsync"><img id="img7" src="pic/blank.png" width="25" height="25" align="center"><br>
            <input type="button" onclick="cancelCategoriesAsync('img8')" value="CancelCategoriesAsync"><img id="img8" src="pic/blank.png" width="25" height="25" align="center"><br>
            <input type="button" onclick="cancelLandmarksAsync('img9')" value="CancelLandmarksAsync"><img id="img9" src="pic/blank.png" width="25" height="25" align="center"><br>
            <input type="button" onclick="deleteCategory('img10')" value="DeleteCategory"><img id="img10" src="pic/blank.png" width="25" height="25" align="center"><br>
            <input type="button" onclick="deleteLandmark('img11')" value="DeleteLandMark"><img id="img11" src="pic/blank.png" width="25" height="25" align="center"><br>
            <input type="button" onclick="exportLandmarks('img12')" value="ExportLandmarks"><img id="img12" src="pic/blank.png" width="25" height="25" align="center"><br>
            <input type="button" onclick="importLandmarks('img13')" value="ImportLandmarks"><img id="img13" src="pic/blank.png" width="25" height="25" align="center"><br>
            <input type="button" onclick="organiseLandmarks('img14')" value="OrganiseLandmarks"><img id="img14" src="pic/blank.png" width="25" height="25" align="center"><hr>
            <div class='landmarks' id='landmarks' bgcolor="#ddeeff" style=width:100%;height:100%;overflow:auto>
            </div>
        </form>
    </body>
    </html>

### common.js

    // common.js
    //
    // This file contains some utility functions

    // Check the error code and show the information to users
    function checkError(message, resultList, divId, imgId)
    {
      var errCode = resultList.ErrorCode;
      var msg = "";

      if (errCode) {
        msg = message + "<BR>" + "Failed Error: " + errCode + "<BR>";
        if(resultList.ErrorMessage != undefined)
          msg += "Error Message: " + resultList.ErrorMessage;
        showIMG(imgId,"no");
      } else {
        showIMG(imgId,"yes");
      }

      //print error message
      if(divId != null && divId != undefined)
        document.getElementById(divId).innerHTML = msg;
      console.info(msg);

      return errCode;
    }

    // Build the message by reading a iteratorable list in a recursive manner
    function showIterableList(iterator)
    {
      var msg = "";
      try
      {
        iterator.reset();
        var item;
        while (( item = iterator.getNext()) != undefined ){
          msg += showObject( item );
        }
      }
      catch(e)
      {
        alert('<showIterableList> ' + e);
      }
      return msg;
    }

    // Build the message by reading a JS object in a recursive manner
    function showObject( obj )
    {
      var txt = "";
      try {
        if ( typeof obj != 'object' )
          return "" + obj + '<BR/>';
        else {
          for(var key in obj) {
            txt +=  key + ":";
            txt += showObject( obj[key] );
            txt += '<BR/>';
          }
          txt += '<BR/>';
        }
      }
      catch (e)
      {
        alert("showObject: " + e);
      }
      return txt;
    }

    // Show the image to indicate the test result
    function showIMG(imgId, isOK)
    {
      if(imgId == null || imgId == undefined)
        return;

      if(isOK == "yes")
        document.getElementById(imgId).src = "pic/yes.png";
      else if(isOK == "no")
        document.getElementById(imgId).src = "pic/no.png";
      else
        document.getElementById(imgId).src = "pic/blank.png";
    }

    // Show elements in object by using 'alert'
    function testObject(obj)
    {
      var msg = "";
      for(var key in obj) {
        msg = msg + ":" + key + "=" + obj[key];
      }
      alert(msg);
    }

    // Test whether the input is numeric
    function IsNumeric(sText)
    {
      var ValidChars = "0123456789.";
      var IsNumber=true;
      var Char;

      for (i = 0; i < sText.length && IsNumber == true; i++)
      {
        Char = sText.charAt(i);
        if (ValidChars.indexOf(Char) == -1)
        {
          IsNumber = false;
        }
      }
      return IsNumber;
    }

### landmarks-sample.js

    // landmarks-sample.js
    //
    // In this sample Categories will be added, deleted, and listed from default database,
    // Landmarks will be imported, exported, added, deleted, and listed from sample database
    // Also, async operation will be canceled

    //SAPI Error Codes
    // 0    - Success
    // 1000 - InvalidServiceArgument
    // 1001 - UnknownArgumentName
    // 1002 - BadArgumentType
    // 1003 - MissingArgument
    // 1004 - ServiceNotSupported
    // 1005 - ServiceInUse
    // 1006 - ServiceNotReady
    // 1007 - NoMemory
    // 1008 - HardwareNotAvailable
    // 1009 - ServerBusy
    // 1010 - EntryExists
    // 1011 - AccessDenied
    // 1012 - NotFound
    // 1013 - UnknownFormat
    // 1014 - GeneralError
    // 1015 - CancelSuccess
    // 1016 - ServiceTimedOut
    // 1017 - PathNotFound

    // Declare the service object
    var so;

    // id of the div used to display information
    const DIV_ID = 'landmarks';

    // imgid for callback1 function
    var imgid_callback1;

    // imgid for callback2 function
    var imgid_callback2;

    // Called from onload()
    function setup()
    {
      try
      {
        so = device.getServiceObject("Service.Landmarks", "IDataSource");
        console.info("setup: so: %s", so);
      }
      catch(e)
      {
        alert('<setup> ' +e);
      }
    }

    // Add new Category
    // Note: Category with the CategoryName can not be added twice.
    // So, you should delete just added category first and add category after that
    function addCategory(imgId)
    {
      // Setup input params using dot syntax
      var category = new Object();
      category.CategoryName = 'MyCategory';
      var criteria = new Object();
      criteria.Type = 'Category';
      criteria.Data = category;
      try
      {
        var resultList = so.IDataSource.Add(criteria);
        checkError("IDataSource::addCategory",resultList,DIV_ID,imgId);
      }
      catch(e)
      {
        showIMG(imgId,"no");
        alert ("addCategory: " + e);
      }
    }

    // Populate a Landmark Object with sample data
    function populateLandmark(landmark)
    {
      var landmarkfields = new Object();
      landmarkfields.Country = 'USA';
      landmarkfields.AreaCode = '01803';
      landmarkfields.City = 'Boston';
      landmarkfields.District = 'Dist';
      landmarkfields.Street = 'Wayside Rd';
      landmarkfields.Telephone = '781-993-9393';

      landmark.DatabaseURI      = 'file://c:eposlm.ldb';
      landmark.LandmarkName     = 'NewLandmark';
      landmark.LandmarkDesc     = 'My Landmark';
      landmark.LandmarkFields   = landmarkfields;
    }

    // Add new Landmark (sync operation)
    function addLandmark(imgId)
    {
      // Setup input params using dot syntax
      var criteria = new Object();
      criteria.Type = 'Landmark';

      try
      {
        var lm = so.IDataSource.New( criteria );
        populateLandmark(lm);
        var criteria1 = new Object();
        criteria1.Type = 'Landmark';
        criteria1.Data = lm;
        var resultList = so.IDataSource.Add(criteria1);
        checkError("IDataSource::addLandmark",resultList,DIV_ID,imgId);
      }
      catch(e)
      {
        showIMG(imgId,"no");
        alert ("addLandmark: " + e);
      }
    }

    // Get List of all Databases (sync operation)
    function getListDatabases(imgId)
    {
      // Setup input params using dot syntax
      var criteria = new Object();
      criteria.Type = 'Database';
      try
      {
        var resultList = so.IDataSource.GetList(criteria);
        if(!checkError("IDataSource::getListDatabases",resultList,DIV_ID,imgId)) {
          document.getElementById(DIV_ID).innerHTML = showIterableList(resultList.ReturnValue);
        }
      }
      catch(e)
      {
        showIMG(imgId,"no");
        alert ("getListDatabases: " + e);
      }
    }

    // Get List of all Categories (sync operation)
    function getListCategories(imgId)
    {
      // Setup input params using dot syntax
      var criteria = new Object();
      criteria.Type = 'Category';
      try
      {
        var resultList = so.IDataSource.GetList(criteria);
        if(!checkError("IDataSource::getListCategories",resultList,DIV_ID,imgId)) {
          document.getElementById(DIV_ID).innerHTML = showIterableList(resultList.ReturnValue);
        }
      }
      catch(e)
      {
        showIMG(imgId,"no");
        alert ("getListCategories: " + e);
      }
    }

    // Get List of all Categories (Async operation)
    function getListCategoriesAsync(imgId)
    {
      // Setup input params using dot syntax
      var criteria = new Object();
      criteria.Type = 'Category';
      try
      {
        imgid_callback1 = imgId;
        var resultList = so.IDataSource.GetList(criteria, callback1);
        if(!checkError("IDataSource::getListCategoriesAsync",resultList,DIV_ID,imgId))
          showIMG(imgId, "");
      }
      catch(e)
      {
        showIMG(imgId,"no");
        alert ("addCategory: " + e);
      }
    }

    // Get List of Landmarks (sync operation)
    function getListLandmarks(imgId)
    {
      var sort = new Object();
      sort.Key = 'LandmarkName';
      sort.Order = 'Descending';
      var criteria = new Object();
      criteria.Type = 'Landmark';
      criteria.Sort = sort;
      try
      {
        var resultList = so.IDataSource.GetList(criteria);
        if(!checkError("IDataSource::getListLandmarks",resultList,DIV_ID,imgId)) {
          document.getElementById(DIV_ID).innerHTML = showIterableList(resultList.ReturnValue);
        }
      }
      catch(e)
      {
        showIMG(imgId,"no");
        alert ("getListLandmarks: " + e);
      }
    }

    // Get List of Landmarks (Async operation)
    function getListLandmarksAsync(imgId)
    {
      var sort = new Object();
      sort.Key = 'LandmarkName';
      sort.Order = 'Descending';
      var criteria = new Object();
      criteria.Type = 'Landmark';
      criteria.Sort = sort;
      try
      {
        imgid_callback2 = imgId;
        var resultList = so.IDataSource.GetList(criteria, callback2);
        if(!checkError("IDataSource::getListLandmarksAsync",resultList,DIV_ID,imgId))
          showIMG(imgId, "");
      }
      catch(e)
      {
        showIMG(imgId,"no");
        alert ("getListLandmarksAsync: " + e);
      }
    }

    // cancel get categories
    function cancelCategoriesAsync(imgId)
    {
      // Setup input params using dot syntax
      var criteria = new Object();
      criteria.Type = 'Category';
      try
      {
        imgid_callback1 = imgId;
        var resultList = so.IDataSource.GetList(criteria, callback1);
        if(!checkError("IDataSource::cancelCategoriesAsync",resultList,DIV_ID,imgId)) {
          showIMG(imgId, "");
          var criteria2 = new Object();
          criteria2.TransactionID = resultList.TransactionID;
          var resultList2 = so.IDataSource.Cancel(criteria2);
          checkError("IDataSource::cancelCategoriesAsync",resultList2,DIV_ID,imgId);
        }
      }
      catch(e)
      {
        showIMG(imgId,"no");
        alert ("cancelCategoriesAsync: " + e);
      }
    }

    // cancel get landmarks
    function cancelLandmarksAsync(imgId)
    {
      var sort = new Object();
      sort.Key = 'LandmarkName';
      sort.Order = 'Descending';
      var criteria = new Object();
      criteria.Type = 'Landmark';
      criteria.Sort = sort;
      try
      {
        imgid_callback2 = imgId;
        var resultList = so.IDataSource.GetList(criteria, callback2);
        if(!checkError("IDataSource::cancelLandmarksAsync",resultList,DIV_ID,imgId)) {
          showIMG(imgId, "");
          var criteria2 = new Object();
          criteria2.TransactionID = resultList.TransactionID;
          var resultList2 = so.IDataSource.Cancel(criteria2);
          checkError("IDataSource::cancelLandmarksAsync",resultList2,DIV_ID,imgId);
        }
      }
      catch(e)
      {
        showIMG(imgId,"no");
        alert ("cancelLandmarksAsync: " + e);
      }
    }

    // Delete one Category (sync operation)
    function deleteCategory(imgId)
    {
      var landmarkIdStr = prompt("Please type the landmark id", "0");
      if(landmarkIdStr == "" || landmarkIdStr == null)
        return;

      // Setup input params using dot syntax
      var data = new Object();
      data.id = parseInt(landmarkIdStr);
      var criteria = new Object();
      criteria.Type = 'Category';
      criteria.Data = data;
      try
      {
        var resultList = so.IDataSource.Delete(criteria);
        checkError("IDataSource::deleteCategory",resultList,DIV_ID,imgId);
      }
      catch(e)
      {
        showIMG(imgId,"no");
        alert ("deleteCategory: " + e);
      }
    }

    // Delete one Landmark (sync operation)
    function deleteLandmark(imgId)
    {
      var landmarkIdStr = prompt("Please type the landmark id", "0");
      if(landmarkIdStr == "" || landmarkIdStr == null)
        return;

      // Setup input params using dot syntax
      var data = new Object();
      data.id = parseInt(landmarkIdStr);
      var criteria = new Object();
      criteria.Type = 'Landmark';
      criteria.Data = data;
      try
      {
        var resultList = so.IDataSource.Delete(criteria);
        checkError("IDataSource::deleteLandmark",resultList,DIV_ID,imgId);
      }
      catch(e)
      {
        showIMG(imgId,"no");
        alert ("deleteLandmark: " + e);
      }
    }

    // Export specific Landmarks to xml file (sync operation)
    // When we export file already exist it returns an errorCode !!!
    function exportLandmarks(imgId)
    {
      // Setup input params using dot syntax
      var data = new Object();
      data.DestinationFile = 'landmarks-export.xml';
      data.MimeType = 'application/vnd.nokia.landmarkcollection+xml';
      data.IdList = [ "3", "4" ];
      var criteria = new Object();
      criteria.Type = 'Landmark';
      criteria.Data = data;
      try
      {
        var resultList = so.IDataSource.Export(criteria);
        checkError("IDataSource::exportLandmarks",resultList,DIV_ID,imgId);
      }
      catch(e)
      {
        showIMG(imgId,"no");
        alert ("exportLandmarks: " + e);
      }
    }

    // Import Landmarks from xml file (sync operation)
    function importLandmarks(imgId)
    {
      // Setup input params using dot syntax
      var data = new Object();
      data.SourceFile = 'landmarks-export.xml';
      data.MimeType = 'application/vnd.nokia.landmarkcollection+xml';
      var criteria = new Object();
      criteria.Type = 'Landmark';
      criteria.Data = data;
      try
      {
        var resultList = so.IDataSource.Import(criteria);
        checkError("IDataSource::importLandmarks",resultList,DIV_ID,imgId);
      }
      catch(e)
      {
        showIMG(imgId,"no");
        alert ("importLandmarks: " + e);
      }
    }

    // Organise Landmarks with entered ladmark id (sync operation)
    function organiseLandmarks(imgId)
    {
      // Setup input params using dot syntax
      var landmarkIdStr = prompt("Please type the landmark id", "0");
      if(landmarkIdStr == "" || landmarkIdStr == null)
        return;

      var data = new Object();
      data.id = parseInt(landmarkIdStr);
      data.IdList = [ "3", "4" ];
      var criteria = new Object();
      criteria.Type = 'Landmark';
      criteria.Data = data;
      criteria.OperationType = 'Associate';
      try
      {
        var resultList = so.IDataSource.Organise(criteria);
        checkError("IDataSource::organiseLandmarks",resultList,DIV_ID,imgId);
      }
      catch(e)
      {
        showIMG(imgId,"no");
        alert ("organiseLandmarks: " + e);
      }
    }

    // This is the asynchronous callback handler
    function callback1(transId, eventCode, result)
    {
      console.info("callback1: transId: %d  eventCode: %d result.ErrorCode: %d", transId, eventCode, result.ErrorCode);
      if(!checkError("IDataSource::getListCategoriesAsync",result,DIV_ID,imgid_callback1)) {
        document.getElementById(DIV_ID).innerHTML = showIterableList(result.ReturnValue);
      }
    }

    // This is the asynchronous callback handler
    function callback2(transId, eventCode, result)
    {
      console.info("callback2: transId: %d  eventCode: %d result.ErrorCode: %d", transId, eventCode, result.ErrorCode);
      if(!checkError("IDataSource::getListLandmarksAsync",result,DIV_ID,imgid_callback2)) {
        document.getElementById(DIV_ID).innerHTML = showIterableList(result.ReturnValue);
      }
    }