dependencies dependencies cluster_WidgetsModule cluster_WidgetsModule_declarations cluster_WidgetsModule_exports cluster_WidgetsModule_providers RccWidgetComponent RccWidgetComponent WidgetsModule WidgetsModule RccWidgetComponent->WidgetsModule RccWidgetComponent RccWidgetComponent WidgetsModule->RccWidgetComponent WidgetsService WidgetsService WidgetsService->WidgetsModule

File

lib/common/src/widgets/widgets.module.ts

Description

This Module manages widgets.

A widget is a component that is dynamically added at runtime depending on the context. Modules can register widgets to the WidgetModule. Every widget component comes with a static widgetMatch method (see WidgetComponent), that tells the app how well the widget fits the context.

This module does NOT provide any widgets by itself, it only provides the infrastructure. Tutorial: How to use widgets

Declarations

Providers

Methods

Static forChild
forChild(widgetComponents: WidgetComponent<any>[])

Registers WidgetComponents, when importing this module. Modules providing their own widget types will most likly have their own static method to register WidgetComponents, which in turn will make use of the same InjectionToken as this method.

Parameters :
Name Type Optional
widgetComponents WidgetComponent<any>[] No
Returns : ModuleWithProviders<WidgetsModule>

How to use Widgets

Widgets are a kind of dynamic Components {@link WidgetComponent}. They come in handy if the decision, which component to display, has to be made at runtime, yet when coding you do not know all the options yet:

Say you have a module for data visualization, you built a couple of components that visualize data for you. A bar chart may be best suited for visualizing some data. A table may be the best match for something else and a line chart for yet another dataset.

You could create a template that checks each of the three cases and displays the according component. But if another Module (perhaps by another author) has a nicer bar chart or a completely different - but better suited - way to display certain datasets, you'd have to change your template in order to accomodate the new component.

With widgets instead you write your template and mark the location where you want the data visualization to be placed. Then register components together with a {@link WidgetMatchFn}. Your data is represented as a {@link WidgetControl} and the {@link WidgetMatchFn} determines how well your component can handle the data. The best matchig component will then be displayed. This way you can add your original three components moving the checks from the template into the {@link WidgetMatchFn}. Every other module can now provide additional components for your visualization case by registering new {@link WidgetComponents}.

Enable widgets in your module

WidgetControl

First of all create a model of the data you want to present with your widgets by extending {@WidgetControl}. Lets say we have color sets in mind:

    export class ColorSchemeWidgetControl extends WidgetControl{


        constructor(
            public name				: string,
            public colors			: [number, number, number, number][],
            public darkModeColors	: [number, number, number, number][],
            public tags				: string[]		
        ){
            super()
        }

        /**
         * Activate this color scheme for the runnig app.
         */ 
        activateSheme(){ ... } 
    }

Your model can include methods or anything else you want your widgets to make use of.

Use in a component

example.component.html:


    <h2> Here comes a widget </h2>
    <rcc-widget
        [widgetControl] = "myWidgetControl"
    >
    </rcc-widget>

exmaple.component.ts:

    @Compontent({
        template : './example.component.html'
    })
    export class ExampleComponent {

        myWidgetControl: ColorSchemeWidgetControl

        constructor(){
            this.myWidgetControl = 	new ColorSchemeWidgetControl(
                                        'My Color Scheme',
                                        [ [255, 255, 255, 1], [255, 0, 0, 1], [255, 100, 0, 1] ],
                                        [ [0, 0, 0, 1], [100, 0, 0, 1], [100, 50, 0, 1] ],
                                        []

                                    )
        }
    }

Up to this point your component won't show anything. In order to see something, you (or someone else) has to register widgets with you new Control class (ColorSchemeWidgetControl).

Provide Widgets

Creating a custom widget

This time we want to add a custom {@link WidgetComponent} to the module we just prepared (or someone else's module that is widget ready.) We figure out which type of {@link WidgetControl} we should use (here it is ColorSchemeWidgetControl), then we define our new custom widget by extending the {@link WidgetComponent} class.

    import	{	Component 					} from '@angular/core'
    import	{	WidgetComponent				} from ''
    import	{	ColorSchemeWidgetControl 	} from 'color-schemes'

    @Component({
        template: 	`
                        <table>
                            <tr *ngFor = let color of widgetControl.colors><td>{{color}}</td></tr>
                            <tr><td>---</td></tr>
                            <tr *ngFor = let color of widgetControl.darkModeColors><td>{{color}}</td></tr>
                        </table>
                    ` 
    })
    export class TableColorSchemeWidgetComponent extends WidgetComponent<ColorSchemeWidgetControl> {

        static controlType = ColorSchemeWidgetControl

        static widgetMatch(widgetControl: ColorSchemeWidgetControl){
            return 0
        }

        constructor(public widgetControl: ColorSchemeWidgetControl){
            super(widgetControl)
        }

    }

This custom widget just lists all the colors of the color scheme in a table. Pretty boring, but a good start for the first widget, because this one will be able to visualize all kinds of colorShemeControls. That's also why .widgetMatch always returns 0. This widgets can handle all controls, but is not very good at it.

Besides the .widgetMatch() static method this works exactly like a normal component. If you wanted to, you could inject other injectables into the constructor. In order to get the fitting control you have to use the matching type of {@link WidgetControl} for injection. In this case: ColorSchemeWidgetControl.

Dont forget to add the static property controlType. Without that typescript complains and wouldn't know where to place your widget.

A more complex widget might look like this:

    import 	{ ColorSchemeWidgetComponent, ColorSchemeWidgetControl } from 'color-schemes'
    import	{ Component } from '@angular/core'

    @Component({
        template: 	`
                        <div 
                            style 	= "width: 10rem"
                            (click)	= "toggleMode()"
                        >

                            <div 
                                *ngFor	= "let color of (mode == 'dark' ? widgetControl.darkModeColors : widgetControl.colors)"
                                style	= "width: 2rem; height: 2rem; background-color:rgba({{color[0]}}, {{color[1]}}, {{color[2]}}, {{color[3]}})"
                            ></div>

                        </div

                    ` 
    })
    export class SwitchColorSchemeWidgetComponent extends WidgetComponent<ColorSchemeWidgetControl> {

        static controlType = ColorSchemeWidgetControl

        static widgetMatch(widgetControl: ColorSchemeWidgetControl){

            return 	this.widgetControl.darkModeColors
                    ?	1
                    :	-1

        }


        public mode = 'light'

        constructor( public widgetControl: ColorSchemeWidgetControl ){
            super()
        }

        toggleMode(){

            this.mode =	this.mode == 'light'
                        ?	'dark'
                        :	'light'

        }

    }

This Widget shows the actual colors in colored boxes and can switch between dark and light mode. If a ColorSchemeControl has no .darkModeColor values, this widget will leave the job to another widget, thus widgetMatch returns 1 when darkModeColors are present and -1 if not. The TableColorSchemeWidgetComponent will take over in the latter case, if no other widgets are registered.

Register a custom widget

Before any of your widgets show up at any point, you have to register them:

    import 	{
                WidgetsModule,
                provideWidget
            } 											from '@rcc/common'
    import 	{ 	TableColorSchemeWidgetComponent 	} 	from './table-color-scheme-widget.component'
    import 	{ 	SwitchColorSchemeWidgetComponent 	} 	from './switch-color-scheme-widget.component'

    @Module({
        providers:[
            ...,
            WidgetsModule,
            provideWidget(TableColorSchemeWidgetComponent),
            provideWidget(SwitchColorSchemeWidgetComponent)
        ]
    })

import 	{ 	
			ModuleWithProviders,
			NgModule,			
		}							from '@angular/core'

import	{
			CommonModule,
		}							from '@angular/common'

import	{
			WIDGETS,
			WidgetComponent

		}							from './widgets.commons'

import	{
			RccWidgetComponent
		}							from './widget.component'


import	{
			WidgetsService
		}							from './widgets.service'

/**
 * This Module manages widgets. 
 * 
 * A widget is a component that is dynamically added at runtime depending on the context. 
 * Modules can register widgets to the WidgetModule. Every widget component comes with a static
 * widgetMatch method (see {@link WidgetComponent}), that tells the app how well the widget fits the context.
 * 
 * This module does NOT provide any widgets by itself, it only provides the infrastructure.
 * {@link modules/WidgetsModule.html#readme | Tutorial: How to use widgets}
 */ 
@NgModule({

	imports: [
		CommonModule
	],
	providers:[
		WidgetsService
	],
	declarations :[
		RccWidgetComponent,
	],
	exports: [
		RccWidgetComponent,
	]

})
export class WidgetsModule {

	/**
	 * Registers {@link WidgetComponent}s, when importing this module. 
	 * Modules providing their own widget types will most likly have their own static method to register {@link WidgetComponents}, 
	 * which in turn will make use of the same {@link InjectionToken} as this method.	
	 * 
	 * @deprecated  
	 */	 
	static forChild(

		widgetComponents: WidgetComponent<any>[]

	) : ModuleWithProviders<WidgetsModule> {

		console.warn('WidgetsModule.forChild() is deprecated, use provideWidget() instead.')

		return 	{
					ngModule: 	WidgetsModule,
					providers: 	[
									widgetComponents.map( widgetComponent => ({
										provide: 	WIDGETS,
										useValue:	widgetComponent,
										multi:		true
									}))
								]
				}
	}
}

results matching ""

    No results matching ""