Skip to content

Some useful code snippets

JS

js - nameof
// very simple nameof version to ensure type safety. usage: nameof<User>(‘name’)
export function nameof<T>(key: keyof T, instance?: T): keyof T {
  return key;
}
js - guid
export function guid() {
  function s4() {
    return Math.floor((1 + Math.random()) * 0x10000)
      .toString(16)
      .substring(1);
  }

  return s4() + s4() + "-" + s4() + "-" + s4() + "-" + s4() + "-" + s4() + s4() + s4();
}

rxjs

rxjs - unsubscribe on destroy ![unsubscribe on destroy](../assets/on-destroy.png "unsubscribe on destroy")
rxjs - untilDestroy - operator
import { MonoTypeOperatorFunction, Observable } from "rxjs";
import { takeUntil } from "rxjs/operators";

// create a symbol identify the observable I add to
// the component so it doesn't conflict with anything.
// I need this so I'm able to add the desired behaviour to the component.
export const destroy$ = Symbol("destroy$");

/**
 * An operator that takes until destroy it takes a components this a parameter
 * returns a pipeable RxJS operator.
 */
export const untilDestroy = <T>(component: any): MonoTypeOperatorFunction<T> => {
  const orignalDestroy = component.ngOnDestroy;
  if (orignalDestroy == null) {
    // Angular does not support dynamic added destroy methods
    // so make sure there is one.
    throw new Error("untilDestroy operator needs the component to have an ngOnDestroy method");
  }
  if (component[destroy$] === undefined) {
    // only hookup each component once.
    addDestroyObservableToComponent(component);
  }

  // pipe in the takeUntil destroy$ and return the source unaltered
  return takeUntil<T>(component[destroy$]);
};

/**
 * @internal
 */
export function addDestroyObservableToComponent(component: any) {
  component[destroy$] = new Observable<void>((observer) => {
    // keep track of the original destroy function,
    // the user might do something in there
    const orignalDestroy = component.ngOnDestroy;
    // replace the ngOndestroy
    component.ngOnDestroy = () => {
      // fire off the destroy observable
      observer.next();
      // complete the observable
      observer.complete();
      // and at last, call the original destroy
      orignalDestroy.call(component);
    };
    // return cleanup function.
    return (_: any) => (component[destroy$] = undefined);
  });
}
rxjs - isTruthy - operator
// same behaviour like filter(Boolean) but keeps the type.
// Maybe "is not null nor undefined" check would be better then isTruthy (which e.g. also filters true, '' or 0)
// but for legacy reasons we use that instead.
export function isTruthy<T>(): MonoTypeOperatorFunction<T> {
  return (source$: Observable<null | undefined | T>) => source$.pipe(filter(inputIsTruthy));
}

function inputIsTruthy<T>(input: null | undefined | T): boolean {
  return !!input;
}
rxjs - firstTruthy - operator
function firstTruthy<T>(): MonoTypeOperatorFunction<T> { 
  return input$ => input$.pipe(first(Boolean));
}
rxjs - isNotNullNorUndefined - operator
export function isNotNullNorUndefined<T>(): MonoTypeOperatorFunction<T> {
  return (source$: Observable<null | undefined | T>) => source$.pipe(filter(inputIsNotNullNorUndefined));
}

function inputIsNotNullNorUndefined<T>(input: null | undefined | T): boolean {
  return input !== null && input !== undefined;
}
rxjs - log - operator
export function log<T>(id: string = null, uniqueColor: boolean = true): MonoTypeOperatorFunction<T> {
  const tag = `Stream: ${id || guid()}`;
  let color = `color: #000000;`;

  if (uniqueColor) {
    const r = "88";
    const g = Math.floor(Math.random() * 256).toString(16);
    const b = Math.floor(Math.random() * 256).toString(16);
    color = `color: #${r}${g}${b}`;
  }

  return pipe(
    tap(
      (next) => console.log(`%c[${tag}: Next]`, color, next),
      (error) => console.log(`%c${tag}: Error]`, uniqueColor ? color : "color: #F44336;", error),
      () => console.log(`%c[${tag}: Complete]`, color)
    ),
    finalize(() => console.log(`%c[${tag}: Finalize]`, color))
  );
}
##

Angular

Angular - ngLet - Directive
import { NgModule, Directive, Input, TemplateRef, ViewContainerRef, OnInit } from "@angular/core";

export class NgLetContext {
  $implicit: any = null;
  ngLet: any = null;
}

@Directive({
  selector: "[ngLet]",
})
export class NgLetDirective implements OnInit {
  private _context = new NgLetContext();

  @Input()
  set ngLet(value: any) {
    this._context.$implicit = this._context.ngLet = value;
  }

  constructor(private _vcr: ViewContainerRef, private _templateRef: TemplateRef<NgLetContext>) {}

  ngOnInit() {
    this._vcr.createEmbeddedView(this._templateRef, this._context);
  }
}

@NgModule({
  declarations: [NgLetDirective],
  exports: [NgLetDirective],
})
export class NgLetModule {}
Angular - Tooltip - Directive
import { Directive, ElementRef, Input, OnDestroy, OnInit } from '@angular/core';
import { MatTooltip } from '@angular/material/tooltip';

@Directive({
  selector: '[showTooltipIfTruncated]'
})
export class ShowTooltipIfTruncatedDirective implements OnInit, OnDestroy {

  @Input() rmShowTooltipIfTruncated: 'useInnerText' | '' = '';

  private observer: ResizeObserver | null = null;

  constructor(
    private matTooltip: MatTooltip,
    private elementRef: ElementRef<HTMLElement>,
  ) {
  }

  public ngOnInit(): void {
    const element = this.elementRef.nativeElement;


    setTimeout(() => {
      if (this.rmShowTooltipIfTruncated === 'useInnerText') {
        this.matTooltip.message = element.innerText;
      }

      this.observer = new ResizeObserver(() => {
        this.matTooltip.disabled = element.scrollWidth <= element.clientWidth;
      });

      this.observer.observe(element);
    });
  }

  ngOnDestroy() {
    this.observer?.unobserve(this.elementRef.nativeElement);
  }
}
<div class="ellipsis" matTooltip="" showTooltipIfTruncated="useInnerText" [target]="input">my inner text as tooltip</div>
Angular - Ellipsis - Pipe
import { Pipe, PipeTransform } from "@angular/core";

/**
 * Truncates text accordingly
 */
@Pipe({
  name: "ellipsis",
})
export class EllipsisPipe implements PipeTransform {
  transform(str: string, strLength: number = 250): string | null {
    if (str == null) {
      return null;
    }

    const withoutHtml = str.replace(/(<([^>]+)>)/gi, "");

    if (str.length >= strLength) {
      return `${withoutHtml.slice(0, strLength)}...`;
    }

    return withoutHtml;
  }
}
Angular - OpenExternalWindow - Service
import { Inject, Injectable } from "@angular/core";
import { WindowToken } from "src/app/core/window/window";

/**
 * Service to open an external website
 */
@Injectable()
export class OpenExternalWindowService {
  constructor(@Inject(WindowToken) private window: Window) {}

  openExternalWindowService(helpUrl: string): void {
    let url = "";
    if (!/^http[s]?:\/\//.test(helpUrl) && !helpUrl.toLowerCase().startsWith("file://")) {
      url += "https://";
    }

    url += helpUrl;
    this.window.open(url, "_blank");
  }
}