I am trying to do a PoC for ngUpgrade on one module of my app, and I'm running into an issue with transclusion/content projection along with AngularJS requires
.
Let's say there's a downgraded Angular component defined like:
@Component({
selector: 'common-filter',
template: `
<ajs-filter>
<div>Common Filter</div>
<ajs-button text="Outside of content projection"></ajs-button>
<ng-content></ng-content>
</ajs-filter>
})
export class CommonFilter {}
ajsButton
is an upgraded AngularJS component that requires a parent controller:
require: {
ajsFilterCtrl: '^ajsFilter'
}
A normal use of common-filter
works perfectly fine, however when projecting an ajs-button
like:
<common-filter>
<ajs-button text="Inside of content projection"></ajs-button>
</common-filter>
This error is thrown:
Unhandled Promise rejection: [$compile:ctreq] Controller 'ajsFilter', required by directive 'ajsButton', can't be found!
Is there any way around this? I know that I can rewrite the surrounding classes, but many other apps use them and I need to be able to upgrade the apps gradually.
Working Example:
https://stackblitz.com/edit/ngupgradestatic-playground-uvr14t
Snippets above are from index.html
and common-filter.component.ts
. This is a (more-or-less) minimal example based on much more complicated components. I'm going with the downgradeModule
approach for performance reasons.
A maintainer, gkalpak, provided a workaround for this issue in the Github issue that I posted for this: https://github.com/angular/angular/issues/24846#issuecomment-404448494
In short, this is an issue with the order of initialization of the different controllers.
To get around it, you can make the parent require
optional and then use setTimeout
to wait until the parent controller is initialized:
this.$onInit = () => {
this.requireAjsFilterCtrl().then(() => console.log('!', !!this.ajsFilterCtrl));
}
this.requireAjsFilterCtrl = () => {
return new Promise(resolve => {
setTimeout(() => {
this.ajsFilterCtrl = this.ajsFilterCtrl || $element.controller('ajsFilter');
resolve(this.ajsFilterCtrl);
});
});
};
The workaround can be seen in action here: https://stackblitz.com/edit/ngupgradestatic-playground-a6zkwb