How to handle/provide @Input
and @Output
properties for dynamically created Components in Angular 2?
The idea is to dynamically create (in this case) the SubComponent when the createSub method is called. Forks fine, but how do I provide data for the @Input
properties in the SubComponent. Also, how to handle/subscribe to the @Output
events the SubComponent provides?
Example: (Both components are in the same NgModule)
AppComponent
@Component({ selector: 'app-root' }) export class AppComponent { someData: 'asdfasf' constructor(private resolver: ComponentFactoryResolver, private location: ViewContainerRef) { } createSub() { const factory = this.resolver.resolveComponentFactory(SubComponent); const ref = this.location.createComponent(factory, this.location.length, this.location.parentInjector, []); ref.changeDetectorRef.detectChanges(); return ref; } onClick() { // do something } }
SubComponent
@Component({ selector: 'app-sub' }) export class SubComponent { @Input('data') someData: string; @Output('onClick') onClick = new EventEmitter(); }
The @Input is a decorator to mark an input property. The @Output is a decorator to mark an output property. The @Input is used to define an input property to achieve component property binding. The @Output is used to define output property to achieve custom event binding.
We use these decorators to pass data from parent to child component & vice versa. @Input defines the input property in the component, which the parent component can set. The @output defines the output property (event), which we raise in the child component using the EventEmitter . The parent listens to these events.
@Input() and @Output() give a child component a way to communicate with its parent component. @Input() lets a parent component update data in the child component. Conversely, @Output() lets the child send data to a parent component.
What dynamic components are. Dynamic means, that the components location in the application is not defined at buildtime. That means, that it is not used in any angular template. Instead, the component is instantiated and placed in the application at runtime.
You can easily bind it when you create the component:
createSub() { const factory = this.resolver.resolveComponentFactory(SubComponent); const ref = this.location.createComponent(factory, this.location.length, this.location.parentInjector, []); ref.someData = { data: '123' }; // send data to input ref.onClick.subscribe( // subscribe to event emitter (event: any) => { console.log('click'); } ) ref.changeDetectorRef.detectChanges(); return ref; }
Sending data is really straigthforward, just do ref.someData = data
where data
is the data you wish to send.
Getting data from output is also very easy, since it's an EventEmitter
you can simply subscribe to it and the clojure you pass in will execute whenever you emit()
a value from the component.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With