This documentation is currently being moved to our new documentation site.

Please view or edit the documentation there, instead.

If you're looking for Fluid Project coordination, design, communication, etc, try the Fluid Project Wiki.

Why Inversion of Control

The Infusion Framework is designed to support highly flexible aggregation of reusable components. The Inversion of Control (IoC) system provides the ability for reusable components to pull dependencies from the environment rather than having to push them in initialisers. Inverting control this way allows users of the framework and components to customize implementations by plugging in alternative subcomponents, without having to modify the parent component code.

Compare the following examples:

Without IoC

 

/**
 * Component creator function
 */
fluid.myComponent = function (container, options) {
    var that = fluid.initView("fluid.myComponent", container, options); // WARNING: This kind of manual initialisation is no longer supported
    that.model = {
        ...
    };
    that.field = that.locate("inputField");

    // Instantiation of first subcomponent
    that.sub1 = fluid.initSubcomponent(that, "sub1",
        [that.options.selectors.sub1container, {
            model: that.model,
            field: that.field
        }]);

    // Instantiation of second subcomponent
    that.sub2 = fluid.initSubcomponent(that, "sub2",
        [that.model]);

    // Instantiation of third subcomponent
    that.sub3 = fluid.initSubcomponent(that, "sub3",
        [that.container, that.events.onSave]);

    return that;
};

This is an old style of code which is no longer supported in the framework. It shows how the construction of a component and its subcomponent could be expressed without IoC, using literal JavaScript code. This component creator function initializes three subcomponents. Each initialization requires a call to fluid.initSubcomponent() with the specific parameters that the subcomponent implementation requires (the array of parameters is the third argument to fluid.initSubcomponent()). The second argument to fluid.initSubcomponent() is the string name of the subcomponent, as specified in the defaults (not necessarily the actual function name).

 

/**
 * Default options for the component
 */
fluid.defaults("fluid.myComponent", {
    sub1: {
        type: "fluid.mySubComponent1Impl"
    },
    sub2: {
        type: "fluid.mySubComponent2Impl"
    },
    sub3: {
        type: "fluid.mySubComponent3Impl"
    },
    selectors: {
        inputField: ".flc-myComponent-inputField",
        sub1container: ".flc-subComponent1"
    },
    events: {
        onSave: null,
        afterSave: null
    }
});

The fluid.defaults() call declares the default function to use for the subcomponents, by name. Users can override these defaults by specifying a different function name, but the arguments to the customized replacement must be the same, or the user will have to modify the code that calls fluid.initSubcomponent() for that subcomponent. Note that this style of fluid.defaults call without gradeNames is no longer supported.

With IoC

 

/**
 * Default options for the component with autoInit grade.
 */
fluid.defaults("fluid.myComponent", {
    gradeNames: ["fluid.viewComponent", "autoInit"],
    "fluid.myComponent.postInitFunction",
    members: {
        field: "{that}.dom.inputField"
    },
    components: {
        sub1: {
            type: "fluid.subComponent1Impl"
        },
        sub2: {
            type: "fluid.subComponent2Impl"
        },
        sub3: {
            type: "fluid.subComponent3Impl"
        }
    },
    selectors: {
        inputField: ".flc-myComponent-inputField"
    },
    events: {
        onSave: null,
        afterSave: null
    }
});

With IoC, no JavaScript code is required either for component/subcomponent initialisation, or for wiring the tree together. The component creator function does not initialize each subcomponent manually - any components defined in the components section of the defaults provided to fluid.defaults() will be initialized automatically when the component is constructed. In the component defaults, the types of components to use for the subcomponents are defined inside a property called components. The values for the type properties will be grade names. With the autoInit grade directive, the component creator function will be generated from component defaults. Any code present in the old style creator function can then be distributed into appropriate IoC definitions. Most can be written declaratively, some still require to be registered as a listener to the standard component event onCreate.