Note, this article is part of series (see here). In our last installment we introduced our application's user interface (UI) and the subject of, user experience (UX). We identified "must have" functions and started our implementation.

In this installment we continue to focus on implementing our "must have" UI/UX functions. Thus we are adding the following:

The above are public functions, functions the user invokes. To implement the above functions, we also require additional internal infra structure functions. For example, in prior articles we defined the following business rules:

The following method

In our last commit, we added an internal entity that serves as a collection of row_columns. We call that collection of row_columns a "grid". Logically the grid represents our resume document. The grid provides the resume document's public properties and methods. That also means the "grid" is going to be composed of some of our other infra structure entities. Thus, I've added an instance of "columnList" and "rowList" to our grid.

Our grid now contains 3 collections, a columnList, a rowList and a list of row_columns (AKA cells).

Our grid can now count we the number of columns in each row. Here is our implementation:

    /** Check to see if we this row is empty **/
    this.getNumColumnsInRow=function(row_id) {
	var len = this.list.length;
	var elem = null;
	var count = 0;
	for (var nIndex=0; nIndex < len; nIndex++) {
            elem = this.list[nIndex];
            if (elem.getRowId() == row_id) {
        return count;

But wait, we are not done. If we delete a row at the top of the document, that effects all the rows below it. For example, we have 10 rows. The location property of the bottom row is 10. 10 is how the user identifies the bottom (AKA last) row. If we delete row 1 that means row 10 is now row 9. The last row now has a location value of 9. Thus, when we delete a row, we need to adjust the "location" properties of the remaining rows. The following method is our implementation:

 /** Delete a row entity from this row_list instance.
    *   Moves the location values of all rows below the deleted row.
    * */
    this.deleteRow=function(row_id) {
        var row_position = null;
        var row_column = null;
        var row  = null;
        var column = null;
        var row_column_delete_list = [];
        var column_delete_list = [];
        var len = this.list.length;
        for (var nIndex= 0; nIndex < len; nIndex++) {
            row_column = this.list[nIndex];
            if (row_column && (row_column.getRowId() == row_id)) {
        len = row_column_delete_list.length;
        for (var nIndex=0; nIndex < len; nIndex++) {
            row_column = row_column_delete_list[nIndex];
        len = column_delete_list.length;
        for (var nIndex=0; nIndex < len; nIndex++) {
            column = column_delete_list[nIndex];
            if (this.getNumColumnReferences(column) === 0){
        row = this.rowList.getRow(row_id);
        row_position = row.getLocation();
        // finally renumber the location values
        len = this.list.length;
        var location = null;
        for (var nIndex=0; nIndex < len; nIndex++){
            row_column = this.list[nIndex];
            row = this.rowList.getRow(row_column.getRowId());
            if (row.getLocation() > row_position) {
                location = row.getLocation();
                if (location > 0) {
                    location = location -1;

Why are we looking at the application through a microscope. What is the point?
Well, when you are part of an organization you need to explain the time duration required to implement a function. Often, when implementing details, you discover additional requirements. The additional requirements mean additional analysis testing ,etc.

You can always structure a document so folks who are in different organizational rows can focus or ignore certain sections of your document. For example an "Executive Summary" section.

Besides, terms like "micro" are subjective terms.

Truth be told, as I wrote the above micro-description, it forced me to verify I was indeed deleting empty rows. I actually discovered I had a defect, I was not deleting the row itself. The application worked from the user's perspective, but internally the application was storing unnecessary information. When you deploy a JavaScript application on a mobile device that type of micro-defect is magnified. On a full size desktop web browser, hanging on to a few unused rows is unlikely to adversely effect performance (and ultimately functionality). On a mobile device, we don't have that same luxury.

The process of documenting, implementing and testing are closely connected. My example is actually typical. While documenting I discovered a defect in my test plan and my code implementing. You may also find your documentation contains defects when you are testing or implementing code.

I've committed all the new code to my Git Hub repository here.

If you study the commit, you'll see I made one additional change. I decided to simply use the Twitter Bootstrap Front-end framework's built-in drop-menu facility, rather than roll my own. My rational is, our published resumes do not include the application's menu. Thus, leveraging Bootstrap's working menu facility expedites our immediate goal of getting to a demonstration release of our project. I made an executive decision, the application menu is not a "must have" for our learning experience. At least not for this particular project.

About the Author:
Lorin M Klugman is an experienced developer focused on new technology.
Open for work (contract or hire).
Drop Lorin a note. Click here for address.
Please no recruiters :)
- Home