Portfolio

Carl James Trelfa

JavaScript App

This is where I will show off some JavaScripting skills.

The mini-app below is built using JQuery and later updated to also use Angular (scroll to the bottom of the page to see the changes). It's a simple database explorer that allows you to add new data and browse existing records.

In total I spent about a day making this version. I've barely scratched the surface of what's possible - we could really juice up our app with some effects!

For a few examples of the possibilities visit: https://www.w3schools.com/howto/default.asp

CodeIgniter

A quick update to the app - I've updated the back-end to use CodeIgniter (which is why the CodeIgniter link leads to this page for now).

What can I say? I like it, it was really easy to get up and running and it has so many nice functions, I'm going to use it for a full update of the site.

At some point I'm going to make a react version of this app. I've started already and again I'm thinking of re-doing the whole site with it, so CodeIgniter for the back-end stuff (I'll use it like a rest API) and React to build the actual pages using JSX and AJAX calls to fetch the data from the back-end, basically more like a web-app.

React and Angular

OK, I decided to create a different app with React, so make sure you check out the React Gallery App and also the Angular Gallery App.

Watch this space for updates.

Styling

I'm not too worried about styling here, I just want to concentrate on using JavaScript. I've chosen grey (I know, it's a bit boring) because it helps to differentiate the app from the rest of the site without clashing.

One point to note is that I used a re-styled html list for the navigation this time, instead of the inline-divs I used on the main navigation. It's a much better way, maybe I'll update the other navigation at some point.

How It Works

There's two parts to our JS App, a client part written using JavaScript and a PHP part on the server. This is a simple demo app for testing out JQuery and Angular, if you were building a more complex app, you might re-think the architecture a bit.

Client Side JavaScript/JQuery

The first part I worked on was switching between the apps main views. This is really simple with JQuery.

The main app views are just divs that are hidden and shown as we need them. I have a couple of classes in my CSS that I use and with JQuery I simply use the following JS to switch views:

Main App Nav

// add a click handler to our nav buttons
$("#home-button").click( function() { switchView("home"); } );
$("#browsedata-button").click( function() { switchView("browsedata"); } );
// ... there is more for the other nav buttons

function switchView(nextView) {
    $("#"+currentView+"-view").hide();
    $("#"+nextView+"-view").show();
    currentView = nextView;
    updateNav();
}

function updateNav() {
    for (i = 0; i < allViews.length; i++) {
        if (allViews[i] == currentView) {
            $("#"+allViews[i]+"-button").addClass("activeAngularAppNav");
        } else {
            $("#"+allViews[i]+"-button").removeClass("activeAngularAppNav");
        }
    }
}

As you can see I'm just using JQuery's hide, show, addClass and removeClass functions to update the view and the nav when you click the main app navigation buttons.

Each view also has some sub views, like when you submit data there are two sub views - the form and the success message. Switching between them is the same principle as switching the main view.

Server Side PHP

I've kept the php code quite simple - it only has two functions, insert a record and retrieve a record. It's nothing compared to the depth and complexity of the Facebook Framework API I made and used for Prizechinko (code available on request)

If you know anything about PHP code you should be able to figure this out:

PHP App Code

<?php
    // Handle the db app requests
    // I want to keep the code short and simple
    $returnData = new stdClass();
    $returnData->{'s'} = "fail";
   
    // validate input
    $ops = ["retrieve", "insert"];
    $op = $ops[0];

    // form is already validated by the client so we don't need to do too much here
    if (isset($_POST['o']) && in_array($_POST['o'], $ops)) {
        // valid operation
        $op = $_POST['o'];
        $validData = false;
        switch ($op) {
            case $ops[0]:
                // retrieve
                if (isset($_POST['r']) && !empty($_POST['r'])) {
                    $validData = true;
                    $recordToFetch = $_POST['r'];
                }
                break;
            case $ops[1]:
                // insert
                if (isset($_POST['n']) && !empty($_POST['n'])
                    && isset($_POST['d']) && !empty($_POST['d'])
                    && isset($_POST['num']) && !empty($_POST['num'])
                    && (isset($_POST['i']) && ($_POST['i'] === "0" || $_POST['i'] === "1"))
                    ) {
                        $validData = true;
                        $rec_name = $_POST['n'];
                        $rec_description = $_POST['d'];
                        $rec_num = $_POST['num'];
                        $rec_i = $_POST['i'];
                }
                break;
        }
       
        if ($validData) {
            // connect to db
            require "../libs/MySQLAccess.php";
            $ourDB = new MySQLAccess();
            $ourDB->init($dbhostname, $dbusername, $dbpassword, $dbname);
           
            // run the query an update our return data
            switch ($op) {
                case $ops[0]:
                    // retrieve
                    // I should update this to use a COUNT MySQL query...
                    // I guess it's OK for a small table
                    $mysqlQuery = "SELECT `recordname`, `recorddescription`, `somenumber`, `important` FROM `jsdemoappdata`";
                    $queryLimitPart = " LIMIT ".($recordToFetch - 1).",1";
                    $result = $ourDB->executeQuery($mysqlQuery);
                    if ($result) {
                        $total = $result->num_rows;
                        $ourDB->freeResult($result);
                    }
                    $result = $ourDB->executeQuery($mysqlQuery.$queryLimitPart);
                    if ($result) {
                        $row = $ourDB->fetchNextRow($result);
                        if ($row) {
                            $returnData->{'n'} = $row['recordname'];
                            $returnData->{'d'} = $row['recorddescription'];
                            $returnData->{'num'} = $row['somenumber'];
                            $returnData->{'i'} = $row['important'];
                            $returnData->{'r'} = $recordToFetch;
                            $returnData->{'t'} = $total;
                            $returnData->{'s'} = "success";
                        }
                        $ourDB->freeResult($result);
                    }
                    break;
                case $ops[1]:
                    // insert
                    $mysqlQuery = "INSERT INTO `jsdemoappdata` (`recordname`, `recorddescription`, `somenumber`, `important`) VALUES ('".$ourDB->escapeString($rec_name)."', '".$ourDB->escapeString($rec_description)."', '".$ourDB->escapeString($rec_num)."', '".$ourDB->escapeString($rec_i)."')";
                    $result = $ourDB->executeQuery($mysqlQuery);
                    if ($result) {
                        $returnData->{'n'} = $rec_name;
                        $returnData->{'d'} = $rec_description;
                        $returnData->{'num'} = $rec_num;
                        $returnData->{'i'} = $rec_i;
                        $returnData->{'s'} = "success";
                    }
                    break;
            }
        }
    }
  
    // output a json object
    echo  json_encode($returnData);
?>

Pretty straight forward - you post the right data to it and it does it's thing.

CodeIgniter

A small addition - the api now uses CodeIgniter. The actual logic is almost identical, so I won't put up a load of repeated code, just an overview.

So all I needed for the switch to CodeIgniter was one class file called Db with fetch and post methods. To fetch a record you can go to: http://cjtportfolio.ish-games.com/cidb_api/index.php/Db/fetch/9 and see the JSON object that gets returned. I've kept the property names as single letters on the JSON object to minimise the amount of data transferred.

Then I've just updated the url used by the AJAX calls in the JavaScript. I was thinking of using .htaccess to tweak the url of that so it's a bit more friendly, but maybe I'll do that another time.

There's loads of cool stuff you can do with CodeIgniter, I'll definitely be using it again!

AJAX

AJAX is a method where JavaScript can communicate with the server in the background, so we don't need to refresh the whole page - just the bit we need to update.

I'm using AJAX to POST data to my PHP script which then carries out the requested task and outputs a response that I can interpret with JavaScript.

Retrieving a Record

// vars for the last data we received
var rec_name = "";
var rec_description = "";
var rec_num = 0;
var rec_i = 0;
var rec_total = 0;
var rec_current = 0;

function fetchRecord() {
    showFetchingDataView();
    if (rec_current === 0) {
        rec_current = 1;
    }
    dataToSend = {
        o: "retrieve",
        r: rec_current
    };
    $.post("jsappapi/index.php", dataToSend,
            function(data, status){
                data = JSON.parse(data);
                if (status == "success" && data.s == "success") {
                    rec_name = data.n;
                    rec_description = data.d;
                    rec_num = data.num;
                    rec_i = data.i;
                    rec_current = data.r;
                    rec_total = data.t;
                    showFetchingSuccessView();
                } else {
                    showFetchingErrorView();
                }
            });
}

If you wanted to do it "properly" you should use a GET request for retrieving and a POST for sending data. A POST works fine for us here, so I'm going to stick with it for now.

The problem with JQuery is that now to display the data I need code like this:

Displaying a Record

function showSendingSuccessView() {
    $("#sendingerror-view").hide();
    $("#sendingsuccess-view").show();
    $("#addrecord-form").hide();
   
    // display the record - I could eliminate this code by using Angular
    $("#inserted_rec_name").text(rec_name);
    $("#inserted_rec_description").text(rec_description);
    $("#inserted_rec_num").text(rec_num);
    if (rec_i == "0") {
      $("#inserted_rec_i").text("No");
    } else {
      $("#inserted_rec_i").text("Yes");     
    }
}

The code does also do some form validation and I've not covered inserting records, partly because the code is very similar. Feel free to take a look at the JS file to find out how these parts work.

Angular JS

I've updated the app to make use of Angular JS. I've used data-binding and switched the AJAX code to use Angular instead. I had to make some minor changes to the php code because Angular submits it's data differently (by default).

The first step was to add an ng-app attribute to my app's div:

Defining Your App

<div data-ng-app="myApp" data-ng-controller="myCtrl">

Then we need to initialise our controller for the app:

Angular App Controller

var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, $http) {
      $scope.rec_name = "";
      $scope.rec_description = "";
      $scope.rec_num = 0;
      $scope.rec_i = "No";
      $scope.rec_total = 0;
      $scope.rec_current = 0;
      
      // fetch our record
      $scope.fetchRecord = function() {
            var dataToSend = {
                  o: "retrieve",
                  r: $scope.rec_current
            };
            $http.post("jsappapi/index.php", dataToSend)
                  .then(function (response) {
                              // success callback
                              if (response.data.s == "success") {
                                    $scope.rec_name = response.data.n;
                                    $scope.rec_description = response.data.d;
                                    $scope.rec_num = response.data.num;
                                    if (response.data.i == "0") {
                                          $scope.rec_i = "No";
                                    } else {
                                          $scope.rec_i = "Yes";
                                    }
                                    $scope.rec_current = response.data.r;
                                    $scope.rec_total = response.data.t;
                                    showFetchingSuccessView();
                              } else {
                                    showFetchingErrorView();
                              }
                        },
                        function () {
                              // failure callback
                              showFetchingErrorView();
                        }
                  );
      };
      
      // There is some code here for inserting records as well,
      // it's very similar to fetching

      // show the browse data view
      $scope.browseData = function() {
            switchView("browsedata");
            $scope.viewNextPrevRecord(0);
      };
      
      // go up or down a record (dir should be 0, -1 or +1)
      $scope.viewNextPrevRecord = function(dir) {
            if ($scope.rec_current === 0) {
                  $scope.rec_current = 1;
            } else {
                  $scope.rec_current += dir;
                  if ($scope.rec_current < 1) {
                        $scope.rec_current = $scope.rec_total;
                  } else
                  if ($scope.rec_current > $scope.rec_total) {
                        $scope.rec_current = 1;
                  }
            }
            showFetchingDataView();
            $scope.fetchRecord();
      };
});

The main thing to note is that my vars for the last record have now moved in to our controller. This will allow us to do data-binding, so we don't need to manually update our views when the data changes.

I've also switched the AJAX to use $http from Angular and there are a couple of buttons where the clicks are now handled by Angular.

Angular Data Binding

<div id="fetchingsuccess-view">
    <h3>Data was successfully fetched!</h3>
    <p>Name: <span class="bold-text" data-ng-bind="rec_name"></span></p>
    <p>Description: <span class="bold-text" data-ng-bind="rec_description"></span></p>
    <p>Fave Number: <span class="bold-text" data-ng-bind="rec_num"></span></p>
    <p>Important: <span class="bold-text" data-ng-bind="rec_i"></span></p>
    <p>Record <span class="bold-text" data-ng-bind="rec_current"></span> of <span class="bold-text" data-ng-bind="rec_total"></span></p>
    <button class="appButton" data-ng-click="viewNextPrevRecord(-1)">Prev Record</button><button class="appButton" data-ng-click="viewNextPrevRecord(1)">Next Record</button>
</div>

Those ng-bind attributes mean Angular will now automatically update our view.

I've also used ng-click to add click handlers to the Next Record and Prev Record buttons using Angular (I've also used Angular to handle clicking the Browse Data button on the Main Nav). The reason is that I need to use Angular to communicate with our server so we can properly use Data Binding, so any buttons that do more than just switching views now use Angular.

The old JQuery "Display Record" code now just does this:

Displaying a Record

function showSendingSuccessView() {
    $("#sendingerror-view").hide();
    $("#sendingsuccess-view").show();
    $("#addrecord-form").hide();
}

Overall my JS code and HTML are more streamlined using Angular.

Home > Technical Skills > JavaScript