<< Back

Instructions for Completing the Campus Travel Mobile App Project with the Ionic Creator Free Version

In this project you are going to finish a mobile app version of the Campus Travel website like this.

Click for a video on completing this exercise without upgrading to Creator Pro.

We assume you have completed Campus Travel Part 1. Click if you want to complete Part 2 using the Pro version. We begin by exporting the finished user interface to your desktop to finish adding the code.

Exporting Your Mobile App to your Desktop

1. To Export your application to your desktop
  1. Click on the Cloud icon with the down arrow to export your application to your computer as a ZIP file.
  2. Locate your downloaded ZIP file and drag it to your Desktop
  3. Unzip it (by double-clicking on a Mac or right-click Extract All on Windows).
  4. Open the folder. There should be an index.html file, and a templates, lib, js and img folder.
To finish coding your application, you can first edit the following HTML files (found in the templates folder) by adding the Angular directives using a text editor (e.g., TextEdit on a Mac or WordPad/NotePad on Windows).
  1. templates/agentBookings.html
  2. templates/sales.html
  3. templates/addAgent.html
  4. templates/addSale.html
  5. templates/searchSales.html
  6. templates/searchResults.html
  7. templates/updateSale.html
Then you will add code to the following JavaScript files in the js folder.
  1. js/routes.js
  2. js/services.js
  3. js/controllers.js

Add Angular Directives to HTML files

2. addAgent.html
  1. Locate and open addAgent.html in the templates folder.
  2. Add the ng-model="data.agent" Angular directive to the Agent Name Input component
  3. Add the ng-model="data.office" ng-options="office.OfficeID as office.OfficeLocation for office in offices" Angular directives to the Office Select component
  4. Add the ng-click="addAgent()" ng-hide="hideButton" Angular directives to the Button component
  5. Save and Close the file.
3. addSale.html
  1. Locate and open addSale.html in the templates folder.
  2. Add the ng-model="data.agent" ng-options="agent.AgentID as agent.AgentName for agent in agents" Angular directives to the Agent Select component
  3. Add the ng-model="data.saleDate" Angular directive to the Sale Date Input component
  4. Add the ng-model="data.destination" ng-options="destination.DestinationID as destination.DestinationName for destination in destinations" Angular directives to the Destination Select component
  5. Add the ng-model="data.amount" Angular directive to the Amount Input component
  6. Add the ng-click="addSale()" ng-hide="hideButton" Angular directives to the Button component
  7. Save and Close the file.
4. agentBookings.html
  1. Locate and open AgentBookings.html in the templates folder.
  2. Locate the second div row and add ng-repeat="booking in bookings" as an attribute.
  3. Save and Close the file.
5. sales.html
  1. Locate and open sales.html in the templates folder.
  2. Locate the second div row and add ng-repeat="sale in sales" as an attribute.
  3. Save and Close the file.
6. searchResults.html
  1. Locate and open searchResults.html in the templates folder.
  2. Add the ng-repeat="sale in sales" Angular directive to repeat the second div row to display sales records
  3. Add arguments to the campusTravel.updateSale function call in the ui-sref attribute in Button component. The saleId argument is passed as a property in a JSON object: ({"saleId":""+ sale.SaleID +""}).
    Therefore, with HTML encoding, add the parentheses with arguments as shown just after updateSale: campusTravel.updateSale({&quot;saleId&quot;:&quot;&quot;+ sale.SaleID +&quot;&quot;})
  4. Add the ng-click="updateSale()" Angular directive to the Button component
  5. Save and Close the file.
7. searchSales.html
  1. Locate and open searchSales.html in the templates folder.
  2. Add the ng-model="data.agent" ng-options="agent.AgentID as agent.AgentName for agent in agents" Angular directives to the Agent Select component
  3. Add the ng-model="data.destination" ng-options="destination.DestinationID as destination.DestinationName for destination in destinations" Angular directives to the Destination Select component
  4. Add the ng-model="data.above" Angular directive to the Amounts Above Input component
  5. Add the ng-model="data.below" Angular directive to the Amounts Below Input component
  6. Add arguments to the campusTravel.searchResults function call in the ui-sref attribute in the Search Sales Button component. Arguments (AgentKey, DestinationKey, AmountsAbove and AmountsBelow) are passed as properties in a JSON object: ({"agent":""+ data.agent +"","destination":""+ data.destination +"","above":""+ data.above +"","below":""+ data.below +""}).
    Therefore, with HTML encoding, add the parentheses with arguments as shown just after .searchResults: campusTravel.searchResults({&quot;agent&quot;:&quot;&quot;+ data.agent +&quot;&quot;,&quot;destination&quot;:&quot;&quot;+ data.destination +&quot;&quot;,&quot;above&quot;:&quot;&quot;+ data.above +&quot;&quot;,&quot;below&quot;:&quot;&quot;+ data.below +&quot;&quot;})
  7. Add the ng-click="searchSales()" Angular directive to the Button component
  8. Save and Close the file.
8. updateSale.html
  1. Locate and open updateSale.html in the templates folder.
  2. Add the ng-click="deleteSale()" ng-hide="hideDeleteButton" Angular directives to the Delete Button component
  3. Add the ng-hide="hideUpdateForm" Angular directive to the Form tag.
  4. (Also, make sure the paragraph tag above the form contains {{ post.message }}.)
  5. Add the ng-model="data.agentKey" ng-options="agent.AgentID as agent.AgentName for agent in agents" Angular directives to the Agent Select component
  6. Add the ng-model="data.saleDate" Angular directive to the Sale Date Input component
  7. Add the ng-model="data.amount" Angular directive to the Amount Input component
  8. Add the ng-model="data.destinationKey" ng-options="destination.DestinationID as destination.DestinationName for destination in destinations" Angular directives to the Destination Select component
  9. Add the ng-click="updateSale()" ng-hide="hideUpdateButton" Angular directives to the Update Button component
  10. Save and Close the file.

Add Parameter Passing to Page Routing

9. Next, locate and open the routes.js file in the js folder.

Parameters passed from Search Sales to Search Results Page
  1. To declare the parameters passed into the Search Results page, search and find the .state('campusTravel.searchResults' ... specification.
  2. In between the lines that begin with "url: '/page8'," and "views: {", add a new line:
    params: { agent: "0", destination: "0", above: "0", below: "0"},

Parameter passed from Search Results to Update Sale Page
  1. To declare the parameters passed into the Update Sale page, search and find the .state('campusTravel.updateSale' ... specification.
  2. In between the lines that begin with "url: '/page9'," and "views: {", add a new line:
    params: { saleId: "1" },


10. Save and Close routes.js.

Adding Page Controller JavaScript

11. Add Page Controller JavaScript:
Locate and open the js/controllers.js file. The first line of js/controllers.js should be:
angular.module('app.controllers', [])
12. .controller('agentBookingsCtrl' for AgentBookings.html
  1. Locate the line that begins with .controller('agentBookingsCtrl', ['$scope', '$stateParams', and
    add 'GetAgentBookings', (including the comma) just after "'$stateParams',"

  2. Replace line: function ($scope, $stateParams) {
    with 6 lines of code:
    function ($scope, $stateParams, GetAgentBookings) {
      GetAgentBookings.getPost()
      .then(function(response) {
        $scope.post = response;
        $scope.bookings =  $scope.post.records;
      });
13. .controller('salesCtrl' for sales.html
  1. Locate the line that begins with .controller('salesCtrl', ['$scope', '$stateParams', and
    add 'GetSales', (including the comma) just after "'$stateParams',"

  2. Replace line: function ($scope, $stateParams) {
    with 6 lines of code:
    function ($scope, $stateParams, GetSales) {
      GetSales.getPost()
      .then(function(response) {
        $scope.post = response;
        $scope.sales =  $scope.post.records;
      });
14. .controller('addAgent' for addAgent.html
  1. Locate the line that begins with .controller('addAgentCtrl', ['$scope', '$stateParams', and
    add 'GetOffices', 'AddAgent', (including comma) just after "'$stateParams',"

  2. Replace line: function ($scope, $stateParams) {
    with 25 lines of code:
    function ($scope, $stateParams, GetOffices, AddAgent) {
    
      $scope.offices = [];    
    
      $scope.data = {};
    
      $scope.addAgent = function(){
        var agent = $scope.data.agent;
        var office = $scope.data.office;
        $scope.hideButton=true;
    
        AddAgent.getPost(agent, office) 
        .then(function(response) {
          $scope.post = response;
         });
      };
    
      GetOffices.getPost()
      .then(function(response) {
        $scope.post = response;
        $scope.offices =  $scope.post.records;
    	$scope.offices.unshift({ "OfficeID": 0, "OfficeLocation": "--- Select Office Location ---" });
    	$scope.data.office=0;
      });
      
15. .controller('addSaleCtrl' for addSale.html
  1. Locate the line that begins with .controller('addSaleCtrl', ['$scope', '$stateParams', and
    add 'GetAgents', 'GetDestinations', 'AddSale', just after "'$stateParams',"

  2. Replace line: function ($scope, $stateParams) {
    with 42 lines of code:
    function ($scope, $stateParams, GetAgents, GetDestinations, AddSale) {
    
      $scope.destinations = [];    
      $scope.agents = [];    
    
      $scope.data = {};
    
      $scope.addSale = function(){
        var agent = $scope.data.agent;
        var destination = $scope.data.destination;
    
        var s = $scope.data.saleDate;
        var m = s.getMonth()+1;
        var d = s.getDate();
        m = '0'+m; m = m.substr(-2,2);
        d = '0'+d; d = d.substr(-2,2);
        var saleDate = s.getFullYear()+'-'+m+'-'+d;
    
    	var amount = $scope.data.amount;
        $scope.hideButton=true;
    
        AddSale.getPost(agent, saleDate, amount, destination) 
        .then(function(response) {
          $scope.post = response;
         });
      };
    
      GetAgents.getPost()
      .then(function(response) {
        $scope.post = response;
        $scope.agents =  $scope.post.records;
    	$scope.agents.unshift({ "AgentID": 0, "AgentName": "--- Select Agent ---" });
    	$scope.data.agent=0;
      });
    
      GetDestinations.getPost()
      .then(function(response) {
        $scope.post = response;
        $scope.destinations =  $scope.post.records;
    	$scope.destinations.unshift({ "DestinationID": 0, "DestinationName": "--- Select Destination ---" });
    	$scope.data.destination=0;
      });
16. .controller('searchSalesCtrl' for searchSales.html
  1. Locate the line that begins with .controller('searchSalesCtrl', ['$scope', '$stateParams', and
    add 'GetAgents', 'GetDestinations', just after "'$stateParams',"

  2. Replace line: function ($scope, $stateParams) {
    with 22 lines of code:
    function ($scope, $stateParams, GetAgents, GetDestinations) {
    
      $scope.destinations = [];    
      $scope.agents = [];    
    
      $scope.data = {};
    
      GetAgents.getPost()
      .then(function(response) {
        $scope.post = response;
        $scope.agents =  $scope.post.records;
    	$scope.agents.unshift({ "AgentID": 0, "AgentName": "--- Select Agent ---" });
    	$scope.data.agent=0;
      });
    
      GetDestinations.getPost()
      .then(function(response) {
        $scope.post = response;
        $scope.destinations =  $scope.post.records;
    	$scope.destinations.unshift({ "DestinationID": 0, "DestinationName": "--- Select Destination ---" });
    	$scope.data.destination=0;
      });
17. .controller('searchResultsCtrl' for searchResults.html
  1. Locate the line that begins with .controller('searchResultsCtrl', ['$scope', '$stateParams', and
    add 'SearchSales', just after "'$stateParams',"

  2. Replace line: function ($scope, $stateParams) {
    with 22 lines of code:
    function ($scope, $stateParams, SearchSales) {
    
      $scope.data = { 
    	  "agent": $stateParams.agent,
    	  "destination": $stateParams.destination,
    	  "above": $stateParams.above,
    	  "below": $stateParams.below
      };
    
      var criteria = '';
      if($scope.data.agent > 0) criteria += ", AgentID = "+$scope.data.agent;
      if($scope.data.destination > 0) criteria += ", DestinationID = "+$scope.data.destination;
      if($scope.data.above > 0) criteria += ", Amounts Above $"+$scope.data.above;
      if($scope.data.below > 0) criteria += ", Amounts Below $"+$scope.data.below;
    
      $scope.data.criteria = criteria.substr(2);
    
      SearchSales.getPost($scope.data.agent, $scope.data.destination, $scope.data.above, $scope.data.below)
      .then(function(response) {
        $scope.post = response;
        $scope.sales =  $scope.post.records;
      });
18. .controller('updateSaleCtrl' for updateSale.html
  1. Locate the line that begins with
    .controller('updateSaleCtrl', ['$scope', '$stateParams', and
    add 'GetAgents', 'GetDestinations', 'GetSale', 'DeleteSale', 'UpdateSale', just after "'$stateParams',"

  2. Replace line: function ($scope, $stateParams) {
    with 82 lines of code:
    function ($scope, $stateParams, GetAgents, GetDestinations, GetSale, DeleteSale, UpdateSale) {
    
      $scope.destinations = [];    
      $scope.agents = [];
      $scope.sale = {};
    
      $scope.data = { "saleId": $stateParams.saleId };
    
      GetAgents.getPost()
      .then(function(response) {
        $scope.post = response;
        $scope.agents =  $scope.post.records;
      });
    
      GetDestinations.getPost()
      .then(function(response) {
        $scope.post = response;
        $scope.destinations =  $scope.post.records;
      });
    
      var saleId;
      var original_AgentKey;
      var original_SaleDate;
      var original_Amount;
      var original_DestinationKey;
    
    
      GetSale.getPost($scope.data.saleId)
      .then(function(response) {
        $scope.post = response;
        $scope.sale =  $scope.post.records[0];
    	SetVariables();
      });
    
      SetVariables = function(){
        $scope.data.agentName=$scope.sale.AgentName;
        $scope.data.agentKey=$scope.sale.AgentKey;
        $scope.data.destinationKey=$scope.sale.DestinationKey;
        $scope.data.destinationName=$scope.sale.DestinationName;
        $scope.data.saleDate=new Date(parseInt($scope.sale.SaleTime));
        $scope.data.amount=parseFloat($scope.sale.Amount);
        saleId = $scope.sale.SaleID;
        original_AgentKey = $scope.sale.AgentKey;
        original_SaleDate = $scope.sale.SaleDate;
        original_Amount = $scope.sale.Amount;
        original_DestinationKey = $scope.sale.DestinationKey;
      };
    
      $scope.agentChanged = function(){
    	alert("AgentID was changed to "+$scope.data.agent);
      }
    
      $scope.deleteSale = function(){
        if(confirm("Are you sure you want to delete this sale?"))
        {
          $scope.hideDeleteButton=true;
    	  $scope.hideUpdateForm=true;
    
          DeleteSale.getPost(saleId, original_AgentKey, original_SaleDate, original_Amount, original_DestinationKey) 
          .then(function(response) {
            $scope.post = response;
           });
    	}
      };
    
      $scope.updateSale = function(){
    
        var s = $scope.data.saleDate;
        var m = s.getMonth()+1;
        var d = s.getDate();
        m = '0'+m; m = m.substr(-2,2);
        d = '0'+d; d = d.substr(-2,2);
        var saleDate = s.getFullYear()+'-'+m+'-'+d;
    
        UpdateSale.getPost(saleId, original_AgentKey, original_SaleDate, original_Amount, original_DestinationKey, 
          $scope.data.agentKey, saleDate, $scope.data.amount, $scope.data.destinationKey) 
        .then(function(response) {
          $scope.post = response;
          $scope.sale =  $scope.post.SaleRecord;
    	  SetVariables();
         });
      };
19. Save and Close controllers.js.

Adding API Services JavaScript

20. Locate and open the js/services.js folder. The first line of services.js should be: angular.module('app.services', [])

Note that you will not be further testing your app on the Ionic Creator platform or hosting your app on a secure server host.

Therefore it is not necessary that your APIs are accessed through a secure server.

Just after the first line, insert the following 211 lines of code:
.service('GetAgentBookings', function($http) {
  return {
    getPost: function() {
      var columns="AgentName, OfficeLocation, SUM(1) AS NumSales, SUM(IF(Amount IS NOT NULL,Amount,0)) AS Total";
      var table=encodeURIComponent("AGENT LEFT JOIN SALE ON AgentKey=AgentID LEFT JOIN OFFICE ON OfficeKey=OfficeID");
      var group="AgentID";
      var order="Total DESC";
      var query = '?columns='+columns;
      query += '&table='+table;
      query += '&group='+group;
      query += '&order='+order;

      return $http.get('http://secrdir.com/campus/ionic/list.php'+query)
      .then(function (response) {
        return response.data;
      });
    }
  };
})

.service('GetSales', function($http) {
  return {
    getPost: function() {
      var columns = "SaleID, SaleDate, UNIX_TIMESTAMP(SaleDate)*1000 AS SaleTime, AgentKey, Amount, DestinationKey";
	  columns += ", AgentName, OfficeKey, OfficeLocation, DestinationName";
	  var tab = "SALE INNER JOIN AGENT ON AgentKey=AgentID INNER JOIN OFFICE ON OfficeKey=OfficeID ";
	  tab += " INNER JOIN DESTINATION ON DestinationKey=DestinationID";
      var table = encodeURIComponent(tab);
      var order="SaleID DESC";

      var query = '?columns='+columns;
      query += '&table='+table;
      query += '&order='+order;

      return $http.get('http://secrdir.com/campus/ionic/list.php'+query)
      .then(function (response) {
        return response.data;
      });
    }
  };
})

.service('GetOffices', function($http) {
  return {
    getPost: function() {

      var query = '?table=OFFICE&order=OfficeLocation';

      return $http.get('http://secrdir.com/campus/ionic/list.php'+query)
      .then(function (response) {
        return response.data;
      });
    }
  };
})

.service('GetAgents', function($http) {
  return {
    getPost: function() {

      var query = '?table=AGENT&order=AgentName';

      return $http.get('http://secrdir.com/campus/ionic/list.php'+query)
      .then(function (response) {
        return response.data;
      });
    }
  };
})

.service('GetDestinations', function($http) {
  return {
    getPost: function() {

      var query = '?table=DESTINATION&order=DestinationName';

      return $http.get('http://secrdir.com/campus/ionic/list.php'+query)
      .then(function (response) {
        return response.data;
      });
    }
  };
})

.service('AddAgent', function($http) {
  return {
    getPost: function(agent,office) {
      var query = '?AgentName='+agent;
      query += '&OfficeKey='+office;
      return $http.get('http://secrdir.com/campus/ionic/add_agent.php'+query)
      .then(function (response) {
        return response.data;
      });
    }
  };
})

.service('AddSale', function($http) {
  return {
    getPost: function(agent,saleDate,amount,destination) {
      var query = '?AgentKey='+agent;
      query += '&DestinationKey='+destination;
      query += '&Amount='+amount;
      query += '&SaleDate='+saleDate;
      return $http.get('http://secrdir.com/campus/ionic/add_sale.php'+query)
      .then(function (response) {
        return response.data;
      });
    }
  };
})

.service('SearchSales', function($http) {
  return {
    getPost: function(agent, destination, amountsAbove, amountsBelow) {
      var columns = "SaleID, SaleDate, UNIX_TIMESTAMP(SaleDate)*1000 AS SaleTime, AgentKey, Amount, DestinationKey";
	  columns += ", AgentName, OfficeKey, OfficeLocation, DestinationName";
	  var tab = "SALE INNER JOIN AGENT ON AgentKey=AgentID INNER JOIN OFFICE ON OfficeKey=OfficeID ";
	  tab += " INNER JOIN DESTINATION ON DestinationKey=DestinationID";
      var table = encodeURIComponent(tab);
      var order="SaleID DESC";
      var query = '?columns='+columns;
      query += '&table='+table;
      query += '&order='+order;

	  var where = "";
	  if(agent > 0 ) { where += " AND AgentKey="+agent ; }
	  if(destination > 0 ) { where += " AND DestinationKey="+destination ; }
	  if(amountsAbove > 0 ) { where += " AND Amount>='"+amountsAbove+"'" ; }
	  if(amountsBelow > 0 ) { where += " AND Amount<='"+amountsBelow+"'" ; }
	  if(where>'') {
		  where = where.substr(4) ;
		  where=encodeURIComponent(where);
		  query += '&where='+where ;
      }
      return $http.get('http://secrdir.com/campus/ionic/list.php'+query)
      .then(function (response) {
        return response.data;
      });
    }
  };
})

.service('GetSale', function($http) {
  return {
    getPost: function(saleId) {
      var columns = "SaleID, SaleDate, UNIX_TIMESTAMP(SaleDate)*1000 AS SaleTime, AgentKey, Amount, DestinationKey";
	  columns += ", AgentName, OfficeKey, OfficeLocation, DestinationName";
	  var tab = "SALE INNER JOIN AGENT ON AgentKey=AgentID INNER JOIN OFFICE ON OfficeKey=OfficeID ";
	  tab += " INNER JOIN DESTINATION ON DestinationKey=DestinationID";
      var table = encodeURIComponent(tab);
      var query = '?columns='+columns;
      query += '&table='+table;
      query += '&where='+encodeURIComponent("SaleID=" + saleId);

      return $http.get('http://secrdir.com/campus/ionic/list.php'+query)
      .then(function (response) {
        return response.data;
      });
    }
  };
})


.service('DeleteSale', function($http) {
  return {
    getPost: function(saleId, originalAgent, originalSaleDate, originalAmount, originalDestination) {
      var query = '?SaleID='+saleId;
      query += '&Original_AgentKey='+originalAgent;
      query += '&Original_DestinationKey='+originalDestination;
      query += '&Original_Amount='+originalAmount;
      query += '&Original_SaleDate='+originalSaleDate;

	  return $http.get('http://secrdir.com/campus/ionic/delete_sale.php'+query)
      .then(function (response) {
        return response.data;
      });
    }
  };
})


.service('UpdateSale', function($http) {
  return {
    getPost: function(saleId, originalAgent, originalSaleDate, originalAmount, originalDestination, 
		agent, saleDate, amount, destination) {
      var query = '?SaleID='+saleId;
      query += '&Original_AgentKey='+originalAgent;
      query += '&Original_DestinationKey='+originalDestination;
      query += '&Original_Amount='+originalAmount;
      query += '&Original_SaleDate='+originalSaleDate;
	  var changes = 0;
      if(agent != originalAgent) { query += '&AgentKey='+agent; changes += 1; }
      if(destination != originalDestination) { query += '&DestinationKey='+destination; changes += 1; }
      if(amount != originalAmount) { query += '&Amount='+amount; changes += 1; }
      if(saleDate != originalSaleDate) { query += '&SaleDate='+saleDate; changes += 1; }
	  if( changes == 0 )
      {
        var message = { "message" : "Nothing to update" };
        return message;
      }
      else
      {
		  return $http.get('http://secrdir.com/campus/ionic/update_sale.php'+query)
		  .then(function (response) {
			return response.data;
		  });
	  }
    }
  };
})
21. Change every occurrence of http://secrdir.com/campus/ionic/ in the services.js file to the URL path to your APIs.
22. Save and Close services.js.

Exporting Your Mobile App to your Website

23. To export your app to your server,
  1. Select the four folders and index.html file (img, js, lib, templates and index.html) from inside the campusTravel folder that you downloaded.
  2. Right click and choose Send to > Compressed (zipped) folder.
  3. Open your cPanel on your web server.
  4. In the File Manager, create a new folder in the public_html directory named ct (for Campus Travel).
  5. Open the ct folder. Upload the zipped folder of your app into the ct folder on your server.
  6. Select the zipped file, right click and unzip the file.
  7. Test your app by going to the /ct/ directory of your website on your browser or mobile device.
  8. If your site is blank, the access permissions of the lib folder might not have been initialized correctly. To make sure,
    1. In your /ct/ directory, create a new file named chmod.php.
    2. Enter the following line: <?php shell_exec('chmod -R 755 lib'); ?>
    3. Save the file. Execute by going to /ct/chmod.php
  9. Use the Developer's Web Console of your browser to track down errors you may have.


Richard Halverson, Jr., Ph.D. • University of Hawaii