Today I would like to talk about a particular case when building an Angular application.
I, personally, face this issue while building an online banking integration to Salesforce.
TUPAS is a digital authentication method created by the Federation of Finnish Financial Services.
The actual problem was with special characters such as “äö,” so-called ääkköset in Finnish.
Because TUPAS supports only ISO 8859-1 (Latin-1) encoding the browser converts them using an escaping character “%.”
Angular Router’s URL parser cannot parse it so that it would break the whole application.
In this article, I will show how you can extend the standard framework functionality and eventually resolve the issue.
The problem
First of all, let’s figure out where the error appears. We already know that the problem is with the router module.
The router is using the UrlSerializer to parse and serialize the URL. It has two corresponding methods. The first one accepts a string value and returns a UrlTree, and the other does the opposite.
Parse is the method which gives an error because of a particular character.
In general, people suggest pre-modifying the URL on the back-end side before sending to the Angular Router, e.g., using the proxy to return the URL with UTF-8 encoding.
I used that approach for one of the client projects with Salesforce to prevent VisualForce pages from breaking.
Though the solution works fine, it requires additional effort.
What I would like to do is to show how you can fix it on the front-end side.
The solution
The solution itself is a pretty trivial one. We already know that the escape char is the reason behind the issue so what we have to do is to unescape a string before passing it to the parse method of the UrlSerializer class.
The most exciting part is how to do it because it’s a default Angular class.
In fact, you can extend or modify any part of Angular by writing custom classes and provide them to the module.
As an example, you might want to do this to build a custom router state serializer when using NGRX store (Redux implementation for Angular using Reactive-Functional paradigm).
That is how you can do this.
Let’s create a file with the following code.
// custom-url-serializer.ts
import { UrlSerializer, UrlTree, DefaultUrlSerializer } from '@angular/router';
export class CustomUrlSerializer implements UrlSerializer {
parse(url: any): UrlTree {
const dus = new DefaultUrlSerializer();
return dus.parse(unescape(url));
}
serialize(tree: UrlTree): any {
const dus = new DefaultUrlSerializer();
return dus.serialize(tree);
}
}
It’s a custom class which implements the default UrlSerializer, and the only difference is that it uses the unescape function inside the parse method.
Then we need to navigate to our module file, import the class we just created and use it for the UrlSerializer in the providers.
// app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { UrlSerializer } from '@angular/router';
import { AppComponent } from 'app/app.component';
import { CustomUrlSerializer } from './custom-url-serializer';
@NgModule({
imports: [
BrowserModule
],
declarations: [ AppComponent ],
providers: [
{ provide: UrlSerializer, useClass: CustomUrlSerializer }
],
bootstrap: [ AppComponent ]
})
export class AppModule { }
That is it, the straightforward solution to our problem.
One of the cool things I like about the Angular is that you can rewrite any default functionality using the given approach.
Of course, in the majority of cases, you won’t have to do it, but still, it might be good to have in your arsenal.
Nikita Verkhoshintcev
Salesforce Freelance Developer / Solution Architect
I'm a senior freelance Salesforce and full-stack web developer based in Helsinki, Finland. I help companies, consulting agencies, and ISV partners build custom Salesforce applications.