ProxyJS – A JavaScript Proxy Library

What’s A Proxy

My JavaScript-centric and simplified definition of proxy is: “it’s an object that functions as an interface to another function or method”. To act as an interface to another functions, a proxy wraps that function and intercepts all the calls that are made to it. This ability to intercept calls made to the wrapped function allows a proxy to spy on it.

Proxies Are Spies

For example, suppose you have to integrate a library into an application that you are building out and that library’s documentation isn’t all that clear. Ideally you would like to spy each call made to one or more of that library’s methods and record the arguments they are passed and what they return. In fact, that is exactly what we are going to focus on and build out in this tutorial, using proxy as a spy to gleam information about the functions they are wrapping.

Building A Small Proxy Library

The approach I will take to implementing proxy relies on the fact that in JavaScript functions are themselves objects and as such they can have their own member properties. We will see how this plays out in the examples as proxy gets incrementally built out in three stages:

  1. An infrastructure
  2. Recording information
  3. API

Identifying Requirements

Everything worth building deserves to have its requirements identified before a single line of code is written and is the case for ProxyJS, the proxy library that we will build here. So, simply stated, proxy must:

  1. Maintain a count of how many times the proxy was called.
  2. Record the arguments that are passed to it every time the proxy was called.
  3. Call the wrapped function using its intended context (the intended “this”) passing it the arguments that proxy itself was called with.
  4. Record what the wrapped function returns.
  5. Return what the wrapped function returns to the caller.
  6. Provide an API which allows retrieving the information that has been recorded.

Infrastructure Implementation

First, A naive Infrastructure Implementation

Lets first begin with what is admittedly a naive infrastructure implementation and create a function named unsurprisingly “proxy”. At first we’ll have it take a single argument, the function that is to be wrapped:


function proxy(fnArg){}

At this point a naive implementation of a suitable wrapper mechanism might appear to be


function proxy(fnArg){
    fnArg();
}

but this falls far short of our requirement as it really just provides one more additional level of indirection between the caller and the wrapped function. We need to build out an infrastructure that will support all our requirements as was laid out above.

Stage 1 – Infrastructure

To provide an API proxy’s implementation will require property methods which will be applied to the function that proxy returns to the caller. A note of caution, though, we have to safeguard that the function returned to the caller is isolated from other functions that are returned. In order to provide isolation we will use a modular pattern in combination with a factory method which is responsible for creating scope and closure around the function that is returned to the caller.


function proxy(){

    var proxyFactory = function(fnArg){

        var fnToCall = fnArg;
        var fn = function(){
            fnToCall();
        };
        return fn;
    };

    return proxyFactory(arguments[0]);

}

var targetFn = function(string){
    console.log("targetFn called with " + string + " and with conext of " + this);
};

var prxyFn = proxy(targetFn);
prxyFn("Somewhere over the rainbow");

We can now use proxy to call the wrapped function but when we run the above (in Chrome developer tools, for instance) we can immediately see that there is a problem – we haven’t accounted for the fact that the function we are wrapping might be called with arguments. The argument that we passed when we called prxyFn(“Somewhere over the rainbow”) was never passed to the wrapped function – it logs to the console “targetFn called with [object window]” (Note: if you use strict mode it will output “targetFn called with undefined”). In addition to not passing the arguments to the wrapped function, we also haven’t provided the ability to call the wrapped function with the intended context – the value of its “this”. Our implementation must allow for both of these, calling the wrapped function with all the arguments that were passed to it and calling it with the correct context.


function proxy(){

    var proxyFactory = function(fnArg){

        var fnToCall = fnArg;
        var fn = function(){
            var args = [].slice.call(arguments);
            fnToCall.apply(this, args);
        };
        return fn;
    };

    return proxyFactory(arguments[0]);

}

var targetFn = function(string){
    console.log("targetFn called with " + string + " and with conext of " + this);
};

var prxyFn = proxy(targetFn);
prxyFn("Somewhere over the rainbow");

Now, when we run the above in the console, we can see that the argument was passed to the wrapped function and that we also called the wrapped function with the intended context, which in this case happens to be the global window context since we are proxying a mere function. But what if we wanted to proxy a method of an object instead, and to be able to call that method directly on the object so that its calling context is correct? The next implementation addresses those concerns.


function proxy(){

    var proxyFactory = function(){

        var fnToCall = arguments.length === 2 ? arguments[0][arguments[1]] : arguments[0];
        var fn = function(){
            var args = [].slice.call(arguments);
            fnToCall.apply(this, args);
        };
        if(arguments.length === 2){
            arguments[0][arguments[1]] = fn;
        }
        return fn;
    };

    var args = [].slice.call(arguments);
    return proxyFactory.apply(null, args);

}

var targetFn = function(string){
    console.log("targetFn called with " + string + " and with conext of " + this);
};

var prxyFn = proxy(targetFn);
prxyFn("Somewhere over the rainbow");

var someObject = {
    targetFn: function(string){
        console.log("targetFn called with " + string + " and with conext of " + this);
    }
};
prxyFn = proxy(someObject, "targetFn");
someObject.targetFn("Somewhere over the rainbow");

With the above we have provided proxy the ability to not only wrap functions but also object property methods. Being able to proxy object property methods means that we can call those property methods through their objects and by doing so maintain the correct context of the method calls. When we run this code in the console we can see that both the function and the property methods were both called with arguments and both were also called with the correct context.

Stage 2 – Recording Information

With proxy’s infrastructure now in place lets turn our attention to the information we wish to record, namely maintaining a count of how many times proxy was called, the arguments that are passed to it and what it returned.


function proxy(){

    var proxyFactory = function(){

        var fnToCall = arguments.length === 2 ? arguments[0][arguments[1]] : arguments[0];
        //A counter used to note how many times proxy has been called.
        var xCalled = 0;
        //An array of arrays used to note the arguments that were passed to proxy.
        var argsPassed = [];
        //An array whose elements note what the wrapped function returned.
        var returned = [];
        var fn = function(){
            //Note the arguments that were passed for this invocation.
            var args = [].slice.call(arguments);
            argsPassed.push(args.length ? args : []);
            //Increment the called count for this invocation.
            xCalled += 1;
            //Call the wrapped function noting what it returns.
            var ret = fnToCall.apply(this, args);
            returned.push(ret);
            //Return what the wrapped function returned to the caller.
            return ret;
        };
        if(arguments.length === 2){
            arguments[0][arguments[1]] = fn;
        }
        return fn;
    };

    var args = [].slice.call(arguments);
    return proxyFactory.apply(null, args);

}

var targetFn = function(string){
    console.log("targetFn called with " + string + " and with conext of " + this);
    return string;
};
var prxyFn1 = proxy(targetFn);
prxyFn1("Somewhere over the rainbow");

var someObject = {
    targetFn: function(string){
        console.log("targetFn called with " + string + " and with conext of " + this);
        return string;
    }
};
prxyFn2 = proxy(someObject, "targetFn");
someObject.targetFn("Somewhere over the rainbow");

If we run the above and step through it with the debugger we can confirm that the code is indeed recording the information accurately. All that’s missing now is an API that will provide access to all that good information that proxy is accumulating for us.

Stage 3 – API

The API takes advantage of the fact that JavaScript functions are themselves first class objects. Therefore, each API method is implemented as a privileged function and is exposed to the caller as properties of the proxy object itself. This way if the user inadvertently assigns something to them it wont affect any other instances of proxy.


function proxy(){

    var proxyFactory = function(){

        //The wrapped function to call.
        var fnToCall = arguments.length === 2 ? arguments[0][arguments[1]] : arguments[0];

        //A counter used to note how many times proxy has been called.
        var xCalled = 0;

        //An array of arrays used to note the arguments that were passed to proxy.
        var argsPassed = [];

        //An array whose elements note what the wrapped function returned.
        var returned = [];

        ///
        ///Privileged functions used by API
        ///

        //Returns the number of times the wrapped function was called.
        var getCalledCount = function(){
            return xCalled;
        };

        //If called with 'n' and 'n' is within bounds then returns the
        //array found at argsPassed[n], otherwise returns argsPassed.
        var getArgsPassed = function(){
            if(arguments.length === 1 && arguments[0] >= 0 && arguments[0] < argsPassed.length){
                return argsPassed[arguments[0]];
            }else{
                return argsPassed;
            }
        };

        //If called with 'n' and 'n' is within bounds then returns
        //value found at returned[n], otherwise returns returned.
        var getReturned = function(){
            if(arguments.length === 1 && arguments[0] >= 0 && arguments[0] < returned.length){
                return returned[arguments[0]];
            }else{
                return returned;
            }
        };

        //If 'n' is within bounds then returns an
        //info object, otherwsie returns undefined.
        var getData= function(n){
            if(n >= 0 && n < xCalled){
                var args = getArgsPassed(n);
                var ret = getReturned(n);
                var info = {
                    count: n + 1,
                    argsPassed: args,
                    returned: ret
                };
                return info;
            }
        };

        //A higher order function - iterates through the collected data and
        //returns the information collected for each invocation of proxy.
        var dataIterator = function(callback){
            for(var i = 0; i < xCalled; i++){
                callback(getData(i));
            }
        };

        //The function that is returned to the caller.
        var fn = function(){
            //Note the arguments that were passed for this invocation.
            var args = [].slice.call(arguments);
            argsPassed.push(args.length ? args : []);
            //Increment the called count for this invocation.
            xCalled += 1;
            //Call the wrapped function noting what it returns.
            var ret = fnToCall.apply(this, args);
            returned.push(ret);
            //Return what the wrapped function returned to the caller.
            return ret;
        };

        ///
        ///Exposed Lovwer level API - see Privileged functions used by API above.
        ///

        fn.getCalledCount = getCalledCount;

        fn.getArgsPassed = getArgsPassed;

        fn.getReturned = getReturned;

        fn.getData = getData;

        ///Exposed Higher Order API - see Privileged functions used by API above.
        fn.dataIterator = dataIterator;

        ///Replaces object's method property with proxy's fn.
        if(arguments.length === 2){
            arguments[0][arguments[1]] = fn;
        }

        //Return fn to the caller.
        return fn;
    };

    //Convert arguments to an array, call factory and returns its value to the caller.
    var args = [].slice.call(arguments);
    return proxyFactory.apply(null, args);

}

var targetFn = function(string){
    console.log("targetFn called with " + string + " and with conext of " + this);
    return string;
};
var prxyFn1 = proxy(targetFn);
prxyFn1(1);
prxyFn1(2);
prxyFn1(3);
prxyFn1(4);
prxyFn1(5);
prxyFn1(6);
prxyFn1(7);
prxyFn1(8);
prxyFn1(9);
prxyFn1.dataIterator(function(info){
    console.log(info);
});

var someObject = {
    targetFn: function(string){
        console.log("targetFn called with " + string + " and with conext of " + this);
        return string;
    }
};
prxyFn2 = proxy(someObject, "targetFn");
someObject.targetFn(1);
someObject.targetFn(2);
someObject.targetFn(3);
someObject.targetFn(4);
someObject.targetFn(5);
someObject.targetFn(6);
someObject.targetFn(7);
someObject.targetFn(8);
someObject.targetFn(9);
someObject.targetFn.dataIterator(function(info){
    console.log(info);
});

The API itself has four lower level functions, getCalledCount, getArgsPassed, getReturned and getData. Both getArgsPassed and getReturned can be called with or without arguments. If they are called without arguments they just return their backing variables, which are arrays. If they are called with a number which is in bounds then their backing variables’ corresponding array elements are returned. getData must be called with a number which is in bounds and returns an info object with count, argsPassed and returned properties. The API’s one higher level method dataIterator, which internally calls getData, takes a callback function as its only parameter which it calls with the info object returned by getData for as many times as proxy was invoked.

Summary

ProxyJS is now complete and fully functional. The source code for ProxyJS is available in a Gist on GitHub at https://gist.github.com/jeffschwartz/8375965. Please feel free to download it, play with it and to extend it for your own needs.

On a personal note, I am often amazed at what this little “toy language” JavaScript, yes, the language that some love to hate, is capable of. If you think about the functionality that is implemented into proxy and then consider how little code it actually took to implement it, well I find that impressive and I hope you do also. JavaScript sometimes just takes my breath away and leaves me speechless.

Please don’t forget to leave comments and remember to come back soon because I have a list of very interesting JavaScript topics that I intend writing about. Until then, happy coding!

Become A CoccyxJS MVC Ninja – Mini Tutorial #5: DOM Events

coccyxjs_ninjaWelcome to the 5th tutorial in a series of CoccyxJS mini tutorials. In the previous tutorial we learned how easy it is to use the CoccyxJS Collection component. In this tutorial we will explore how to handle DOM events. Before we get on with today’s mini tutorial please follow the instructions at “A Series jOf CoccyxJS Mini Tutorials”, if you haven’t already, for setting up a project directory structure and installing http-server which we will use throughout this series.

DOM Events

Views register the DOM events they want to be handled by Controllers by passing a hash with controller and events properties to Coccyx.views.extend. The value of the “controller” property is used as the context when calling the event handler functions. Additional properties are defined by the events hash for each DOM event to be handled and are of the form “event selector”: handler. When a DOM event is triggered, CoccyxJS will call the handler with a jQuery event object as an argument.

tutorial05.js

In your project’s root folder, specifically its javascripts folder, create a file named tutrotial05.js. In tutorial05.js paste the following code and save the file. We’ll discuss the code in a moment but it is so much better to see it played out first:


/**
 * CoccyxJS mini tutorial 05.
 * Expands on tutorial 04.
 * Handling DOM Events.
 */

(function(v){

    'use strict';

    //The object that we will use to create selectedDowView.
    var selectedDowViewTemplate = {
        tagName: 'h3',
        domTargetAttrs: {
            style: 'color: #f00; font-style: italic;'
        },
        render: function(dow){
            this.$domTarget.text('You clicked on ' + dow);
            return this;
        }
    };

    //Responds to click events on the days of the week.
    //We get the inner text of the target element.
    //Then we create a new selectedDowView and pass the inner text to its render method.
    //We then append the selectedDowView to the DOM.
    var dowClicked = function(event){
        //Get the inner text which happens to be the day of the week.
        var innerText = $(event.target).text();
        //Create a new selectedDowView by extending selectedDowViewTemplate.
        var selectedDowView = v.views.extend(selectedDowViewTemplate);
        //Render the day of the week to the DOM.
        v.$('#container').append(selectedDowView.render(innerText).domTarget);
    };

    //We'll create a View that renders markup to the page.
    //We define a method for the View named render. We
    //will pass it a Collection's data which is an array of
    //days of the week objects as a parameter and it will wrap each
    //day of the week object's day property in a header tag
    //and render it to the page.
    var daysOfTheWeekView = v.views.extend({
        render: function(data){
            var self = this;
            data.forEach(function(dayOfTheWeek){
                self.$domTarget.append('<h2 style="color: #00f">' + dayOfTheWeek.day + '</h2>');
            });
            //Return 'this' allows for chained access to
            //View properties when rendering to the page.
            return this;
        }
    }, {
        //The context that will be used when calling the event handlers.
        controller: this,
        //The events we will handle.
        events: {
            //Handle click events on all the h2 elements in dowClicked.
            'click h2': dowClicked
        }
    });

    //Implement a route handler for 'get /'
    var showIndexPage = function showIndexPage(){
        //Render the data to the DOM. Notice how we are taking
        //advantage of chaining!
        v.$('#container').html(daysOfTheWeekView.render(this.collection.getData()).domTarget);
    };

    //A simple controller that declares one route
    //and an init method that will be called immediately
    //before its route handler is called.
    //The route it will handle is 'get /'.
    //The function it will call is showIndexPage.
    var controller = {
        init: function(){
            //The data for the Collection.
            var data = [
                {day: 'Monday'},
                {day: 'Tuesday'},
                {day: 'Wednesday'},
                {day: 'Thursday'},
                {day: 'Friday'},
                {day: 'Saturday'},
                {day: 'Sunday'}
            ];
            //Create a Collection and initialize it with some data.
            this.collection = v.collections.extend();
            this.collection.setModels(data);
        },
        name: '',
        routes: {
            'get /': showIndexPage
        }
    };

    //Register the controller &
    //begin handling routing requests.
    v.history.start(true, [controller]);

}(window.Coccyx));

Add tutorial05.js to index.html

Open the index.html file, which is located in the project’s root directory, and then copy and paste the following markup into the file and save the file.

<!DOCTYPE html>
<html>
<head>
    <title>CoccyxJS Mini Tutorial Series</title>
</head>
<body>
    <h1>CoccyxJS Mini Tutorial Series</h1>
    <d id="container"></d>
    <!-- JavaScripts -->
    <script src="javascripts/libs/jquery.js"></script>
    <!-- Shim file has to be loaded before coccyx.js is loaded!!! -->
    <script src="javascripts/libs/shim.js"></script>
    <script src="javascripts/libs/coccyx.js"></script>
    <!--  Previous mini tutorials
    <script src="javascripts/tutorial01.js"></script>
    <script src="javascripts/tutorial02.js"></script>
    <script src="javascripts/tutorial03.js"></script>
    <script src="javascripts/tutorial04.js"></script>
    -->
    <script src="javascripts/tutorial05.js"></script>
</body>
</html>

Start http-server

Now open your terminal and make the project folder the current directory. Once you’ve done that start the server by typing http-server at the command line and hit enter. Depending on your operating system (I am running on a Mac) you should see something similar to the following:

Terminal

Run The Application In The Browser

Now open your browser and navigate to http://localhost:8080 and you should see the following in response:

minitutoutput4

Now click on a one or more of the days of the week that are displayed on the page. You should see something similar to this:

minitutoutput#5

What Just Happened?

Lets break this down by focusing only on what we added to the code from the previous tutorial:

  • We modified the way we are extending the daysOfTheWeekView to include a hash that has both a controller property and an events property. The controller property’s value will be used as the context whenever the event handlers are called which is convenient since it points to the controller. The events property is a hash whose property names are used to define the event type and the elements we are targeting, respectively, and the property’s value is the event handler function that we want to be called anytime an event on the element(s) is raised. So by defining these properties as we did, the function dowClicked will be called anytime a click event is raised on any h2 element on the page and it will be passed a jQuery Event object as its only argument.
  • In the dowClicked function we grab the inner text of the element that was clicked, which is the day of the week, and pass that on to the selectedDowView’s render method. The selectedDowView’s render method will render its DOM target by wrapping the text in an h3 element. Then the dowClicked function renders selectedDowView’s domTarget to the page by appending it to the div element whose id is container.

Now wasn’t that ezpz? Give yourself another pat on the back because you are one step closer to becoming a CoccyxJS Ninja.

What’s Next

With the conclusion of this tutorial we have learned about Models, Collections, Views, Controllers and how to wire up event handling. In our next mini tutorial we will go back to Collections and explore its rich API in greater detail. See you soon.

Become A CoccyxJS MVC Ninja – Mini Tutorial #4: Collection

coccyxjs_ninjaWelcome to the 4th tutorial in a series of CoccyxJS mini tutorials. In the previous tutorial we learned how easy it is to use the CoccyxJS Model component in a Web application for storing data. In this tutorial we will expand on that and use a Collection to store multiple data that we will pass to the View’s render method. But before we get on with today’s mini tutorial please follow the instructions at “A Series jOf CoccyxJS Mini Tutorials”, if you haven’t already, for setting up a project directory structure and installing http-server which we will use throughout this series.

Collections

Collections are light weight components that encapsulate arrays of Models which are stored in their “coll” array properties. Like Models and Views, they are manipulated by Controllers and their route handlers.

tutorial04.js

In your project’s root folder, specifically its javascripts folder, create a file named tutrotial04.js. In tutorial04.js paste the following code and save the file. We’ll discuss the code in a moment but it is so much better to see it played out first:

/**
 * CoccyxJS mini tutorial 04.
 * Expands on tutorial 03.
 * Using a Collection to pass data to a View.
 */

(function(v){

    'use strict';

    //Implement a route handler for 'get /'
    var showIndexPage = function showIndexPage(){
        //We'll create a View that renders markup to the page.
        //We define a method for the View named render. We
        //will pass it a Collection's data which is an array of
        //days of the week objects as a parameter and it will wrap each
        //day of the week object's day property in a header tag
        //and render it to the page.
        var daysOfTheWeekView = v.views.extend({
            render: function(data){
                var self = this;
                data.forEach(function(dayOfTheWeek){
                    self.$domTarget.append('<h2 style="color: #00f">' + dayOfTheWeek.day + '</h2>');
                });
                //Return 'this' allows for chained access to
                //View properties when rendering to the page.
                return this;
            }
        });
        //Render the data to the DOM. Notice how we are taking
        //advantage of chaining!
        v.$('#container').html(daysOfTheWeekView.render(this.collection.getData()).domTarget);
    };

    //A simple controller that declares one route
    //and an init method that will be called immediately
    //before its route handler is called.
    //The route it will handle is 'get /'.
    //The function it will call is showIndexPage.
    var controller = {
        init: function(){
            //The data for the Collection.
            var data = [
                {day: 'Monday'},
                {day: 'Tuesday'},
                {day: 'Wednesday'},
                {day: 'Thursday'},
                {day: 'Friday'},
                {day: 'Saturday'},
                {day: 'Sunday'}
            ];
            //Create a Collection and initialize it with some data.
            this.collection = v.collections.extend();
            this.collection.setModels(data);
        },
        name: '',
        routes: {
            'get /': showIndexPage
        }
    };

    //Register the controller &
    //begin handling routing requests.
    v.history.start(true, [controller]);

}(window.Coccyx));

Add tutorial04.js to index.html

Open the index.html file, which is located in the project’s root directory, and then copy and paste the following markup into the file and save the file.


<!DOCTYPE html>
<html>
<head>
    <title>CoccyxJS Mini Tutorial Series</title>
</head>
<body>
    <h1>CoccyxJS Mini Tutorial Series</h1>
    <d id="container"></d>
    <!-- JavaScripts -->
    <script src="javascripts/libs/jquery.js"></script>
    <!-- Shim file has to be loaded before coccyx.js is loaded!!! -->
    <script src="javascripts/libs/shim.js"></script>
    <script src="javascripts/libs/coccyx.js"></script>
    <!--  Previous mini tutorials
    <script src="javascripts/tutorial01.js"></script>
    <script src="javascripts/tutorial02.js"></script>
    <script src="javascripts/tutorial03.js"></script>
    -->
    <script src="javascripts/tutorial04.js"></script>
</body>
</html>

Start http-server

Now open your terminal and make the project folder the current directory. Once you’ve done that start the server by typing http-server at the command line and hit enter. Depending on your operating system (I am running on a Mac) you should see something similar to the following:

Terminal

Run The Application In The Browser

Now open your browser and navigate to http://localhost:8080 and you should see the following in response:

minitutoutput4

What Just Happened?

Lets break this down:

  • We declared that our Controller has an init method. A Controller’s init method is a very handy way to do one-time initialization and it is called only once and only when a Controller receives its first routing request. Here we are using the init method to create and initialize a Collection and add it as a property of the Controller. When the route handler is called the Collection’s data will be passed to the View’s render method.
  • In the Controller init method we create a new Collection by calling v.collections.extend(), and then we call collection.setModels(data) to initialize the new Collection with data. Notice how we passed an array of hashes, where each hash has a day property whose value is the day of the week that will be rendered to the DOM.
  • Just like in tutorial03.js the route handler creates a View with a render method which takes a single parameter whose value will be rendered to the DOM. This route handler, however, differs from tutorial03.js in that it extracts multiple data that are to be rendered to the DOM from the Controller’s collection property by calling this.collection.getData(), which returns a copy of the data that is stored in the collection.

Now wasn’t that ezpz? Give yourself another pat on the back because you are one step closer to becoming a CoccyxJS Ninja.

What’s Next

With the conclusion of this tutorial we have learned about Models, Collections, Views and Controllers, which are the basic components for every CoccyxJS MVC application. In our next mini tutorial we will learn how to declare and respond to DOM events. See you soon.

Become A CoccyxJS MVC Ninja – Mini Tutorial #3: Model

coccyxjs_ninjaWelcome to the 3rd tutorial in a series of CoccyxJS mini tutorials. In the previous tutorial we learned how easy it is to use a CoccyxJS View component in a Web application for rendering markup to the DOM. In this tutorial we will expand on that and use a Model to store the message that we will pass to the View’s render method. But before we get on with today’s mini tutorial please follow the instructions at “A Series jOf CoccyxJS Mini Tutorials”, if you haven’t already, for setting up a project directory structure and installing http-server which we will use throughout this series.

Models

Models are light weight components that encapsulate data. Like Collections, which we will cover in a future tutorial, and Views, they are manipulated by Controllers and their route handlers. Models store their data in their “data” hash properties and Models provide a rich array-like API that includes methods for initializing , getting, setting and deleting data properties. Today we will focus on initializing a Model with data and getting the data back out of it.

tutorial03.js

In your project’s root folder, specifically its javascripts folder, create a file named tutrotial03.js. In tutorial03.js paste the following code and save the file. We’ll discuss the code in a moment but it is so much better to see it played out first:

/**
 * CoccyxJS mini tutorial 03.
 * Expands on tutorial 02.
 * Using a Model to pass data to a View.
 */

(function(v){

    'use strict';

    //Implement a route handler for 'get /'
    var showIndexPage = function showIndexPage(){
        //We'll create a View that renders markup to the page.
        //We define a method for the View named render. We
        //will pass it a Model's data which is a message as a
        //parameter and it will wrap the message in a header tag
        //and render it to the page.
        var helloWorldView = v.views.extend({
            render: function(data){
                this.$domTarget.html('<h2 style="color: #00f">' + data.message + '</h2>');
                //Return 'this' allows for chained access to
                //View properties when rendering to the page.
                return this;
            }
        });
        //Show the message. Notice how we are taking
        //advantage of chaining!
        v.$('#container').html(helloWorldView.render(this.model.getData()).domTarget);
    };

    //A simple Controller that declares one route
    //and an init method that will be called immediately
    //before its route handler is called.
    //The route it will handle is 'get /'.
    //The function it will call is showIndexPage.
    var controller = {
        init: function(){
            //Create a Model and initialize it with some data.
            this.model = v.models.extend();
            this.model.setData({message: 'Hello World!'});
        },
        name: '',
        routes: {
            'get /': showIndexPage
        }
    };

    //Register the controller &
    //begin handling routing requests.
    v.history.start(true, [controller]);

}(window.Coccyx));

Add tutorial03.js to index.html

Open the index.html file, which is located in the project’s root directory, and then copy and paste the following markup into the file and save the file.

<!DOCTYPE html>
<html>
<head>
    <title>CoccyxJS Mini Tutorial Series</title>
</head>
<body>
    <h1>CoccyxJS Mini Tutorial Series</h1>
    <d id="container"></d>
    <!-- JavaScripts -->
    <script src="javascripts/libs/jquery.js"></script>
    <!-- Shim file has to be loaded before coccyx.js is loaded!!! -->
    <script src="javascripts/libs/shim.js"></script>
    <script src="javascripts/libs/coccyx.js"></script>
    <!--  Previous mini tutorials
    <script src="javascripts/tutorial01.js"></script>
    <script src="javascripts/tutorial02.js"></script>
    -->
    <script src="javascripts/tutorial03.js"></script>
</body>
</html>

Start http-server

Now open your terminal and make the project folder the current directory. Once you’ve done that start the server by typing http-server at the command line and hit enter. Depending on your operating system (I am running on a Mac) you should see something similar to the following:

Terminal

Run The Application In The Browser

Now open your browser and navigate to http://localhost:8080 and you should see the following in response:

minitutorialoutput02

What Just Happened?

Lets break this down:

  • We declared that our Controller has an init method. A Controller’s init method is a very handy way to do one-time initialization and it is called only once and only when a Controller receives its first routing request. Here we are using the init method to create and initialize a Model and add it as a property of the Controller. When the route handler is called the Model’s data will be passed to the View’s render method.
  • In the Controller init method we first create a new Model by calling v.models.extend(), and then we call model.setData({message: ‘Hello World!’}) to initialize the new Model with data. Notice how we passed a hash with a message property whose value is the message that will be rendered to the DOM.
  • Just like in tutorial02.js the route handler creates a View with a render method which takes a single parameter whose value will be rendered to the DOM. This route handler, however, differs from tutorial02.js in that it extracts the message that is to be rendered to the DOM from the Controller’s model property by calling this.model.getData(), which returns a copy of the data that is stored in the model.

Now wasn’t that ezpz? Give yourself another pat on the back because you are one step closer to becoming a CoccyxJS Ninja.

What’s Next

In our next mini tutorial we will learn about Collections and we will expand upon tutorial03.js by passing a Collection to the View’s render method. See you soon.

Become A CoccyxJS MVC Ninja – Mini Tutorial #2: View

coccyxjs_ninjaWelcome to the second tutorial in a series of CoccyxJS mini tutorials. In the previous tutorial we learned how easy it is to use a CoccyxJS Controller component in a Web application for declaring and handling routing requests. In this tutorial we will expand on that and add a View to our application which will render markup to the DOM. But before we get on with today’s mini tutorial please follow the instructions at “A Series jOf CoccyxJS Mini Tutorials”, if you haven’t already, for setting up a project directory structure and installing http-server which we will use throughout this series.

Views

Views are generic components which applications use to render and remove markup to and from the DOM, respectively. Applications can also use Views to declare the DOM events that Controllers respond to. In todays mini tutorial we will focus only on rendering markup, leaving DOM event handling for a future tutorial. Views, like Models and Collections, which we will also learn about in future tutorials, are manipulated by Controllers and their route handlers.

Two common use patterns exist when working with Views:

  1. passing data that is to be rendered, whole or in part, to a View’s method which, by convention, is often named “render”, and
  2. returning “this” from the rendering method, allowing for “chained” access to View properties.

tutorial02.js

In your project’s root folder, specifically its javascripts folder, create a file named tutrotial02.js. In tutorial02.js paste the following code and save the file. We’ll discuss the code in a moment but it is so much better to see it played out first:

/**
 * CoccyxJS mini tutorial 02.
 * Expands on tutorial 01.
 * Creating a View that renders makrup to the DOM.
 */

(function(v){

    'use strict';

    //Implement a route handler for 'get /'
    function showIndexPage(){
        //We'll create a View that renders markup to the page.
        //We define a method for the View named render. We
        //will pass it a message as a parameter and it will
        //wrap the message in a header tag and render it to
        //the page.
        var helloWorldView = v.views.extend({
            render: function(message){
                this.$domTarget.html('
<h2 style="color: #00f">' + message + '</h2>
');
                //Return 'this' allows for chained access to
                //View properties when rendering to the page.
                return this;
            }
        });
        //Show the message. Notice how we are taking
        //advantage of chaining!
        v.$('#container').html(helloWorldView.render('Hello World!').domTarget);
    }

    //A simple controller that declares one route.
    //The route it will handle is 'get /'.
    //The function it will call is showIndexPage.
    var controller = {
        name: '',
        routes: {
            'get /': showIndexPage
        }
    };

    //Register the controller &
    //begin handling routing requests.
    v.history.start(true, [controller]);

}(window.Coccyx));

Add tutorial02.js to index.html

Open the index.html file, which is located in the project’s root directory, and then copy and paste the following markup into the file and save the file.

<!DOCTYPE html>
<html>
<head>
    <title>CoccyxJS Mini Tutorial Series</title>
</head>
<body>
<h1>CoccyxJS Mini Tutorial Series</h1>
<d id="container"></d>
    <!-- JavaScripts -->
    <script src="javascripts/libs/jquery.js"></script>
    <!-- Shim file has to be loaded before coccyx.js is loaded!!! -->
    <script src="javascripts/libs/shim.js"></script>
    <script src="javascripts/libs/coccyx.js"></script>
    <!--  Previous mini tutorials
    <script src="javascripts/tutorial01.js"></script>
    -->
    <script src="javascripts/tutorial02.js"></script>
</body>
</html>

Start http-server

Now open your terminal and make the project folder the current directory. Once you’ve done that start the server by typing http-server at the command line and hit enter. Depending on your operating system (I am running on a Mac) you should see something similar to the following:

Terminal

Run The Application In The Browser

Now open your browser and navigate to http://localhost:8080 and you should see the following in response:

minitutorialoutput02

What Just Happened?

Lets break this down:

  • First we created a View by extending the CoccyxJS View component, passing it an object “template” that defines the View we want it to create for us. We then assigned the returned View object to the variable helloWorldView.
  • In the View template that we passed to extend we created a method called render which takes a single parameter named message. In the body of the render method we wrapped message inside an h1 tag and called this.$domTarget.html, passing it the wrapped message and returned this to allow for easy chaining. Since we didn’t “tell” the View what it should use for the domTarget the View defaulted to using a plain div element and rendered our wrapped message to that div element while it was still detached from the DOM (see the Guide for a detailed explanation of detached and attached rendering and for how the View component creates its $domTarget property from its domTarget property).
  • Next, in our route handler we actually rendered the content of $domTarget to the DOM by calling v.$(‘#container’).html(helloWorldView.render(‘Hello World!’).domTarget). Notice how we are passing the value of message to the View’s render method as well as how we are making use of chaining.

(Note: In a real application it isn’t advisable to dynamically build markup using strings like we did here and instead we would probably chose to use one of the many templating libraries that are available.)

Now wasn’t that ezpz? Give yourself another pat on the back because you are one step closer to becoming a CoccyxJS Ninja.

What’s Next

In our next mini tutorial we will learn about Models and we will expand upon tutorial02.js by passing a Model to the View’s render method. See you soon.

Become A CoccyxJS MVC Ninja – Mini Tutorial #1: Controller

coccyxjs_ninjaWelcome to the first in a series of CoccyxJS mini tutorials and today we are going to learn how easy it is to add routing to our Web applications using the CoccyxJS Controller component. But before we get on with today’s mini tutorial please read the instructions in my article, “A Series jOf CoccyxJS Mini Tutorials”, which has instructions for setting up a project directory structure that we will use throughout the series as well as instructions for installing http-server, which we will use to run our mini applications.

Routing Request

Controllers manage your applications’ views, models and collections. They are also responsible for handle routing request, which is what we will focus on here today. Routing request can result whenever the URL in the browser’s address bar changes by clicking the browser’s forward and back navigation buttons or when a user clicks on an anchor tag or submits a form.

When a routing requests is made the CoccyxJS router will attempt to match the request to a route handler defined by a Controller in it routes hash. If found then the router will call the route’s handler function. If not found the router will ignore it.

Since CoccyxJS implements RESTFUL routing we always have to define our routes as “verb url”: handler, where verb can be one of “get”, “post”, “put” and “delete” and the url is the actual URL associated with the route. The verb plus the url together serve to uniquely identify the resource, which in the case of routing is the route handler function that will be called.

The most important thing to know at this point though is that CoccyxJS ignores all routing request until it is explicitly told to begin handling them. For that we need to call its History component’s start method which is used to register one or more Controllers and to begin processing routing requests.

I am sure that all this must sound a lot more complicated than it really is so instead of talking about it, lets implement it and we’ll see how CoccyxJS makes all this really easy.

tutorial01.js

In your project’s root folder, specifically its javascripts folder, create a file named tutrotial01.js if it doesn’t already exist. In tutorial01.js paste the following code and save the file. We’ll discuss the code in a moment but it is so much better to see it played out first:

/**
 * CoccyxJS mini tutorial 01.
 * Creating our first Controller and route handler.
 * The route we want thato handle is 'get /' and the
 * route handler that will be called will simply
 * alert 'Hello World!'.
 */

(function(v){

    'use strict';

    //Implement a route handler for 'get /'
    function showIndexPage(){
        //Alert "Hellow World!" just so we know
        //our routing request was actually handled.
        alert('Hello World!');
    }

    //A simple controller that declares one route.
    //The route it will handle is 'get /'.
    //The function it will call is showIndexPage.
    var controller = {
        name: '',
        routes: {
            'get /': showIndexPage
        }
    };

    //Register the controller &
    //begin handling routing requests.
    v.history.start(true, [controller]);

}(window.Coccyx));

Now, if you are on a Mac open up the terminal and make the project folder the current directory. Once you’ve done that we will start our server. Type http-server and hit enter. You should see the following:

Terminal

Now open your browser and navigate to http://localhost:8080 and you should see the following in response:

running_tutorial01

What Just Happened?

Ok so lets break this down:

  • First we created a function named showIndexPage which when called simply alerts “Hello World!”.
  • Next we created a Controller and its routes hash with one route definition defined to handle a request of “get /” by calling the showIndexPage function. We also gave the Controller a name by assigning it a property called… you guessed it… name and assigned it a value of “”. Since name is an empty string the router interpreted our route definition’s URL to just “domain/”. Had we given it a real name, say “invoices” for instances, then the router would have interpreted our route definition’s URL as domain/invoices. We will cover route definitions in more detail in a later mini tutorial but for now it is important just to realize that every Controller defines the routes it wants to handle and a name.
  • Lastly we called history.start(true, [controller]) to register our Controller and to begin processing route requests. By passing true as the first argument, we are instructing the router to not only begin processing routing requests, but to also route the browser’s current address. In response, after having registered our Controller, the router found a matching route definition (which it does because our Controller defined one) and called its handler, which is the showIndexPage function that we defined which displayed an alert of “Hello World!”.

Now wasn’t that ezpz? Give yourself a pat on the back because you are well on the way to becoming a CoccyxJS Ninja.

What’s Next

In the next mini tutorial we will learn about Views and we will expand upon tutorial01.js by adding a View to the route handler function. See you soon.

Become A CoccyxJS MVC Ninja – A Series Of CoccyxJS Mini Tutorials

coccyxjs_ninjaWhen learning how to use a new library there is nothing better than “hands on” experience. So in a series of mini tutorials I will teach you how easy it is to become a master at writing Web applications using CoccyJS. Each mini tutorial will be short and to the point and will be limited in focus to one or two aspects of CoccyxJS.

But before we actually begin with the mini tutorials we will need to create a simple project structure and install http-server (a simple command line server which we will use to serve static content).

Please follow the instructions below which will explain how to create the project structure which will be used throughout the series.

Project Structure

To begin, lets create a root project folder that we will use to contain the files for the mini tutorials. You can name it anything you like.

Once you have created the root project folder create the same project structure as pictured below. Please note that you do not have to create the javascripts/tutorial01.js file now. We will create that file together in the first mini tutorial.

projectstructure

With our project structure now in place, we need to add some JavaScript files to the javascripts folder.

Core JavaScript Library Files

Download CoccyxJS and save it to a file named coccyx.js in the javascripts/libs folder.

Download jQuery and save it to a file named jquery.js in the javascripts/libs folder.

Create a new file in /javascripts/libs and name it shim.js. Then paste the code below into it and save the file.

(function(){
    'use strict';
    window.define =  function define(){
        (arguments[arguments.length - 1])();
    };
}());

index.html

Create a new file in your root project folder and name it index.html. Then paste the markup below into it and save the file.

<!DOCTYPE html>
<html>
<head>
    <title>CoccyxJS Mini Tutorial Series</title>
</head>
<body>
    <h1>CoccyxJS Mini Tutorial Series</h1>
    <d id="container"></d>
    <!-- JavaScripts -->
    <script src="javascripts/libs/jquery.js"></script>
    <!-- Shim file has to be loaded before coccyx.js is loaded!!! -->
    <script src="javascripts/libs/shim.js"></script>
    <script src="javascripts/libs/coccyx.js"></script>
    <script src="javascripts/tutorial01.js"></script>
</body>
</html>

http-server

http-server is a simple command line http server that we will use. Please visit https://npmjs.org/package/http-server and follow the instructions there for installing http-server.

Reference Materials

Please take the opportunity now to read the Guide and scan through the API Reference. They will provide context that will be very helpful as we work through each mini tutorial and you can refer back to them at any time.

With our project structure now in place and http-server installed we are ready to begin with our very first mini tutorial.