fix(core): set correct context for inject() for component ctors#45991
fix(core): set correct context for inject() for component ctors#45991alxhub wants to merge 1 commit intoangular:mainfrom
Conversation
The `inject()` function was introduced with Ivy to support imperative injection in factory/constructor contexts, such as directive or service constructors as well as factory functions defined in `@Injectable` or `InjectionToken`. However, `inject()` in a component/directive constructor did not work due to a flaw in the logic for creating the internal factory for components/directives. The original intention of this logic was to keep `ɵɵdirectiveInject` tree- shakable for applications which don't use any component-level DI. However, this breaks the `inject()` functionality for component/directive constructors. This commit fixes that issue and adds tests for all the various cases in which `inject()` should function. As a result `ɵɵdirectiveInject` is no longer tree-shakable, but that's totally acceptable as any application that uses `*ngIf` or `*ngFor` already contains this function. It's possible to change how `inject()` works to restore this tree-shakability if needed.
|
Caretaker: CI size difference is as expected. |
|
This PR was merged into the repository by commit 9c1735b. |
The `inject()` function was introduced with Ivy to support imperative injection in factory/constructor contexts, such as directive or service constructors as well as factory functions defined in `@Injectable` or `InjectionToken`. However, `inject()` in a component/directive constructor did not work due to a flaw in the logic for creating the internal factory for components/directives. The original intention of this logic was to keep `ɵɵdirectiveInject` tree- shakable for applications which don't use any component-level DI. However, this breaks the `inject()` functionality for component/directive constructors. This commit fixes that issue and adds tests for all the various cases in which `inject()` should function. As a result `ɵɵdirectiveInject` is no longer tree-shakable, but that's totally acceptable as any application that uses `*ngIf` or `*ngFor` already contains this function. It's possible to change how `inject()` works to restore this tree-shakability if needed. PR Close #45991
| template: '{{value}}', | ||
| }) | ||
| class TestCmp { | ||
| cdr = inject(ChangeDetectorRef); |
There was a problem hiding this comment.
@alxhub Hello, thank you for this PR! Really great job!
I want to say you about, is this working with custom decorator?
const Autowired = (target: any, memberName: string) => {
Object.defineProperty(target, memberName, {
set: (newValue: any) => {
target[memberName] = newValue;
},
get: () => inject(ChangeDetectorRef)
});
};
@Component({
standalone: true,
selector: 'test-cmp',
template: '{{value}}',
})
class TestCmp {
@Autowired() cdr!: ChangeDetectorRef;
}There was a problem hiding this comment.
No, that particular code wouldn't work as inject is not called during construction, but only in the property's getter. The injection context won't be available at that point in time.
There was a problem hiding this comment.
What code is then valid for writing your own decorator? Tell me please
There was a problem hiding this comment.
Property decorators don't get to add logic to run during construction, so you can't do that. There's probably ways to get things to work with a supporting class decorator, but I wouldn't recommend that.
Really just use
readonly cdr = inject(ChangeDetectorRef);which gets you type-safe code without size nor runtime overhead and further magic (you have an additional problem to solve w.r.t. the token to inject, which in your example is hardcoded as ChangeDetectorRef in Autowired).
|
Looks like this caused a breakage. Reverting and re-opening. |
This change switches the cdk menu from using constructor injection to using the `inject` function. This was enabled by angular/angular#45991. This approach has a number of advantages: * We can add and remove injectables without changing the public constructor signature * It reduces the boilerplate of passing arguments through `super` * It avoids long/messy constructor blocks in favor of simpler member definitions.
This change switches the cdk menu from using constructor injection to using the `inject` function. This was enabled by angular/angular#45991. This approach has a number of advantages: * We can add and remove injectables without changing the public constructor signature * It reduces the boilerplate of passing arguments through `super` * It avoids long/messy constructor blocks in favor of simpler member definitions. * This sidesteps a common pitfall of making `@Optional` injection (`null` if not provided) as an optional parameter (`undefined` if not provided)`.
… using the `inject` function. This was enabled by angular/angular#45991. This approach has a number of advantages: * We can add and remove injectables without changing the public constructor signature * It reduces the boilerplate of passing arguments through `super` * It avoids long/messy constructor blocks in favor of simpler member definitions. * This sidesteps a common pitfall of making `@Optional` injection (`null` if not provided) as an optional parameter (`undefined` if not provided)`.
This change switches the cdk menu from using constructor injection to using the `inject` function. This was enabled by angular/angular#45991. This approach has a number of advantages: * We can add and remove injectables without changing the public constructor signature * It reduces the boilerplate of passing arguments through `super` * It avoids long/messy constructor blocks in favor of simpler member definitions. * This sidesteps a common pitfall of making `@Optional` injection (`null` if not provided) as an optional parameter (`undefined` if not provided)`.
This change switches the cdk menu from using constructor injection to using the `inject` function. This was enabled by angular/angular#45991. This approach has a number of advantages: * We can add and remove injectables without changing the public constructor signature * It reduces the boilerplate of passing arguments through `super` * It avoids long/messy constructor blocks in favor of simpler member definitions. * This sidesteps a common pitfall of making `@Optional` injection (`null` if not provided) as an optional parameter (`undefined` if not provided)`.
This change switches the cdk menu from using constructor injection to using the `inject` function. This was enabled by angular/angular#45991. This approach has a number of advantages: * We can add and remove injectables without changing the public constructor signature * It reduces the boilerplate of passing arguments through `super` * It avoids long/messy constructor blocks in favor of simpler member definitions. * This sidesteps a common pitfall of making `@Optional` injection (`null` if not provided) as an optional parameter (`undefined` if not provided)`.
This change switches the cdk menu from using constructor injection to using the `inject` function. This was enabled by angular/angular#45991. This approach has a number of advantages: * We can add and remove injectables without changing the public constructor signature * It reduces the boilerplate of passing arguments through `super` * It avoids long/messy constructor blocks in favor of simpler member definitions. * This sidesteps a common pitfall of making `@Optional` injection (`null` if not provided) as an optional parameter (`undefined` if not provided)`.
This change switches the cdk menu from using constructor injection to using the `inject` function. This was enabled by angular/angular#45991. This approach has a number of advantages: * We can add and remove injectables without changing the public constructor signature * It reduces the boilerplate of passing arguments through `super` * It avoids long/messy constructor blocks in favor of simpler member definitions. * This sidesteps a common pitfall of making `@Optional` injection (`null` if not provided) as an optional parameter (`undefined` if not provided)`.
This change switches the cdk menu from using constructor injection to using the `inject` function. This was enabled by angular/angular#45991. This approach has a number of advantages: * We can add and remove injectables without changing the public constructor signature * It reduces the boilerplate of passing arguments through `super` * It avoids long/messy constructor blocks in favor of simpler member definitions. * This sidesteps a common pitfall of making `@Optional` injection (`null` if not provided) as an optional parameter (`undefined` if not provided)`.
This change switches the cdk menu from using constructor injection to using the `inject` function. This was enabled by angular/angular#45991. This approach has a number of advantages: * We can add and remove injectables without changing the public constructor signature * It reduces the boilerplate of passing arguments through `super` * It avoids long/messy constructor blocks in favor of simpler member definitions. * This sidesteps a common pitfall of making `@Optional` injection (`null` if not provided) as an optional parameter (`undefined` if not provided)`.
This change switches the cdk menu from using constructor injection to using the `inject` function. This was enabled by angular/angular#45991. This approach has a number of advantages: * We can add and remove injectables without changing the public constructor signature * It reduces the boilerplate of passing arguments through `super` * It avoids long/messy constructor blocks in favor of simpler member definitions. * This sidesteps a common pitfall of making `@Optional` injection (`null` if not provided) as an optional parameter (`undefined` if not provided)`.
This change switches the cdk menu from using constructor injection to using the `inject` function. This was enabled by angular/angular#45991. This approach has a number of advantages: * We can add and remove injectables without changing the public constructor signature * It reduces the boilerplate of passing arguments through `super` * It avoids long/messy constructor blocks in favor of simpler member definitions. * This sidesteps a common pitfall of making `@Optional` injection (`null` if not provided) as an optional parameter (`undefined` if not provided)`.
This change switches the cdk menu from using constructor injection to using the `inject` function. This was enabled by angular/angular#45991. This approach has a number of advantages: * We can add and remove injectables without changing the public constructor signature * It reduces the boilerplate of passing arguments through `super` * It avoids long/messy constructor blocks in favor of simpler member definitions. * This sidesteps a common pitfall of making `@Optional` injection (`null` if not provided) as an optional parameter (`undefined` if not provided)`.
This change switches the cdk menu from using constructor injection to using the `inject` function. This was enabled by angular/angular#45991. This approach has a number of advantages: * We can add and remove injectables without changing the public constructor signature * It reduces the boilerplate of passing arguments through `super` * It avoids long/messy constructor blocks in favor of simpler member definitions. * This sidesteps a common pitfall of making `@Optional` injection (`null` if not provided) as an optional parameter (`undefined` if not provided)`.
|
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |


The
inject()function was introduced with Ivy to support imperativeinjection in factory/constructor contexts, such as directive or service
constructors as well as factory functions defined in
@InjectableorInjectionToken. However,inject()in a component/directive constructordid not work due to a flaw in the logic for creating the internal factory
for components/directives.
The original intention of this logic was to keep
ɵɵdirectiveInjecttree-shakable for applications which don't use any component-level DI. However,
this breaks the
inject()functionality for component/directiveconstructors.
This commit fixes that issue and adds tests for all the various cases in
which
inject()should function. As a resultɵɵdirectiveInjectis nolonger tree-shakable, but that's totally acceptable as any application that
uses
*ngIfor*ngForalready contains this function. It's possible tochange how
inject()works to restore this tree-shakability if needed.