File

projects/storefrontlib/shared/components/generic-link/generic-link.component.ts

Description

This component navigates using [routerLink] attribute when input 'url' is a relative url. Otherwise (when it's absolute), [href] is used.

Implements

OnChanges

Metadata

selector cx-generic-link
templateUrl ./generic-link.component.html

Index

Properties
Methods
Inputs
Accessors

Constructor

constructor(router: Router, service?: GenericLinkComponentService)
Parameters :
Name Type Optional
router Router No
service GenericLinkComponentService Yes

Inputs

class
Type : string
id
Type : string
style
Type : string
target
Type : string | null
title
Type : string
url
Type : string | any[]

Methods

Private getAbsoluteUrl
getAbsoluteUrl(url: string)

Prepends a leading slash to the given URL string, in case it doesn't have it.

Parameters :
Name Type Optional
url string No
Returns : string
isExternalUrl
isExternalUrl()
Returns : boolean
ngOnChanges
ngOnChanges(changes: SimpleChanges)
Parameters :
Name Type Optional
changes SimpleChanges No
Returns : void
Private setUrlParts
setUrlParts(url: string | any[])

Parses the given url and sets the property urlParts accordingly.

Parameters :
Name Type Optional
url string | any[] No
Returns : void
Private splitUrl
splitUrl(url: string)

Parses the given string into 3 parts:

  • string path (wrapped in an array to be compatible with Angular syntax for the routerLink)
  • query params (as an object)
  • hash fragment (string)
Parameters :
Name Type Optional Default value
url string No ''
Returns : RouteParts

Properties

class
Type : string
Decorators :
@Input()
id
Type : string
Decorators :
@Input()
Protected MAILTO_PROTOCOL_REGEX
Type : RegExp
Default value : /^mailto:/i

Pattern matching string starting with mailto:.

Private Readonly PROTOCOL_REGEX
Type : RegExp
Default value : /^https?:\/\//i

Pattern matching string starting with http:// or https://.

Private routeParts
Type : RouteParts
Default value : {}

Parsed parts of the @Input url, when it's a local URL. It should not be used when the url is external.

style
Type : string
Decorators :
@Input()
target
Type : string | null
Decorators :
@Input()
Protected TEL_PROTOCOL_REGEX
Type : RegExp
Default value : /^tel:/i

Pattern matching string starting with tel:.

title
Type : string
Decorators :
@Input()
url
Type : string | any[]
Decorators :
@Input()
Private Readonly URL_SPLIT
Default value : /(^[^#?]*)(.*)/

Used to split url into 2 parts:

  1. the path
  2. query params + hash fragment

Accessors

rel
getrel()
routerUrl
getrouterUrl()

The part with the path of the local url.

Returns : any[]
queryParams
getqueryParams()

The part with the query params of the local url.

Returns : Params
fragment
getfragment()

The part with the hash fragment of the local url.

Returns : string
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
import { Params, Router } from '@angular/router';
import { GenericLinkComponentService } from './generic-link-component.service';

// private
interface RouteParts {
  /** Path in the Angular-like array format */
  path?: string[];

  /** Query params */
  queryParams?: Params;

  /** Hash fragment */
  fragment?: string;
}

/**
 * This component navigates using [routerLink] attribute when input 'url' is a relative url. Otherwise (when it's absolute), [href] is used.
 */
@Component({
  selector: 'cx-generic-link',
  templateUrl: './generic-link.component.html',
})
export class GenericLinkComponent implements OnChanges {
  /**
   * Pattern matching string starting with `http://` or `https://`.
   */
  private readonly PROTOCOL_REGEX: RegExp = /^https?:\/\//i;

  /**
   * Pattern matching string starting with `mailto:`.
   */
  protected MAILTO_PROTOCOL_REGEX: RegExp = /^mailto:/i;

  /**
   * Pattern matching string starting with `tel:`.
   */
  protected TEL_PROTOCOL_REGEX: RegExp = /^tel:/i;

  /**
   * @deprecated since version 5.0
   * Use the following constructor instead:
   * ```
   * constructor(
   *   protected router: Router,
   *   protected service?: GenericLinkComponentService
   * )
   * ```
   */
  constructor(router: Router);
  constructor(
    protected router: Router,
    protected service?: GenericLinkComponentService
  ) {}

  /**
   * Used to split url into 2 parts:
   * 1. the path
   * 2. query params + hash fragment
   */
  private readonly URL_SPLIT = /(^[^#?]*)(.*)/;

  /**
   * Parsed parts of the @Input `url`, when it's a local URL.
   * It should not be used when the `url` is external.
   * @see `url`
   */
  private routeParts: RouteParts = {};

  @Input() url: string | any[];
  @Input() target: string | null;
  @Input() id: string;
  @Input() class: string;
  @Input() style: string;
  @Input() title: string;

  isExternalUrl(): boolean {
    return (
      this.service?.isExternalUrl(this.url) ||
      (typeof this.url === 'string' &&
        (this.PROTOCOL_REGEX.test(this.url) ||
          this.MAILTO_PROTOCOL_REGEX.test(this.url) ||
          this.TEL_PROTOCOL_REGEX.test(this.url)))
    );
  }

  get rel() {
    return this.target === '_blank' ? 'noopener' : null;
  }

  ngOnChanges(changes: SimpleChanges) {
    if (changes['url']) {
      this.setUrlParts(changes['url'].currentValue);
    }
  }

  /**
   * The part with the path of the local url.
   */
  get routerUrl(): any[] {
    return this.routeParts.path;
  }

  /**
   * The part with the query params of the local url.
   */
  get queryParams(): Params {
    return this.routeParts.queryParams;
  }

  /**
   * The part with the hash fragment of the local url.
   */
  get fragment(): string {
    return this.routeParts.fragment;
  }

  /**
   * Parses the given url and sets the property `urlParts` accordingly.
   */
  private setUrlParts(url: string | any[]) {
    if (typeof url === 'string') {
      url = this.getAbsoluteUrl(url); // string links in CMS sometimes don't have the leading slash, so fix it here
      this.routeParts = this.splitUrl(url as string);
    } else {
      this.routeParts = { path: url };
    }
  }

  /**
   * Parses the given string into 3 parts:
   * - string path (wrapped in an array to be compatible with Angular syntax for the `routerLink`)
   * - query params (as an object)
   * - hash fragment (string)
   */
  private splitUrl(url: string = ''): RouteParts {
    const { queryParams, fragment } = this.router.parseUrl(url);
    const [, path] = url.match(this.URL_SPLIT);

    // wrap path in an array, to have the Angular-like path format
    return { path: [path], queryParams, fragment };
  }

  /**
   * Prepends a leading slash to the given URL string, in case it doesn't have it.
   */
  private getAbsoluteUrl(url: string): string {
    return url.startsWith('/') ? url : '/' + url;
  }
}
<!-- https://github.com/angular/angular/issues/24567 -->

<ng-container *ngIf="isExternalUrl(); else isLocalUrl">
  <a
    [href]="url"
    [attr.target]="target"
    [attr.rel]="rel"
    [attr.id]="id"
    [attr.class]="class"
    [attr.style]="style"
    [attr.title]="title"
  >
    <ng-container *ngTemplateOutlet="content"></ng-container>
  </a>
</ng-container>

<ng-template #isLocalUrl>
  <a
    [routerLink]="routerUrl"
    [queryParams]="queryParams"
    [fragment]="fragment"
    [target]="target"
    [attr.id]="id"
    [attr.class]="class"
    [attr.style]="style"
    [attr.title]="title"
  >
    <ng-container *ngTemplateOutlet="content"></ng-container>
  </a>
</ng-template>

<ng-template #content>
  <ng-content></ng-content>
</ng-template>
Legend
Html element
Component
Html element with directive

result-matching ""

    No results matching ""