docs

Forwarding Aggregations

A mechanism used for aggregations of composite controls. With aggregation forwarding, an aggregation declared on a composite is automatically routed to an aggregation of one of its inner controls — without writing add/remove/destroy wrappers by hand.


Overview

Aggregation forwarding lets a composite control declare an aggregation in its public API while keeping the actual children inside one of its inner controls. The composite acts as if it owned the children; internally, they live on the inner control.

This technique is often used when the composite wraps an existing control to add functionality, but applications should still be able to fill the wrapped control’s aggregations directly. At other times, the composite control uses internal layout controls to position aggregated children.

Note:

Aggregation forwarding is technically a feature of the ManagedObject base class, available to any class that inherits from ManagedObject directly or indirectly. The most common use case is composite controls, which is the focus of this page.

For more information about this class, see the API Reference: ManagedObject.

Note:

Sometimes the controls that have been added to an aggregation of a composite control have to be transformed into different controls, which are then added to an aggregation of an internal control. This is a different use case and not covered by aggregation forwarding. With aggregation forwarding, aggregated child controls are moved without transforming them.


Configuration

Aggregation forwarding is configured directly on the aggregation declaration in the control metadata. OpenUI5 needs two pieces of information: which inner control receives the forwarded children, and which aggregation on that inner control they should land in.

Aggregation forwarding is defined in the aggregation definition inside the control metadata.

The forwarding property can be set as an object defining the following:

When such a forwarding definition is done, OpenUI5 moves all aggregated child controls to the target control. All calls to addAggregation, removeAggregation, indexOfAggregation and so on are forwarded. When asked for the forwarded child control, both the composite control and the forwarding target act like the child control belongs to their aggregation. However, the inner forwarding target control is the actual parent of all forwarded children.


Examples

Here is an example that demonstrates aggregation forwarding: The new FilterableList control is supposed to display a list of items with an input field above the list. The list items are filtered while the user is entering the input. This FilterableList control can be implemented as a composite control, using the sap.m.List and sap.m.Input controls as inner controls to take advantage of their existing implementation, design, and set of features. Application developers using FilterableList cannot change all attributes of the inner List control. However, they should be able to provide the actual list items. Hence, the new FilterableList composite control has an items aggregation and forwards all items to the inner sap.m.List control, so, for example, the layouting, events, and selection can be handled there.

aggregations: {
    // The items forwarded from the FilterableList to the internal sap.m.List
    items: {
        type: "sap.m.ListItemBase",
        multiple: true,
        forwarding: {
            idSuffix: "-myInternalList",
            aggregation: "items"
        }
    }
}

Another example: a ButtonList control that displays an arbitrary number of sap.m.Button controls in a grid. Instead of writing custom HTML and screen-size-dependent CSS for the layout, the composite uses an internal sap.ui.layout.Grid and forwards its buttons aggregation to the grid’s content.

aggregations: {
    // The items forwarded from the ButtonList to the internal sap.ui.layout.Grid
    buttons: {
        type: "sap.m.Button",
        multiple: true,
        forwarding: {
            getter: "_getInternalGrid",
            aggregation: "content"
        }
    }
}

The getter value must be the name of a method on the composite that returns the inner target control instance. A minimal implementation:

_getInternalGrid() {
    return this.getAggregation("_grid");
}

Migrating from XMLComposite

Aggregation forwarding is the same ManagedObject-level API in both worlds — the forwarding configuration on an aggregation is a feature of sap.ui.base.ManagedObject, not of XMLComposite. The aggregations block from a deprecated XMLComposite control can be reused almost verbatim on a standard sap.ui.core.Control, with two adjustments:

Example: Before/After

This example demonstrates the migration of a texts aggregation forwarded into an inner VBox.

Before migration:

// XMLComposite (deprecated): TextList.js
sap.ui.define([
    "sap/ui/core/XMLComposite"
], function(XMLComposite) {
    "use strict";
    return XMLComposite.extend("fragments.TextList", {
        metadata: {
            aggregations: {
                texts: {
                    type: "sap.ui.core.Item",
                    multiple: true,
                    forwarding: {
                        idSuffix: "--vbox",
                        aggregation: "items"
                    }
                }
            }
        }
    });
});
<!-- TextList.control.xml -->
<core:FragmentDefinition xmlns:m="sap.m" xmlns:core="sap.ui.core">
    <m:VBox id="vbox"/>
</core:FragmentDefinition>

After migration:

// Standard composite: TextList.js
sap.ui.define([
    "sap/ui/core/Control",
    "sap/m/VBox",
    "./TextListRenderer"
], function(Control, VBox, TextListRenderer) {
    "use strict";

    const TextList = Control.extend("my.TextList", {
        metadata: {
            aggregations: {
                texts: {
                    type: "sap.ui.core.Item",
                    multiple: true,
                    forwarding: {
                        idSuffix: "-vbox",
                        aggregation: "items"
                    }
                },
                "_layout": { type: "sap.m.VBox", multiple: false, visibility: "hidden" }
            }
        },

        init() {
            Control.prototype.init.apply(this, arguments);
            this.setAggregation("_layout", new VBox(this.getId() + "-vbox"));
        },

        renderer: TextListRenderer
    });

    return TextList;
});
// TextListRenderer.js
sap.ui.define([], function() {
    "use strict";

    return {
        apiVersion: 4,
        render(oRm, oControl) {
            oRm.openStart("div", oControl);
            oRm.openEnd();
            oRm.renderControl(oControl.getAggregation("_layout"));
            oRm.close("div");
        }
    };
});

Only one character changed in the forwarding configuration: the leading double dash became a single dash. The texts aggregation still forwards to the inner VBox’s items.

Tip:

If your inner target’s ID does not follow the <composite-id>-<suffix> convention, use the getter form of forwarding instead of idSuffix. See Configuration and the ButtonList example above.


Dos and Don’ts

If you use aggregation forwarding, you have to keep the following in mind:

Related Information

Composite Controls

Building Standard Composite Controls

Synchronizing Properties via a $this Model

API Reference: sap.ui.base.ManagedObject.extend