如何在Angular组件中读取所有@Input装饰器修饰的成员?
Hey there! I’ve struggled with this exact problem before—trying to use reflect or reflect-metadata directly just doesn’t work because Angular handles component metadata its own way. Let me break down two reliable approaches to get those @Input() properties.
Why Direct reflect-metadata Fails
Angular doesn’t store @Input() metadata in the standard reflect-metadata keys you might expect. Instead, during compilation, it generates internal metadata structures for components, which is where we need to look.
Approach 1: Use Angular’s Internal Component Metadata (Quick & Dirty)
Angular compiles every component with an internal ɵcmp property that holds all the component’s metadata, including inputs. This is straightforward, just note that it’s an internal API (so it might change between Angular versions, but it’s been stable for a while).
Example Code
First, here’s a sample component with inputs:
import { Component, Input } from '@angular/core'; @Component({ selector: 'app-user-profile', template: '<h1>{{username}}</h1><p>Age: {{userAge}}</p>' }) export class UserProfileComponent { @Input() username: string = ''; @Input('userAge') age: number = 0; // Using a custom binding name }
Now extract the inputs:
import { UserProfileComponent } from './user-profile.component'; // Access the internal component metadata const componentMeta = UserProfileComponent['ɵcmp']; // Extract input data: inputs is an array of [bindingName, propertyName] pairs const inputPairs = componentMeta.inputs; // Convert to a more usable map const inputMap = new Map(inputPairs); // Log the results console.log('Component Inputs:'); inputMap.forEach((propertyName, bindingName) => { console.log(`Binding Name (template): ${bindingName}, Component Property: ${propertyName}`); });
Output
Component Inputs: Binding Name (template): username, Component Property: username Binding Name (template): userAge, Component Property: age
Approach 2: Use Angular’s Public API (Stable for Production)
If you want a production-safe method that uses Angular’s public APIs, use ComponentFactoryResolver to resolve the component factory, which exposes input metadata.
Step 1: Create an Extractor Service
import { Injectable, ComponentFactoryResolver, ComponentFactory } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class InputMetadataExtractor { constructor(private cfr: ComponentFactoryResolver) {} getComponentInputs(componentClass: any): Array<{ bindingName: string; propertyName: string }> { const factory: ComponentFactory<any> = this.cfr.resolveComponentFactory(componentClass); // Map the factory's input metadata to a friendly format return factory.inputs.map(input => ({ bindingName: input.propName, // The name used in templates propertyName: input.templateName // The actual property name in the component class })); } }
Step 2: Use the Service in a Component/Service
import { Component, OnInit } from '@angular/core'; import { UserProfileComponent } from './user-profile.component'; import { InputMetadataExtractor } from './input-metadata-extractor.service'; @Component({ selector: 'app-input-demo', template: '<div></div>' }) export class InputDemoComponent implements OnInit { constructor(private inputExtractor: InputMetadataExtractor) {} ngOnInit(): void { const userProfileInputs = this.inputExtractor.getComponentInputs(UserProfileComponent); console.log('Stable API Inputs:', userProfileInputs); } }
Output
Stable API Inputs: [ { bindingName: "username", propertyName: "username" }, { bindingName: "userAge", propertyName: "age" } ]
Key Notes
- Internal API Caveat: The
ɵcmpproperty is not officially documented, so while it works for most Angular versions (v9+), be cautious when upgrading major versions. - Public API Benefit: The
ComponentFactoryResolverapproach is fully supported and won’t break with Angular updates, making it ideal for production apps. - Why Reflect Failed: Angular doesn’t expose
@Input()metadata via standardreflect-metadatamethods—it compiles metadata into its own internal structures, which is why we need these Angular-specific approaches.
内容的提问来源于stack exchange,提问作者Yang Rui

