npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ngx-decorate

v3.0.3

Published

Useful decorators for Angular 2 and above

Downloads

31

Readme

NpmVersion Travis (.com) branch Coveralls github branch CodeFactor codebeat badge Greenkeeper badge

Useful decorators for Angular 2 and above. Full API docs available here


Table of Contents

Installation

npm install ngx-decorate

Or use the CDN version:

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/ngx-decorators.umd.min.js"></script>

The AMD name is NgxDecorate.

Basic principle

Angular apps have a lot of repetitive code - completing subjects, unsubscribing, triggering change detection etc. This library hooks into a component's OnInit and OnDestroy hooks and does all the magic for you. If your component already has an OnInit or OnDestroy hook, it will still be called.

IMPORTANT

AoT compilation notice

For the decorators to work in AoT mode the classes must contain the ngOnInit and ngOnDestroy methods. It is currently not possible to provide this functionality in the form of a Webpack plugin because @ngtools/webpack ignores loader input. Until this ceases to be the case you can use the ngx-decorate-preprocessor tool.

Class inheritance

The decorators might not work or work incorrectly if used from within a subclass. Only use the decorators for classes that do not extend other classes.

Decorators

CdrProp - automatically trigger change detection

Before:

@Component({})
export class Foo {
  private _prop: string;

  public constructor(private readonly cdr: ChangeDetectorRef) {}
  
  public get prop(): string {
    return this._prop;
  }
  
  public set prop(v: string) {
    this._prop = v;
    this.cdr.markForCheck();
  }
}

After:

@Component({})
export class Foo {
  @CdrProp('cdr')
  public prop: string;

  public constructor(private readonly cdr: ChangeDetectorRef) {}
}

API:

export declare type ConfEnum = Pick<PropertyDescriptor, 'configurable' | 'enumerable'>;

export interface CdrPropConfig {
    /** Default value to set on the prototype */
    default?: any;
    /** Partial property descriptor */
    desc?: ConfEnum;
    /**
     * Key of a property used for tracking whether the component's been destroyed
     * to prevent errors caused by triggering change detection on a destroyed component.
     */
    destroyed?: PropertyKey;
}
/**
 * Call .markForCheck() on the change detector ref whenever this property is written to.
 * This decorator does <b>not</b> require the class to be decorated with {@link NgxDecorate}
 *
 * @param propName Property at which the change detector can be found
 * @param conf Optional configuration
 */
export declare function CdrProp(propName: PropertyKey, conf?: CdrPropConfig): PropertyDecorator;

Complete - automatically complete a subject

The property can hold either a single subject or an array of subjects.

Before:

@Component({})
export class Foo implements OnDestroy {
  private _subjects: Subject<any>[] = [];
  private _oneSubject: Subject<any>;
  
  public ngOnDestroy(): void {
    if (this._oneSubject) {
      this._oneSubject.complete();
    }
    for (const subj of this._subjects) {
      subj.complete();
    }
  }
}

After:

@NgxDecorate()
@Component({})
export class Foo {
  @Complete()
  private _subjects: Subject<any>[] = [];
  @Complete()
  private _oneSubject: Subject<any>;
}

API:

/**
 * Automatically completes the subjects and event emitters at this property.
 * The property can be either a single object or an array of objects.
 */
export declare function Complete(): PropertyDecorator;

LazySubject - create a subject lazily

Creating subjects within a constructor on the OnInit hook can sometimes be wasteful if there's a chance they won't be used. Instantiate your subjects lazily and make sure you only allocate resources to what you actually need! The subject will only be created once; any further access will happen as if it were a regular property.

Code:

@NgxDecorate()
@Component({})
export class Foo {
  
  @LazySubject()
  public get someSubject(): Subject<string> {
    return new Subject<string>();
  }
}

Equivalent logic:

@Component({})
export class Foo implements OnDestroy {
  private _subjects: Subject<any>[] = [];
  
  public get someSubject(): Subject<string> {
    const value = new Subject<string>();
    this._subjects.push(value);
    Object.defineProperty(this, 'someSubject', {value});
    
    return value;
  }
  
  public ngOnDestroy(): void {
    for (const subj of this._subjects) {
      subj.complete();
    }
  }
}

API:

/**
 * Decorate a getter that returns a subject. The subject will automatically get completed
 * when the component/service/pipe is destroyed.
 */
export declare function LazySubject(): MethodDecorator;

SubjectSetter - mirror a property to a subject

Note: Setting the default value will not work if the class does not support OnInit hooks, i.e. don't use the option on services and pipes.

Additionally, the option should not be used on component inputs as the input would get overridden during the OnInit hook.

Before:

@Component({})
export class Foo implements OnInit, OnDestroy {
  private _name: string;
  
  private _name$: Subject<string> = new Subject<string>();
  
  public set name(v: string) {
    this._name = v;
    this._name$.next(v);
  }
  
  public get name(): string {
    return this._name;
  }
  
  public ngOnInit(): void {
    this.name = 'foo';
  }
  
  public ngOnDestroy(): void {
    this._name$.complete();
  }
}

After:

@NgxDecorate()
@Component({})
export class Foo {
  @SubjectSetter('_name$', {default: 'foo'})
  public name: string;
  
  @Complete()
  private _name$: Subject<string> = new Subject<string>();
}

API (see ConfEnum docs under @CdrProp):

export interface SubjectSetterConfig {
    /** Default value to set on the prototype */
    default?: any;
    /** Partial property descriptor */
    desc?: ConfEnum;
}
/**
 * Mark the property as a subject setter. When written to, it will call .next(value) on the subject.
 * The decorator's <b>default</b> config option only works on items that make use of the OnInit hook,
 * i.e. it will <b>not</b> work for services and pipes.
 *
 * Because the <b>default</b> config option utilises the OnInit hook, it should not be used on
 * properties that are component inputs as the input would get overridden during the hook.
 *
 * @param subjectPropName Name of the property at which the subject resides
 * @param conf Optional configuration
 */
export declare function SubjectSetter(subjectPropName: PropertyKey, conf?: SubjectSetterConfig): PropertyDecorator;

SubscribeTo - set a property's value from an observable

Effectively the opposite of @SubjectSetter

Before:

@Component({})
export class Foo implements OnInit, OnDestroy {
  public prop: SomeInterface;
  private prop$: Observable<SomeInterface>;
  private _propSubscription: Subscription;
  
  public constructor(private svc: SomeService, private cdr: ChangeDetectorRef) {}
  
  public ngOnInit(): void {
    this.prop$ = this.svc.getSomeInterface();
    this._propSubscription = this.prop$.subscribe((v: SomeInterface) => {
      this.prop = v;
      this.cdr.markForCheck();
    });
  }
  
  public ngOnDestroy(): void {
    if (this._propSubscription) {
      this._propSubscription.unsubscribe();
    }
  }
}

After:

@NgxDecorate()
@Component({})
export class Foo implements OnInit {
  @SubscribeTo('prop$', {cdrProp: 'cdr'})
  public prop: SomeInterface;
  
  public constructor(private svc: SomeService, private cdr: ChangeDetectorRef) {}
  
  public ngOnInit(): void {
    this.prop$ = this.svc.getSomeInterface();
  }
}

API:

export interface SubscribeToConfig {
    /** Property at which the change detector resides */
    cdrProp?: PropertyKey;
}

/**
 * Subscribe to an observable and set its last emitted value to this property
 *
 * This decorator requires the ngOnInit hook and therefore will only work with directives and components.
 *
 * @param prop Property at which the observable resides
 * @param cfg Optional configuration
 */
export declare function SubscribeTo(prop: PropertyKey, cfg?: SubscribeToConfig): PropertyDecorator;

TrackDestroyed - set the property to true during OnDestroy

This could potentially be used with the @CdrProp() decorator.

Before:

@Component({})
export class Foo implements OnDestroy {
  private _destroyed: boolean;
  
  public ngOnDestroy(): void {
    this._destroyed = true;
  }
}

After:

@NgxDecorate()
@Component({})
export class Foo {
  @TrackDestroyed()
  private _destroyed: boolean;
}

API:

/** Set the given property to true when the component is destroyed */
export declare function TrackDestroyed(): PropertyDecorator;

TrackInit - set the property to true during ngOnInit

Same as @TrackDestroyed(), but for ngOnInit

Unsubscribe - automatically unsubscribe from subscriptions

This decorator is equivalent to @Complete(), but instead of Subjects it works on Subscriptions.