Developer Introduction to the Infusion Framework - Overriding Invokers and Refactoring

With the console and display functionality extracted as separate components, it's easier to see that large blocks of their configuration are similar:

  • they have the same model characteristics
  • they both have a model listener that calls a "say hello" function
  • while their invokers have different names, this isn't necessary now that they've been split out into separate component definitions - we can use invokers to provide each component with an externally identical invoker with a different internal implementation. This is an example of method overriding.

Let's refactor to avoid duplication and create a base "say hello" component that other types of "say hello" component can derive from:

Note: You can check out the Live Example of the code below on CodePen
fluid.defaults("fluidTutorial.helloWorld.sayHello", {
    gradeNames: ["fluid.modelComponent"],
    model: {
        message: "Hello, world!"
    },
    modelListeners: {
        message: "{that}.sayHello"
    },
    invokers: {
        // fluid.notImplemented is a function that specifically represents
        // an unimplemented function that components deriving from this
        // grade are intended to implement; this is called an "abstract
        // method" in Java
        sayHello: "fluid.notImplemented"
    }
});

fluid.defaults("fluidTutorial.helloWorld.consoleHello", {
    // This component has all of the characteristics of sayHello,
    // except for its implementation in the invoker
    gradeNames: ["fluidTutorial.helloWorld.sayHello"],
    invokers: {
        sayHello: {
            "funcName": "fluidTutorial.helloWorld.consoleHello.sayHello",
            // Here, "{that}" means the context of the current
            // component configuration (consoleHello)
            args: ["{that}.model.message"]
        }
    }
});

fluidTutorial.helloWorld.consoleHello.sayHello = function (message) {
    console.log(message);
};

fluid.defaults("fluidTutorial.helloWorld.displayHello", {
    // This component has all of the characteristics of sayHello,
    // except for its implementation in the invoker; additionally:
    //
    // 1) It adds the fluid.viewComponent grade to the gradeNames
    // array to give it the DOM binding capabilities of a viewComponent;
    // when multiple grade name are supplied in the array, their
    // configurations are combined in left to right order, with the
    // rightmost configuration taking precedence if there is a
    // duplication of keys at the same place in the configuration
    //
    // 2) It adds a selector for the messageArea
    gradeNames: ["fluidTutorial.helloWorld.sayHello", "fluid.viewComponent"],
    selectors: {
        messageArea: ".flc-messageArea"
    },
    invokers: {
        sayHello: {
            "this": "{that}.dom.messageArea",
            method: "html",
            args: ["{that}.model.message"]
        }
    }
});

fluid.defaults("fluidTutorial.helloWorld", {
    gradeNames: ["fluid.modelComponent"],
    model: {
        message: "Hello, World!"
    },
    listeners: {
        "onCreate.announceSelf": {
            "this": "console",
            method: "log",
            args: ["The helloWorld Component is ready"]
        }
    },
    components: {
        consoleHello: {
            type: "fluidTutorial.helloWorld.consoleHello",
            options: {
                model: {
                    message: "{helloWorld}.model.message"
                }
            }
        },
        displayHello: {
            type: "fluidTutorial.helloWorld.displayHello",
            container: ".helloWorld",
            options: {
                model: {
                    message: "{helloWorld}.model.message"
                }
            }
        }
    }
});

Next: Extending Designs with Existing Components