HPI 2.1 Extension Examples - tsgrp/HPI GitHub Wiki


Please see Overriding-an-action for up-to-date details on extending an action.


Clean Extension in Javascript has always been a tricky thing. Between the psuedo-object-oriented-but-really-functional nature of javascript and the lack of compilation and enforced structure of projects, it's not always clear how to extend and so many people just copy the original into a new file, change what they want and call it day.

This is not the way to go.

With HPI 2.1 we are striving to establish patterns that developers can follow when they need to make an extension.

For our first example, let's take the Wizard Module. After a form is finished, the user is redirected back to the stage in a track called 'wizard'.

window.finish = function() {
    window.location = "/Stage/wizard/" + formId + "|" + formId;
};

That's all well and good, but let's say a client (Abbspira) has decided to name their wizard trac 'corporateForms'. First, let's create a file to put our overrides in:

wizard-abbpira.js

define(["modules/wizard/wizard"], function(Wizard){
    //make modifications to wizard then return
    return Wizard;
});

Now in config.js change the wizard mapping from "modules/wizard/wizard" to "modules/clients/abbspira/wizard/wizard-abbspira"

At this point you should be able to load up the app and see the code run through our custom module and we can start making customizations. In order to overridde the return function, it may be tempting to just paste in the entire layout, make your change and call it a day. But there is a better way! In java we refer to it as hotspots.

In the original wizard.js let's create a new function:

Wizard.resolveTrac = function(formId){
    return "wizard";
}

Then change the finish (and save/exit) function.

window.finish = function() {
    window.location = "/Stage/" + Wizard.resolveTrac(formId) +"/" + formId + "|" + formId;
};

Now in our custom file, we can just override the one function

define(["modules/wizard/wizard"], function(Wizard){
    //make modifications to wizard then return
    Wizard.resolveTrac = function(formId){
        return "corporateForms";
    };
    return Wizard;
});

It's not hard to see how if you had more complicated logic, you could put in calls to the server or other logic to dynamically choose a return trac. What if you wanted to make this feature a configuration instead of having to override it for every client? Easy.

in wizard.js add module to the define call

define([app, 'module'], function(app, module){
     ...
    Wizard.resolveTrac = function(formId){
    if(module.config()){
        return module.config().wizardTrac || "wizard";
    }
  ...
});

Then in config.js: config : { wizard: { wizardTrac : "corporateForms" } }

There is more to be said about extension especially when it comes to extending views and viewmodels, but that is another day. Please add here if you wish. The basic idea would be:

custom.js define(["modules/foo/bar"], function(Bar){ //make modifications to wizard then return Bar.View = Bar.View.extend({ //maybe custom template here: template: "/new/template", //override a method here: oldMethod : function(){...}; }); return Bar; });

⚠️ **GitHub.com Fallback** ⚠️