dimanche 1 mars 2020

Angular Strategy + Decorator template design without doing a lots of *ngIf

I've been working on a way of not doing a lots of *ngIf that depends on a type selected by the user

<select [(ngModel)]="type" name="type">
    <option value="a">Type A</option>
    <option value="b">Type B</option>
</select>

<div *ngIf="type === 'a'">
    logic...
</div>

<div *ngIf="type === 'b'">
    logic...
</div>

So i endedup doing this, and i want to know if there exists a simplier way

some-service.ts

export const TYPE_MAP = {};

export class SomeService {
    typeMap = TYPE_MAP;

    constructor() {
    }
}

type-manager.interface.ts

export interface TypeManager {
    someMethod();
}

type-manager.decorator.ts

export function TypeManagerDecorator(aType: string) {
    return function _TypeManagerDecorator<T extends { new(...args: any[]): TypeManager}>(constr: T) {
        TYPE_MAP[aType] = constr;
    };
}

manager-for-type-a.component.ts

@TypeManagerDecorator('a')
@Component({
    selector: 'app-manager-for-type-a',
    templateUrl: './manager-for-type-a.component.html',
    styleUrls: ['./manager-for-type-a.component.css'],
    viewProviders: [
        {
            provide: ControlContainer,
            useExisting: NgForm
        }
    ]
})
export class ManagerForTypeAComponent implements OnInit, TypeManager {

    constructor() {
    }

    ngOnInit() {
    };

    someMethod() {
    };
}

manager-for-type-b.component.ts

@TypeManagerDecorator('b')
@Component({
    selector: 'app-manager-for-type-b',
    templateUrl: './manager-for-type-b.component.html',
    styleUrls: ['./manager-for-type-b.component.css'],
    viewProviders: [
        {
            provide: ControlContainer,
            useExisting: NgForm
        }
    ]
})
export class ManagerForTypeBComponent implements OnInit, TypeManager {

    constructor() {
    }

    ngOnInit() {
    };

    someMethod() {
    };
}

main.component.html

<form #form="ngForm" (ngSubmit)="form.valid" autocomplete="off">

    <select [(ngModel)]="type" name="type" (ngModelChange)="changeTypeManager($event)">
        <option value="a">Type A</option>
        <option value="b">Type B</option>
    </select>


    <ng-container #container></ng-container>

</form>

main.component.ts

@Component({
    selector: 'app-main',
    templateUrl: './main.component.html',
    styleUrls: ['./main.component.css']
})
export class MainComponent implements OnInit, OnDestroy {

    @ViewChild('main', {read: ViewContainerRef, static: true})
    private mainContainer: ViewContainerRef;
    private componentReference: ComponentRef<any>;

    constructor(
        private aService: SomeService,
        private resolver: ComponentFactoryResolver
    ) {

    }

    ngOnInit() {
    }

    private changeTypeManager(aType: string) {
        if(this.componentReference) {
            this.componentReference.destroy();
        }

        if(!this.aService.typeMap[aType]) {
            throw new Error(`No class exists with the decorator @TypeManagerDecorator('${aType}')`);
        }

        const componentFactory = this.resolver.resolveComponentFactory(this.aService.typeMap[aType]);
        this.componentReference = this.mainContainer.createComponent(componentFactory);
    }

}

Aucun commentaire:

Enregistrer un commentaire