require (parent controllers) in modern Angular
require: '^^parent' becomes inject(ParentComponent). Angular looks for the parent up the element tree, the same way require did.
Before · AngularJS
app.component('tabPane', {
require: { tabs: '^^tabGroup' },
bindings: { title: '@' },
transclude: true,
template: '<div ng-show="$ctrl.active" ng-transclude></div>',
controller: function () {
this.$onInit = function () { this.tabs.addPane(this); };
this.$onDestroy = function () { this.tabs.removePane(this); };
}
});After · Angular@Component({
selector: 'app-tab-pane',
template: `<div [hidden]="!active()"><ng-content /></div>`,
})
export class TabPaneComponent {
private tabs = inject(TabGroupComponent);
title = input.required<string>();
active = computed(() => this.tabs.selected() === this);
}
// in TabGroupComponent: the parent finds its panes with a query
panes = contentChildren(TabPaneComponent);
selected = signal<TabPaneComponent | undefined>(undefined);What changes
- An optional require ('?^^parent') becomes inject(ParentComponent, { optional: true }).
- Children no longer register themselves with addPane and removePane: the parent reads them with contentChildren or viewChildren.
- When the two components are not ancestor and descendant, use a service listed in the providers of their common container.
Migration tip. A parent and a child that reference each other's classes from separate files create a circular import. Keep the pair in one file, or have the child inject an InjectionToken that the parent provides.
Related
Planning a migration or a micro-frontend platform?
In a 20-minute call you describe your situation and I tell you how I'd approach it. If it isn't worth doing yet, I'll say so.
Message me on LinkedIn