Directives for auto binding Input() and Output() from host component to inner in Angular9+ application
Installation
npm i --save ngx-bind-io
Example
Without auto binding inputs and outputs
<component-name (start)="onStart()" [isLoading]="isLoading$ | async" [propA]="propA" [propB]="propB"> </component-name>
With auto binding inputs and outputs
<component-name [bindIO]> </component-name>
app.module.ts
import { NgxBindIOModule } from 'ngx-bind-io';
import { InnerComponent } from './inner.component';
import { HostComponent } from './host.component';
@NgModule({
...
imports: [
...
NgxBindIOModule.forRoot(), // in child modules import as "NgxBindIOModule"
...
]
declarations: [
...
InnerComponent,
HostComponent
...
],
...
})
export class AppModule { }
inner.component.ts
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
@Component({
selector: 'inner',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div *ngIf="isLoading">Loading... (5s)</div>
<button (click)="onStart()">Start</button> <br />
{{ propA }} <br />
{{ propB }}
`
})
export class InnerComponent {
@Input()
isLoading: boolean;
@Input()
propA = 'Prop A: not defined';
@Input()
propB = 'Prop B: not defined';
@Output()
start = new EventEmitter();
onStart() {
this.start.next(true);
}
}
base-host.component.ts
import { BehaviorSubject } from 'rxjs';
export class BaseHostComponent {
isLoading$ = new BehaviorSubject(false);
onStart() {
this.isLoading$.next(true);
setTimeout(() => this.isLoading$.next(false), 5000);
}
}
host.component.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { BaseHostComponent } from './base-host.component';
@Component({
selector: 'host',
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<inner [bindIO]></inner>
`
})
export class HostComponent extends BaseHostComponent {
propA = 'Prop A: defined';
propB = 'Prop B: defined';
}
Debug
For global debug all bindings
import { NgxBindIOModule } from 'ngx-bind-io';
@NgModule({
...
imports: [
...
NgxBindIOModule.forRoot({debug: true})
...
],
...
})
export class AppModule { }
For debug on one place
<comp-name [bindIO]="{debug:true}"></comp-name>
Rules for detect inputs and outputs
Custom rules for detect output method
my-ngx-bind-outputs.service.ts
import { Injectable } from '@angular/core';
import { IBindIO, NgxBindOutputsService } from 'ngx-bind-io';
@Injectable()
export class MyNgxBindOutputsService extends NgxBindOutputsService {
checkKeyNameToOutputBind(directive: Partial<INgxBindIODirective>, hostKey: string, innerKey: string) {
const outputs = directive.outputs;
const keyWithFirstUpperLetter =
innerKey.length > 0 ? innerKey.charAt(0).toUpperCase() + innerKey.substr(1) : innerKey;
return (
(hostKey === `on${keyWithFirstUpperLetter}` &&
outputs.hostKeys.indexOf(`on${keyWithFirstUpperLetter}Click`) === -1 &&
outputs.hostKeys.indexOf(`on${keyWithFirstUpperLetter}ButtonClick`) === -1) ||
(hostKey === `on${keyWithFirstUpperLetter}Click` &&
outputs.hostKeys.indexOf(`on${keyWithFirstUpperLetter}ButtonClick`) === -1) ||
hostKey === `on${keyWithFirstUpperLetter}ButtonClick`
);
}
}
app.module.ts
import { NgxBindOutputsService, NgxBindIOModule } from 'ngx-bind-io';
import { MyNgxBindOutputsService } from './shared/utils/my-ngx-bind-outputs.service';
import { InnerComponent } from './inner.component';
import { HostComponent } from './host.component';
@NgModule({
declarations: [AppComponent],
imports: [
...
NgxBindIOModule,
...
],
declarations: [
AppComponent,
InnerComponent,
HostComponent,
...
],
providers: [
...
{ provide: NgxBindOutputsService, useClass: MyNgxBindOutputsService },
...
],
bootstrap: [AppComponent]
})
export class AppModule { }
Links
Demo - Demo application with ngx-bind-io.
Stackblitz - Simply sample of usage on https://stackblitz.com
Top comments (0)