-2

Question: Is it possible to retrieve a collection of query string values and assign them to a property of type Filter in a service component class?

interface Filter{
    title?: string;
    genreId?: number;
    inCinemas?: boolean;
    upcomingReleases?: boolean;
}

rather than doing the following tedious, error prone of retrieval and assignment?

constructor(private route: ActivatedRoute) { }
ngOnInit(): void {
  this.route.paramMap.subscribe({
    next: params => this.title = params.get('title'),
    error: e => console.log(e)
  });
  this.route.paramMap.subscribe({
    next: params => this.genreId = params.get('genreId'),
    error: e => console.log(e)
  });
  this.route.paramMap.subscribe({
    next: params => this.inCinemas = params.get('inCinemas'),
    error: e => console.log(e)
  });
  this.route.paramMap.subscribe({
    next: params => this.UpcomingReleases = params.get('upcomingReleases'),
    error: e => console.log(e)
  });
}
R. Richards
  • 24,603
  • 10
  • 64
  • 64
Second Person Shooter
  • 14,188
  • 21
  • 90
  • 165
  • Are you trying to get query string values or path params? they are two different things in Angular `query strings` come after the `?` such as `?user=123`, and `params` are placeholders in your path such as `/user/:id` where `id` is a placeholder. – Get Off My Lawn Jul 01 '22 at 21:59
  • 1
    @GetOffMyLawn: I want to map `https://localhost:40443/MoviesController/ActionMethod?title="Batman"&genreId="1000"&inCinemas="true"` to a property of type `Filter` (and set the missing value to `null`). They will be used to filter a movie in an asp.net core webapi. – Second Person Shooter Jul 01 '22 at 22:02
  • It seems to me this feature does not exist. I already searched everywhere with no result. – Second Person Shooter Jul 01 '22 at 22:11

2 Answers2

0

You could make it very simple, as long as your class properties are the same name as the query string keys, you can do something like this:

export class SearchPageComponent {
  title = '';
  genreId = '';
  inCinemas = '';
  upcomingReleases = '';
 
  constructor(private readonly route: ActivatedRoute) { }

  ngOnInit() {
    // Don't forget to unsubscribe
    this.route.queryParams.pipe(
      // Send each query param as a string to the next pipe individually
      concatMap(i => Object.entries(i)),
      // filter only continue with the current key if the property exists in the class
      filter(([key]) => key in this),
      // Assign the item to the property
      tap(([key, val]) => (this as any)[key] = val)
    ).subscribe(i => console.log(i));
  }
}
Get Off My Lawn
  • 34,175
  • 38
  • 176
  • 338
0

You could create a decorator that you can attach to properties that will read the URL query parameters and get the proper one, this would then automatically assign the param value to the property. The decorator would look like this:

export function QueryParam(key?: string) {
  return (target: object, propertyKey: string) => {
    Object.defineProperty(target, propertyKey, {
      get: () => {
        const query = Object.fromEntries(new URLSearchParams(location.search));
        const find = key ?? propertyKey;
        return query[find];
      },
      set: (newVal: string) => newVal
    });
  };
}

The decorator will use the property that it is attached to, to get the value from the query params. If the query param is different than the property name, you can pass the name of the query param as an argument.

Then you would attach it to the property like this:

import { QueryParam } from '/my/decorators/http'

export class SearchPageComponent {
  @QueryParam() title = '';
  @QueryParam() genreId = '';
  @QueryParam() inCinemas = '';
  @QueryParam('customQueryKey') upcomingReleases = '';
}

You may also need to add DOM.Iterable to your tsconfig.json:

{
  "compilerOptions": {
    "lib": [
      "DOM.Iterable"
    ]
  }
}
Get Off My Lawn
  • 34,175
  • 38
  • 176
  • 338