Skip to content

laidav/ng-mix

Repository files navigation

NgMix

Angular schematic library for generating TypeScript mixins designed for Angular Components.

TypeScript mixins are then used to implement a composition pattern to share common logic across Angular components.

Table of Contents

  1. Requirements
  2. Installation
  3. Usage
    1. CLI Command
    2. Mixin Overview
    3. Usage with Component
    4. Composing with Mixins
    5. Angular Lifecycle Hooks
    6. Angular @Input and @Outputs Decorators
    7. Angular Services

Requirements

  • Angular 8 or higher

Installation

Install via npm:

npm i ng-mix

Usage

CLI Command

  • To create a mixin run the following command

     ng g ng-mix:mixin
    
  • You will be prompted to give your mixin a name

Mixin Overview

  • The following code will be generated (sample.mixin.ts)

    import { Injectable, OnInit } from '@angular/core';
    import { BaseInjectorConstructor } from 'ng-mix';
    
    export const SampleMixin = <Tbase extends BaseInjectorConstructor>(superClass: Tbase) => {
    
     @Injectable()
     class Sample extends superClass implements OnInit {
     
       // You can inject services from the BaseClassInjector i.e
       // myService = this.injector.get(MyService);
    
       ngOnInit(): void {
         //Call super's lifecycle method
         super.ngOnInit();
    
         //Implementation here
       }		
     }
    
     return Sample;
    }
  • All mixins will inherit BaseClassInjector

Back to top


Usage with Component

  • Extend your component class with the mixin.
import { Component, Injector } from '@angular/core';
import { SampleMixin } from './sample.mixin';
import { Base } from 'ng-mix';

@Component({
  selector: 'app-component',
  templateUrl: './app-component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent extends SampleMixin(Base) {
  
  constructor(public injector: Injector) {
    //Provides injector to the mixin(s) for access to Angular Services via DI
    super(injector);
  }
}
  • Provide ng-mix's Base class to the mixin.
  • Provide the injector to the mixin(s) by passing it into the super call in the constructor.

Back to top


Composing with Mixins

  • You can mix mixins together as shown
    const Mixins = SampleOneMixin(SampleTwoMixin(Base));
    export class AppComponent extends Mixins {
     ...
    };

Back to top


Angular Lifecycle Hooks

  • When implementing an Angular lifecycle hook method on a mixin or component using mixin(s), always call super.[ lifecycle method] when mixins are used to ensure the lifecycle methods for all mixins are invoked.

     //sample.mixin.ts
    
     export const SampleMixin = <Tbase extends BaseInjectorConstructor>(superClass: Tbase) => {
    
       @Injectable()
       class Sample extends superClass {
         ...
         ngOnInit(): void {
           super.ngOnInit(); // Make sure to call super lifecycle method!
         //Implementation here
         }		
             ...
       }
    
       return Sample;
     }
     //app.component.ts
    
     @Component({
       ...
     })
     export class AppComponent extends SampleMixin(Base) { 
       ...
       ngOnInit(): void {
         super.ngOnInit(); // Make sure to call super lifecycle method!
         //Implementation here
       }		
       ...
     }

Back to top


Angular @Input and @Outputs Decorators

  • If @Input/@Output decorators are used in mixins, they will need to be declared in the @Component decorator of the component.

     //sample.mixin.ts
    
     export const SampleMixin = <Tbase extends BaseInjectorConstructor>(superClass: Tbase) => {
    
       @Injectable()
       class Sample extends superClass {
         @Input sampleInput = '';
         @Output sampleOutput = new EventEmitter<any>();
         
         ...
       }
    
       return Sample;
     }
     //app.component.ts
    
     @Component({
       ...
       inputs: ['sampleInput'],
       outputs: ['sampleOutput']
     })
     export class AppComponent extends SampleMixin(Base) { ... }

Back to top


Angular Services

  • Services can be accessed via Angular's Injector which is available in every mixin class.
     //sample.mixin.ts
     import { SampleService } from './sample.service.ts'
    
     export const SampleMixin = <Tbase extends BaseInjectorConstructor>(superClass: Tbase) => {
    
       @Injectable()
       class Sample extends superClass {
    
         sampleService = this.injector.get(SampleService);
         
         ...
       }
    
       return Sample;
     }