Archive

Posts Tagged ‘jQuery’

JavaScript, jQuery, and UI Frameworking

In my professional consulting career, I’ve been avoiding the UI area of software development for years, much like I tend to avoid reporting tools like Crystal Reports or Business Objects. I like poking around in the guts of systems. Everything below the surface is so much more interesting, or so I thought. Instead of working on UI layers, I tried to hire other people to do what I thought was fairly simple work. This wasn’t working. It turns out, in order to direct hired hands, you need to know what the hell you’re asking them to do. So I backed off having other people do UI work and realized I just need to strap in and learn it on my own. This includes iOS, JavaScript, jQuery, and anything else to do with building user interfaces. It turns out, there’s a lot to learn.

I’ll talk about iOS in a future blog entry, once I get comfortable with iOS, Objective C, and all the related tools. Today I’m going to talk about JavaScript and jQuery.

In a side-project called Zifmia, I’m developing a service/cloud based game engine for Interactive Fiction. I’ve been working on this in pieces for a long time. It’s morphed from WPF, to Silverlight, to Java, to iOS, and I finally realized that if I could create a service, I don’t need to port it anywhere anymore. Well, except maybe the Kindle since the Kindle doesn’t support connected services. (This makes sense. Most people use the Kindle for reading and are only concerned about connectivity when purchasing and downloading a new book or other content.) But for the web, smartphones, the iPad, iPod, and other tablets, a service/cloud engine is really the right way to go.

I start developing the service layer using RESTful web services. I used the Microsoft .NET WCF REST 4.0 template to provide the external layer for the service side functionality. This was great since WCF 4.0 REST works nearly perfectly out of the box. There’s very little “tuning” to do to make it work locally or on a server. The one major issue I had was with cross-domain ajax calls, but that’s solved by adding a header on all return calls from the server. The service allows a consuming application to register a user, login, start a session (game), send commands to a session, and various other management tasks. I plan to implement oAuth so that the service can be embedded in Facebook properly.

I then start playing with various platforms to consume the service. I played round with Windows Phone 7 (Silverlight) and that was drop dead simple. It takes an object definition and two lines of code to consume the service. I didn’t implement a full Application, but it helped work through some of the service prototyping issues.

I played around with iOS, but stalled out because I wanted the web interface completed first. I had a very committed developer working on it, but our communication wasn’t working well, and so I set that relationship aside for the time being. (I haven’t forgotten about you Dan…hope to catch up soon). I then started to work on the client side JavaScript code and realized there was a LOT of work that needed to be done before anyone could use Zifmia properly. The result of that work is the essence of this article.

I started developing the interfaces in jQuery and JavaScript, but soon realized the code (HTML, CSS, JavaScript, jQuery) was becoming quite convoluted and unreadable. I also realized it would only get worse if I continued. So I started asking around and researching how JavaScript/jQuery based client user interfaces should be organized. The surprising answer is that although there are a handful of serious solutions, there isn’t a lot of open thinking about how this should be done. The people that understand the need and have the ability to work through the problems have created tools, but haven’t really shared the process with the public. It’s a shame, since that’s the really important part to share, not just the code.

I looked at a few of these tools (like JavascriptMVC, Backbone.js, SproutCore) but found all of them to have aspects I dislike. Complexity, dependencies, and high learning curves. Instead of adopting, I chose to develop my own, trying to work through the issues. Here is what I came up with. This is a very simple methodology for separation of concerns in a javascript UI framework.

The first order of business is to identify assumptions:

  • We will work on the concept of a single page interface.
  • The page will have its own class/namespace.
  • The page will have a master HTML arrangement (header, body, footer).
  • The body will be a View container.
  • Each view will be based on an HTML template separate from the main html page. The HTML template will use normal HTML, CSS, and JavaScript.
  • Each View will have its own Controller or Presenter class.
  • All AJAX calls will be contained in a single Service class. (This is arguable, since a more complex web application could have highly distinct groups of service calls. More than one Service class could be adopted).

The result is a very simple and effective way to separate code in a single page framework jQuery driven website.

Create a web page called index.html similar to the one below:

<html>
<head>
    <title>Zifmia></title>
    ....
</head>
<body onload="javascript:$MyWeb.onLoad();">
    <div id="outerPanel">
        <div id="ajaxLoading"><img src="images/loading.gif" alt="Loading" /></div>
        <div id="headerPanel"><p>Textfyre Presents, A Zifmia+Web Portal (Beta)</p></div>
        <div id="viewContainer"></div>
        <div id="footerPanel">Copyright @ 2011 Textfyre, Inc. - All Rights Reserved</div>
    </div>
</body>
</html>

In the head section of the html page, create a class and create an instance of the class as MyWeb:

var $MyWeb = new mySite();

function mySite() {

    this.controller = null;

    this.username = getCookie("username");

    this.onLoad() = function() {
        // Initialize page here.

        // based on your page logic, cookies, etc, determine the initial state of the page
        // this is where you would determine which view to show, or to show the default
        // view. Based on whatever view is needed, we set that controller to the page
        // controller and call init(), which should be a standard function on all
        // controllers.

        if (username != "") {
            this.controller = new sessionController();
        } else {
            this.controller = new defaultController();
        }

        this.controller.init();
    };

}

Since I assume you have a design in mind, you should be able to separate the various views on your own into html templates. Each template might look something like this:

<div id="loginPanel">
    <div style="font-size: 14pt; font-weight: bold;">
        Zifmia Login Form<span id="loginMessage" style="font-size: 10pt; font-weight: normal;
            margin-left: 20px;"></span></div>
    <hr />
    <table>
        <tr>
            <td>
                <span style="white-space: nowrap;">
                    Username:
                    <input class="login" id="zLogUsername" type="text" onkeyup="javascript:validateRequiredField(this);" /><span
                    id="zLogUsernameError"></span></span>
                <span id="nickNameField" style="margin-right:10px;font-weight:bold;">
                </span>
            </td>
            <td style="white-space: nowrap;">
                Password:
                <input class="login" id="zLogPassword" type="password" onkeyup="javascript:validateRequiredField(this);" /><span
                    id="zLogPasswordError"></span>
            </td>
            <td style="white-space: nowrap;">
                <a id="zLogSubmit" href="#login" onclick="javascript:$MyWeb.controller.login();return false;">login</a>
            </td>
            <td style="text-align: right; padding-left: 20px;">
                <span id="registerNotice">If you don't have an account, please <a href="#showRegistration"
                    onclick="javascript:$MyWeb.controller.showRegistration();return false;">register</a>.</span>
            </td>
        </tr>
    </table>
</div>

This html should be stored in a subdirectory called templates with the name loginTemplate.html. We can use a simple AJAX call to retrieve it:

    var loginTemplate = getTemplate("templates/loginTemplate.html");

    function getTemplate(templateURI) {
        return $.ajax({
            url: templateURI,
            global: false,
            type: "GET",
            async: false
        }).responseText;
    }

The getTemplate function should be placed in a utility class or in the page controller for easy reuse. From here’s simple to create a controller class to display a view template in the correct place in our html page:

function introController() {

    var REG_USERNAME_FIELD = "zRegUsername";
    var REG_PASSWORD_FIELD = "zRegPassword";
    var REG_NICKNAME_FIELD = "zRegNickname";
    var REG_EMAIL_ADDRESS_FIELD = "zRegEmailAddress";

    var LOG_USERNAME_FIELD = "zLogUsername";
    var LOG_PASSWORD_FIELD = "zLogPassword";

    var viewContainer = "#viewContainer";
    var usernameField = "#zLogUsername";
    var nicknameField = "#nickNameField";
    var regErrorPanel = "#regErrorPanel";
    var loginMessage = "#loginMessage";

    this.introTemplate = $Z.getTemplate("templates/introTemplate.html");
    this.loginTemplate = $Z.getTemplate("templates/loginTemplate.html");
    this.registrationTemplate = $Z.getTemplate("templates/registrationTemplate.html");

    this.init = function (message) {

        $(viewContainer).hide();
        $(viewContainer).html($(this.loginTemplate).html());

        var zLogUsername = document.getElementById(LOG_USERNAME_FIELD);
        var zLogPassword = document.getElementById(LOG_PASSWORD_FIELD);

        setRequiredValidator(zLogPassword);

        if (message != null && message != "") {
            $(loginMessage).text("(" + message + ")");
        } else {
            $(loginMessage).text("");
        }

        if ($Z.username != "") {
            //
            // We know the username and nickname, but the user is logged out.
            //
            $(usernameField).hide();
            zLogUsername.isValid = true;
            $(nicknameField).show();
            if ($Z.nickname != "") {
                $(nickNameField).html('<a href="#changeUser" onclick="javascript:$MyWeb.controller.changeUser();">' + $Z.nickname + '</a>');
            } else {
                $(nickNameField).html('<a href="#changeUser" onclick="javascript:$MyWeb.controller.changeUser();">' + $Z.username + '</a>');
            }
        } else {
            //
            // We don't know anything about the user.
            //
            setRequiredValidator(zLogUsername);
        }

        $(viewContainer).append($(this.introTemplate).html());
        $(viewContainer).show();

    };

    this.changeUser = function () {
        $Z.username = "";
        $Z.saveSessionData();
        this.init();
    };

    this.login = function () {
        var zLogUsername = document.getElementById(LOG_USERNAME_FIELD);
        var zLogPassword = document.getElementById(LOG_PASSWORD_FIELD);

        $Z.login(zLogUsername.value, zLogPassword.value,
                function (zifmiaLoginViewModel) {
                    if (zifmiaLoginViewModel.Status == "0") {
                        $Z.username = zRegUsername.value;
                        $Z.authKey = zifmiaLoginViewModel.AuthKey;
                        $Z.nickname = zifmiaLoginViewModel.Nickname;
                        $Z.saveSessionData();
                        $ZWeb.onLoad();
                    } else {
                        $(regErrorPanel).text(zifmiaLoginViewModel.Message);
                        $(zLogUsername).focus();
                    }
                },
                function (xhr, textStatus, errorThrown) {
                    $(regErrorPanel).html(xhr.responseText);
                }
            );
    };

    this.showRegistration = function () {
        $(viewContainer).hide();
        $(viewContainer).html($(this.registrationTemplate).html());

        var zRegUsername = document.getElementById(REG_USERNAME_FIELD);
        var zRegPassword = document.getElementById(REG_PASSWORD_FIELD);
        var zRegNickname = document.getElementById(REG_NICKNAME_FIELD);
        var zRegEmailAddress = document.getElementById(REG_EMAIL_ADDRESS_FIELD);

        setRequiredValidator(zRegUsername);
        setRequiredValidator(zRegPassword);
        setRequiredValidator(zRegNickname);
        setRequiredValidator(zRegEmailAddress);

        $(viewContainer).show();
    };

    this.register = function () {
        $(regErrorPanel).text("");
        var zRegUsername = document.getElementById(REG_USERNAME_FIELD);
        var zRegPassword = document.getElementById(REG_PASSWORD_FIELD);
        var zRegNickname = document.getElementById(REG_NICKNAME_FIELD);
        var zRegEmailAddress = document.getElementById(REG_EMAIL_ADDRESS_FIELD);

        $Z.register(zRegUsername.value, zRegPassword.value, zRegNickname.value, zRegEmailAddress.value,
                function (zifmiaRegistrationViewModel) {
                    if (zifmiaRegistrationViewModel.Status == "0") {
                        $Z.username = zRegUsername.value;
                        $Z.nickname = zRegNickname.value;
                        $Z.saveSessionData();
                        $ZWeb.controller.init(zifmiaRegistrationViewModel.Message);
                    } else {
                        $(regErrorPanel).text(zifmiaRegistrationViewModel.Message);
                        $(zRegUsername).focus();
                    }
                },
                function (xhr, textStatus, errorThrown) {
                    $(regErrorPanel).html(xhr.responseText);
                }
            );
    };
}

Note there are many other things happening in this controller including ajax calls and handling user interactions. The view is shown to the user through a jQuery call (which can be done with simple DOM manipulation):

        $(viewContainer).hide();
        $(viewContainer).html($(this.loginTemplate).html());
        $(viewContainer).show();

So that’s it. You have a main controller in your index.html page that can be access by using $MyWeb at any time, you have varied controllers that are at $MyWeb.controller that have methods that can be called from your html. All of your HTML is in separate files for easy editing and reuse. This is a simple, yet effective way to separate and manage your AJAX/jQuery/JavaScript enabled website.

Why Rich Internet Applications are better than AJAX

November 13, 2009 Leave a comment

I recently spent some time in a grindhouse development department learning Flex as well as supporting some basic AJAX features. I’ve also been working with Silverlight for over a year as a part of my Textfyre work. In the past, I’ve worked on projects that used some DHTML. I’m familiar with RESTful web services, jQuery, HttpWebRequest, and all of the other aspects of building highly interactive web apps. I’ve never done any real Java work, but I have played around with the technology enough to know that you can do decent things with Java (although the visuals have always left something to be desired).

Throughout these efforts I’ve always kept an eye what businesses might consider the most cost-effective solution for scaling their applications, whether the application is for internal use, external use, or a hybrid. Google took the lead in developing applications with AJAX when they introduced the nicer features of gmail.com and Google Maps. This was the birth of Web 2.0 and I would say we’re still in the middle of that era. A lot of companies have adapted to AJAX using jQuery and other toolkits. In many cases, using jQuery to liven up a website is very successful.

Then there are websites that are much more than just a website. We call these web applications and they tend to try to do many or all of the things that a desktop or “fat client” would do. These applications will load large amounts of related data, like customers, orders, transactions, and more.

A few years ago, our PC’s weren’t capable of handling this kind of scenario. It wasn’t the browser, but the lack of memory, disk space, and bandwidth. Today, most people have access to high speed Internet access. Most people have newer computers with more memory and more disk space. Certainly many businesses have either adopted these kinds of computers or will within the next year or two (in their move from XP to Windows 7).

So today we have the platform and the ability to make highly interactive and data intensive web applications. But the first question anyone should ask is, what are the requirements? I’ve seen a lot of applications ported from perfectly sound desktop applications (with deployment headaches, but still, they worked) to web applications. Deployment issues aside, there was no other requirement for the application to be built in web technologies. In many cases, the users lost many features and flexibility when their apps were webified. The process of moving a complex desktop application to the web paradigm is very expensive. We now have people called “information architects” that take very sound desktop user experiences and port them to web technologies. Why do we need these people. Because building smart web applications is vastly more complicated than building smart desktop applications.

There certainly are benefits to having an application webified. In a desktop application you might have a very strict set of menus and options or a single path to each feature. In a web application, you can develop multiple paths to features with varying usage scenarios. Some of this is possible in a desktop application too, but a web app offers these types of options through links and is much more seamless.

Benefits aside, web applications are very complex applications to build and moreso, to maintain. To allieviate the maintenance costs of building web applications, tools have been developed that make creating and debugging most applications very easy. Inline debuggers allow us to literally step through every line of code, see the stack trace, review element values, and resolve issues without throwing darts blindfolded. Debugging used to be a much higher level skillset. It’s still an art and skill, but with the tools today, it’s much more widely available to the average programmer. With an exception. AJAX.

AJAX is great, as I said before, for making websites behave nicely. But when you take the technology of AJAX and marry it to a complex web application, you’re exponentially adding complexity and cost to your application development and maintenance budget. The tools for debugging AJAX are not simple. In many cases a developer will resort to using Fiddler (a tool that watches HTML transactions) and arcane alert(‘here I am!’); statements haphazardly placed within the application’s javascript. This is a nightmare scenario for any developer. The more AJAX you implement in a web application, the more complex the interactions get and debugging capabilities rapidly deteriorate. And this is if your codebase is developed well and is highly readable. If the code was slapped together in a rush, forget it. You may never completely understand what the code is trying to do and it could be safer to do an organ transplant instead of minimally invasive surgery.

With any problem, someone inevitably sees it and develops a solution. Oddly enough, Sun developed a solution before the problem existed with Java technology. The problem is that Java made more of a name for itself in the server world and standard web application development. The client side features of Java were left to cute games and scientific demonstrations. You can blame a little of this on Sun for so desperately trying to make Java pure across platforms when they should have recognized the value of implementing a VM->Native compiler for each platform (Sun, Mac, Windows, Unix, etc). Instead, Microsoft saw the potential and created .NET, not necessarily to be cross-platform, but to enable managed code, garbage collection, for client-side and server-side development.

Eventually Sun realized the potential for Rich Internet Applications and has been actively marketing related solutions. But so has Adobe with Flex and Microsoft with Silverlight. These three platforms enable cross-platform application development that does not rely on web technolgies like html, css, and AJAX. These technologies offer front to back development environments with very robust and clear layout engines (arguing that CSS is hardly clear although it is robust), strong debugging tools, and deep integration with web services.

This is where application development is headed and it’s primarily because CIO’s have started to quantify the cost of developing web applications. We made enormous strides in resolving deployment problems (10 years ago we had to package software to be installed automatically on thousands of PC’s upon login and if there was a problem or virus, well, it was very painful), but at the cost of lost features and very expensive maintenance.

We now have the ability to deploy applications that more secure ane vastly more stable than before. Managed code, which is used in all three platforms, is the key to the stability issue. Security has become a primary focus within Microsoft and no one would argue that their systems and applications have improved dramatically since the early XP days of major viruses appearing daily.

We can now develop middleware that is adaptable and maintainable at a low cost. We now have the ability to develop disconnected presentation layers that can manage large datasets, but is also easily developed and maintained. It looks pretty too, if you have good designers.

If you look at new development requirements coming out of the major job sites like Monster.com, CareerBuilder.com, Dice.com, you’ll see that Silverlight and Flex have taken off. I’m not sure why Java hasn’t, but I assume some companies will adopt the Java desktop model too.

Throw away your CSS and AJAX libraries. You’ll save time, money, and your users and your infrastructure staff will love you. So will your shareholders.