I created Angular Library (ngx-wig) and I would like to provide an ability to extend its functionality by using plugins.
What would be the best place to declare plugin in Angular? (may be something like myLibModule.forRoot(..)
) and what type of instance should be plugin itself?
I solved same issue for AngularJs just by adding module for each plugin in which I register plugin by using configProvider of main module. Don't really like this solution because plugin registers itself, but it should be responsibility of applications where library is used.
UPDATE: related issue is opened on github here.
Both libraries and applications are modules a the end of the day. Their main difference is how they are built and deployed. A library can be packaged and published for easier reuse across projects. An application includes browser specific files for deploying and running in the browser.
I think you can provide users to use component as a plug-in. This component has to extends you abstract base plugin component.
For example clear-styles
plugin could look like
@Component({
selector: `nw-clear-styles-button`,
template: `
<button (click)="clearStyles($event)"
[disabled]="editMode || disabled"
class="nw-button clear-styles" title="Clear Styles">
Clear Styles
</button>`
})
export class NwClearStylesButtonComponent extends Ng2WigPluginComponent {
constructor() {
super();
}
clearStyles() {
const div = document.createElement('div');
div.innerHTML = this.content;
this.contentChange.emit(div.textContent);
}
}
format
plugin
@Component({
selector: `nw-formats-button`,
template: `
<select class="nw-select"
[(ngModel)]="format"
(ngModelChange)="execCommand('formatblock', format.value)"
[disabled]="editMode || disabled">
<option *ngFor="let format of formats" [ngValue]="format">{{ format.name }}</option>
</select>
`
})
export class NwFormatButtonComponent extends Ng2WigPluginComponent {
formats = [
{name: 'Normal text', value: '<p>'},
{name: 'Header 1', value: '<h1>'},
{name: 'Header 2', value: '<h2>'},
{name: 'Header 3', value: '<h3>'}
];
format = this.formats[0];
constructor() {
super();
}
}
where Ng2WigPluginComponent
is abstract base class provided by your library:
export abstract class Ng2WigPluginComponent {
execCommand: Function;
editMode: boolean;
content: string;
editModelChange: EventEmitter<boolean> = new EventEmitter();
contentChange: EventEmitter<string> = new EventEmitter();
}
So users can easily use declared in base class properties.
To register such plugins we can use mentioned by you forRoot
method. For that you need to
1) configure you library module like follows:
ng2wig.module.ts
@NgModule({
...
})
export class Ng2WigModule {
static forRoot(entryComponents: CustomButton[]) {
return {
ngModule: Ng2WigModule,
providers: [
Ng2WigToolbarService,
{provide: NG_WIG_CUSTOM_BUTTONS, useValue: entryComponents},
{provide: ANALYZE_FOR_ENTRY_COMPONENTS, multi: true, useValue: entryComponents},
]
};
}
}
where
NG_WIG_CUSTOM_BUTTONS
is your global library token to recognize provided plugins inside libraryng2wig-toolbar.service.ts
@Injectable()
export class Ng2WigToolbarService {
constructor(@Optional() @Inject(NG_WIG_CUSTOM_BUTTONS) customButtons: CustomButton[]) {
if (customButtons) {
customButtons.forEach(plugin => this.addCustomButton(plugin.pluginName, plugin.component));
}
}
ANALYZE_FOR_ENTRY_COMPONENTS
is angular global token to be able to load plugins dynamically2) Declare NwClearStylesButtonComponent
in declarations array of your AppModule
module
3) Pass it to the Ng2WigModule.forRoot
method
Ng2WigModule.forRoot([
{ pluginName: 'clear-styles', component: NwClearStylesButtonComponent },
{ pluginName: 'format', component: NwFormatButtonComponent }
])
And then main you task will be to dynamically generate your component by using ComponentFactoryResolver
and ViewContainerRef
(see ng2wig-plugin.directive.ts
in plunker below)
Plunker Example
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