top of page
Search

Becoming Fluent in JavaScript

Updated: Feb 24, 2021

TL;DR: Granted, the title is a play on words—I’m not offering instant fluency in the JavaScript language. This is, however, the story of how I came to understand and use the “fluent interface” design pattern in that language. If you’re still game, read on! —Mark

 

JavaScript is a second language for me, even though I've been using it for more than a decade. Like all things in programming, though, it's a moving target. Expertise that was sufficient to write JavaScript for, say, running the menus on your website in 2001, is now hopelessly out of date. The cool dudes who specialize in JavaScript-based systems are using ECMAScript (ES6, ES7, etc.), TypeScript, Node.js, React, Vue.js—and a whole host other variants that leave good old JavaScript from yesteryear in the dust.


So, admittedly, I'm not one of the cool dudes of JavaScript, but I still use it, and like it, and continue to learn more about it all the time.


Over the past few weeks, I've been working on a project that I've been meaning to get around to for a at least a year: to create a user interface for the Spatie Laravel-permission package. Laravel-permission is a simple and elegant Role Based Access Control (RBAC) add-on to the Laravel PHP framework. It provides a means to grant access to selected parts of your application in a very flexible way. I'll talk more about this project in a subsequent post.


Out of the box, Laravel-permission is strictly a back-end product. You can do everything necessary on the PHP side, but it leaves the process of creating roles and permissions for you to do manually. Because I’ve used other RBAC's with full user interfaces in the past, I felt that I really needed to have one for this project. I looked at the various possibilities created by other folks, and none of these really satisfied me. But, hey, I'm a coder, so I coded my own.


I decided that the best user experience would come from tying the front end to the back end with AJAX calls that I’d make to API endpoints on the Laravel side. This involved writing a rather complex suite of JavaScript modules using jQuery in ES6 classes that would be compiled into native JavaScript via Laravel Mix.


By yesterday, I had most of the UI working the way I wanted. Then, about 12:30 this morning, I woke up and started thinking about a better way to do the AJAX calls. Once that business starts, there's no hope for it but to sneak out of bed, hoping not to wake up my wife, and head up to the office to code.

 

The idea was to see if I could create a separate JavaScript module just for the AJAX requests, and code it to use a fluent interface. This kind interface is very common in Laravel. You often see something like this:


return Post::where('author', '=', 123)
               ->pluck('title','excerpt')
               ->orderBy('created_at', 'desc')
               ->get(); 

This is very compact and easy to read compared with the more traditional syntax where you might new up (instantiate) the Post class, then make calls to the instance methods on separate lines, maybe setting the results to variables along the way.


$post = new Post();
$post->where('author', '=', 123);
$post->pluck('title','excerpt');
$post->orderBy('created_at', 'desc');

return $post->get();

I'm not sure whether the above would actually work, but I hope you see my point.


Now, you might wonder how the heck you can chain all of these methods together to create a fluent interface, and I did as well until I took a look "under the hood" at Laravel's core code. Each of the methods actually returns a reference to the instance itself. So the "orderBy" method actually does this:

public function orderBy($column, $direction = 'asc')
{
    // Do all the order by stuff, then...
    
    return $this;
}

The key is: return $this—$this being an instance of the Builder class that‘s at the root of Laravel's Eloquent Object Relational Mapping (ORM) framework—the coolness that provides an interface to any type of database you might want to connect to.


I'd been aware that jQuery uses similar syntax without really understanding how it worked. But now, having worked with Laravel for a while, I could see that it does fundamentally the same thing. If you’ve worked with jQuery, you’ve probably used something like this:

$(‘#my_content’).addClass('embolden')
    .show();

Each jQuery method is returns an instance of its parent class, and this lets you add any other relevant method to the chain.


So, given this understanding I created the following class to abstract the jQuery $.ajax object into something I like to call, RequestAjax*.

export default class RequestAjax {
    constructor() {
        this.caller = null;
        this.endpoint = null;
        this.method = null;
        this.data = null;
        this.successCallback = null;
        this.errorCallback = null;
    }

    fromCaller(caller) {
        this.caller = caller;
        return this;
    }

    withMethod(method) {
        this.method = method;
        return this;
    }

    withEndpoint(endpoint) {
        this.endpoint = endpoint;
        return this;
    }

    withData(data) {
        this.data = data;
        return this;
    }

    usingSuccessCallback(callback) {
        this.successCallback = callback;
        return this;
    }

    usingErrorCallback(callback) {
        this.errorCallback = callback;
        return this;
    }

    request() {
        let self = this;
        $.ajax({
            url: this.endpoint,
            type: this.method,
            datatype: 'json',
            data: this.data,
            success: function (response) {
                if (typeof self.successCallback === 'function') {
                    self.successCallback(self.caller, response);
                }
            },
            error: function (response) {
                if (typeof self.errorCallback === 'function') {
                    self.errorCallback(self.caller, response);
                }
            }
        });
    }
}


To use this, you would do something like this:

let ajax = new RequestAjax();

ajax.withMethod('GET')
    .withEndpoint('/api/posts')
    .withData('author=123')
    .usingSuccessCallback(function (response) {
            // Do what thou wilt with the response.
    }).request();

My usual practice is to add this as an import in app.js in the resouces directory of my Laravel project, then inject it into the constructor of whatever class I need it for:


import RequestAjax from './request-ajax.js';
import PostManager from './post-manager.js';

// Make jQuery available to your classes as "$"  
// Requires adding jQuery to package.json
window.$ = require('jquery');

let ajaxRequest = new RequestAjax();

// You can now pass ajaxRequest into the constructor of any class
// I use an “options” parameter and set it via 
// this.ajax = options.ajax
new PostManager({
    ajax: ajaxRequest
});
 

So that‘s the long and the short of it. Before creating RequestAjax, I had calls to jQuery’s $.ajax in four places in my code, with only slight differences between them. Each call required 10-14 lines code, much of which was redundant. The replacements are 5-6 lines, and I can drop an instance of RequestAjax into any class that needs it. As one who is striving to always use SOLID principles, and is forever DRY-ing (Don’t Repeat Yourself) my code, this seemed like a darned good idea.


I welcome your feedback on this and anything I post. If I’ve learned anything in my 30+ years of coding, it’s that I’m never an expert, but ever a student.


* I called my class “RequestAjax” rather than the more intuitive “AjaxRequest” because webpack, the asset compiler used by Laravel Mix, picks the first item in your /resources/assets/js directory alphabetically as the name to use for the name of the compiled file in the public/js directory. Don’t ask me why. If you know how to avoid this, I’d appreciate your input!




34 views0 comments

Recent Posts

See All
bottom of page