question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Using providers instead of using a custom widget registry.

See original GitHub issue

Hi,

Currently A2SF uses ‘WidgetRegistry’ to provide your own custom widgets. Its possible to use the provider in a much more rigorous way to allow for a more descriptive API and to allow for more flexibility in the widget types.

There’s an interesting little quirk in Angular that actually allows you to register a component as a component and a provider. This allows you to inject in the component against a token like so:

import { DashboardWidget } from './dashboard-widget.interface';
import { DemoWidgetComponent } from './demo-widget.component';

@Component({
  selector: 'example-dashboard',
  template: `<div #target></div>`
})
export class DashboardComponent implements OnInit {

  // where we're going to store the rendered widgets.
  @ViewChild('target', {read: ViewContainerRef}) private container: ViewContainerRef;

  constructor(
    private resolver: ComponentFactoryResolver,
    // these are our widgets. we need to have them registered as providers and as components 
    // on the module. This allows us to gain a reference easily to them
    @Inject(DashboardWidget) private widgets: DashboardWidget[]
  ) {}

  public ngOnInit(): void {
    // this is the magic! boom! they see me creating widgets, they hating!!! 
    this.widgets.forEach((w) => {
      // this is the bit that ties it all together. usually people pass in a reference 
      // to the class. you can do the same thing by passing in the constructor. its all 
      // the same under the hood.
      const classType: Type<DashboardWidget> = <Type<DashboardWidget>> w.constructor;

      // then we inject it into our dom element.
      const componentFactory = this.resolver.resolveComponentFactory(classType);
      this.container.createComponent(componentFactory);
    });
  }

}

We create our token like so:

import { Component, Type } from '@angular/core';

export abstract class DashboardWidget {
    public readonly name: string;
}

and our component that extends that token:

import { Component } from '@angular/core';
import { DashboardWidget } from './dashboard-widget.interface';

@Component({
  template: '<div>hello is it me youre looking for?</div>'
})
export class DemoWidgetComponent extends DashboardWidget {
    public name: string = 'DummyWidget';
}

And then to wire it all up together:


import { DashboardWidget } from './dashboard-widget.interface';
import { DemoWidgetComponent } from './demo-widget.component';
import { DashboardComponent } from './dashboard.component';

@NgModule({
    declarations: [
      DashboardComponent,
      DemoWidgetComponent
    ],
    entryComponents: [
      DashboardComponent,
      DemoWidgetComponent
    ],
    providers : [
      {
          provide: DashboardWidget,
          useClass: DemoWidgetComponent,
          multi: true
      },
      {
          provide: DashboardWidget,
          useClass: DemoWidgetComponent,
          multi: true
      },
      {
          provide: DashboardWidget,
          useClass: DemoWidgetComponent,
          multi: true
      },
      {
          provide: DashboardWidget,
          useClass: DemoWidgetComponent,
          multi: true
      }
    ]
})
export class DashboardModule {}

In this case I use a multi binder because I don’t distinguish between widget types. In the case of the forms you can expose an abstract class that each of the widget must adhere to. This allows a developer to see exactly what is available to them to implement and what default values will be available from the schema.

It also allows you to keep providing your default widgets but they can be selectively overridden by a developer as needed.

I use schema form quite a lot at the moment and wouldn’t mind helping to make it a bit more flexible and modular. If you like the approach and would like me to work on a pull request for this then let me know.

Issue Analytics

  • State:open
  • Created 6 years ago
  • Comments:9

github_iconTop GitHub Comments

1reaction
jdrew1303commented, Apr 19, 2017

Hey @ebrehault,

Cool. 👍 It’ll probably be early next week before I can get a preliminary pull request in for handling forms like above.

It also gives you something that I only realized today. I allows you to load different components per module due to the the hierarchical injector (if you’re not using a multi-provider).

image

Ill give you a shout back when I get started on the core refactorings. It will probably involve modifying the core first and then recreating the original widgets. If youve any suggestions or ideas feel free to shout.

0reactions
gpessacommented, Jan 30, 2018

no… this was interesting

Read more comments on GitHub >

github_iconTop Results From Across the Web

The Widget Registry: How to Serve Reusable Interactive ...
The registry itself is a set of moving pieces that enable automation of the management of widgets, and it is formed by the...
Read more >
Recommendations for developing widgets
When developing custom widgets, keep these recommendations in mind for optimal performance, scalable development, and a good user ...
Read more >
Simple app state management - Flutter documentation
The catalog screen includes a custom app bar ( MyAppBar ) and a scrolling view of many list items ( MyListItems ). Here's...
Read more >
Implement a custom configuration provider - .NET
With the sample app in place, define an options object to represent the widget settings. C# Copy. namespace CustomProvider.Example ...
Read more >
How to add custom widget to C1?
The main task is creation and registration of a Widget Provider. The Widget Providers can expand on the list of visual widgets that...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found