4
votes

Currently we use matrix params in my angular 4+ application. Google Analytics has problems reading URL with ; so we decided to change it to query params. However old notation (matrix) must be accessible and redirect to new one and save such event into db.

I see three possible solutions:

  1. Use custom URL serializer/parser which would use regex to convert matrix to query, save to db and make redirect
  2. Use some sort of route guard with the same functionality
  3. Use dedicated component to handle this functionality

While 3rd way is certainly last chance option, I have troubles anticipating which of the remaining two would be better.

2

2 Answers

1
votes

I would use both 1st and 3rd solutions for that.

The component I would use is the AppComponent, because it is the highest component in your application.

Then, I would parse the URL, detect if it's a matrix notation, and if it is, convert it to query params notation.

Then, I would redirect the user to the page he asked for, with the query param notation.

0
votes

I'm past all test on my solution so here it is

customUrlSerializer:

parse(url: any): UrlTree {
    const dus = new DefaultUrlSerializer();
    const splittedUrl = url.replace(/%3D/g, '=').split(/(;[\w\d-]*=[\w\d-]*)/g);

    const matrixParams = this.extractMatrixParams(splittedUrl);
    const queryParams = this.extractQueryParams(url);

    if (matrixParams) {
      this.saveOldUrlIncident(url);
    }

    const newUrl = this.buildNewString(splittedUrl, matrixParams, queryParams);
    return dus.parse(newUrl);
  }

  serialize(tree: UrlTree): any {
    const dus = new DefaultUrlSerializer(),
      path = dus.serialize(tree);
    return path.replace(/%3D/g, '=');
  }

  private extractMatrixParams(splittedUrl: string[]): string {
    return splittedUrl
      .filter(el => el.startsWith(';'))
      .reduce((a, b) => (a = a + b.substr(1) + '&', a), '')
      .slice(0, -1);
  }

  private extractQueryParams(url: string): string {
    return url.lastIndexOf('?') > -1 ? url.substr(url.lastIndexOf('?') + 1, url.length - 1) : '';
  }

  private buildNewString(splittedUrl: string[], matrixParams: string, queryParams: string): string {
    let newUrl = splittedUrl.reduce((a, b) => {
      if (b && !b.startsWith(';')) {
        if (b.indexOf('?')) {
          a = a + b.split('?')[0];
        } else {
          a = a + b;
        }
      }
      return a;
    }, '');

    if (matrixParams || queryParams) {
      newUrl = newUrl + '?';
    }
    if (matrixParams) {
      newUrl = newUrl + matrixParams;
    }
    if (queryParams) {
      newUrl = newUrl + (matrixParams ? '&' : '') + queryParams;
    }

    return newUrl;
  }

And in app.module, in providers add: {provide: UrlSerializer, useClass: CustomUrlSerializer},