Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom encoding for urls using Angular 2 Router (using a + sign in place of a space)

I am using an Angular 2 Router to update the query params in a URL for a search application. I am attempting to replace spaces in a query with + signs. However, + signs are getting encoded. For example:

this.router.navigatebyUrl('?q=one+two');

populates the URL with "?q=one%2Btwo".

In looking at the source code for Angular 2, it looks like the router converts the URL to a UrlTree which uses encodeURIComponent() to encode the url. Because of this, it is impossible to prevent the default encoding.

My current process is that I change the route by doing navigateByUrl as seen above, and then listen for changes with:

this.routeSubscription = this.route.queryParams.subscribe((params: any) => {
  this.term = (params.q ? params.q : '');
});

Is there an alternate way to deal with query parameters that would allow me to use my own strategy for url encoding?

like image 426
Noah Mulfinger Avatar asked Sep 16 '16 23:09

Noah Mulfinger


People also ask

How to prevent the default URL encoding in Angular 2?

populates the URL with "?q=one%2Btwo". In looking at the source code for Angular 2, it looks like the router converts the URL to a UrlTree which uses encodeURIComponent () to encode the url. Because of this, it is impossible to prevent the default encoding.

How to encode the + sign in a URL?

However, + signs are getting encoded. For example: populates the URL with "?q=one%2Btwo". In looking at the source code for Angular 2, it looks like the router converts the URL to a UrlTree which uses encodeURIComponent () to encode the url.

How do I create a custom route in angular?

Using the Angular CLI, create a new application, angular-custom-route-match . In addition to the default Angular application framework, you will also create a profile component. Create a new Angular project, angular-custom-route-match. When prompted with Would you like to add Angular routing?, select Y.

What is the purpose of pattern matching with the angular router?

Pattern matching with the Angular Router provides you with a lot of flexibility when you have dynamic URLs in your application. To learn more about the Angular Router, see the following topics: This content is based on Custom Route Matching with the Angular Router, by Brandon Roberts.


2 Answers

I was able to find a solution to my problem. You can make own custom url serializer by implementing the UrlSerializer class.

Custom Url Serializer

Create a custom url serializer like this:

class CustomUrlSerializer implements UrlSerializer {
    parse(url: string): UrlTree {
        // Custom code here
    }

    serialize(tree: UrlTree): string {
        // Custom code here
    }
}

Then, you just need to provide the CustomUrlSerializer in place of the UrlSerializer, which you can place in the AppModule providers array after importing both serializers.

providers: [
    { provide: UrlSerializer, useClass: CustomUrlSerializer },
    ...
]

Now, when you call router.navigate or router.navigateByUrl, it will use your custom serializer for parsing and serializing.

Using + signs as spaces

To parse + signs as spaces:

parse(url: string): UrlTree {
    // Change plus signs to encoded spaces
    url = url.replace(/\+/g, '%20');
    // Use the default serializer that you can import to just do the 
    // default parsing now that you have fixed the url.
    return this.defaultUrlSerializer.parse(url)  
}

And for serializing:

serialize(tree: UrlTree): string {
    // Use the default serializer to create a url and replace any spaces with + signs
    return this.defaultSerializer.serialize(tree).replace(/%20/g, '+');
}

DefaultUrlSerializer

like image 88
Noah Mulfinger Avatar answered Oct 03 '22 08:10

Noah Mulfinger


I ran into an issue specifying the custom provider. There was apparently a circular dependency when compiling with the --prod flag causing an error with the text: useClass cannot by null. This is how I worked around that error:

In AppModule, define the following:

const customUrlSerializer = new CustomUrlSerializer();
const CustomUrlSerializerProvider = {
    provide: UrlSerializer,
    useValue: customUrlSerializer
};

Then in the providers array, add the provider you specified above.

...
providers: [CustomUrlSerializerProvider]
...
like image 35
Aaron Scherbing Avatar answered Oct 03 '22 07:10

Aaron Scherbing



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!