What is the best way to extract values from case-sensitive query param variables?

I am dealing with a URL that contains the query string id. However, the variable id can appear as either 'id' or 'Id' in the URL.

From my understanding, these two variations will be treated differently. To handle URLs like the following:

http://xxx/abc?id=10

http://xxx/abc?Id=10

private findQueryParams() {
  this._router.queryParams.subscribe((params: Params) => {
    if (Object.keys(params).length) {
      let id = 0;
      if (params['id']) {
        id = Number(params['id']);
      } else if (params['Id']) {
        id = Number(params['Id']);
      }
    }
  });
}

Is there a simpler way to handle case-sensitive variables and retrieve their values accurately in angular4?

Answer №1

Referring to @vogomatix's advice, it is recommended not to have the same parameter with different names. However, if for some reason you do need to, here's a simplified version of your code:

private findQueryParams() {
    this._route.queryParams.subscribe((params: Params) => {
        const idValue = params['id'] || params['Id'] || '0';
        let id = Number(idValue);
    });
}

This will prioritize the value of id, then fallback to Id, and finally default to '0' if none exist.

If there are multiple variations of parameter names as mentioned, a better approach would be to convert all keys to lowercase:

function toLower(params: Params): Params {
    const lowerParams: Params = {};
    for (const key in params) {
        lowerParams[key.toLowerCase()] = params[key];
    }

    return lowerParams;
}

With this modification:

private findQueryParams() {
    this._route.queryParams.subscribe((params: Params) => {
        const _params = toLower(params);
        const idValue = params['id'] || '0';
        let id = Number(params);
    });
}

It's necessary to apply this conversion every time you retrieve parameters from the Router, as the issue lies within the URL system itself.

Answer №2

After searching online without success, I decided to create my own versatile class that wraps the existing Params object and allows for case-insensitive access to query string parameters.

Here's how you can incorporate it into your component:

import { ActivatedRoute } from '@angular/router';
import { CaseInsensitiveParamMap } from '../case-insensitive-param-map';

constructor(private activatedRoute: ActivatedRoute) {}

ngOnInit(): void {
  // Subscribe to changes in query params:
  this.activatedRoute.queryParams.snapshot.paramMap
    .subscribe((params) => this.handleQueryParamsChanged(new CaseInsensitiveParamMap(params)));

  // Or directly use params from the route snapshot:
  const paramMap = new CaseInsensitiveParamMap(this.activatedRoute.snapshot.queryParams);
  const returnUrl = paramMap.get('returnUrl');
}

private handleQueryParamsChanged(paramMap: CaseInsensitiveParamMap): void {
  const returnUrl = paramMap.get('returnUrl');
  // Retrieves the value of the first query param named 'returnUrl' regardless of case sensitivity
}

Additionally, I've included a helpful getNumber method that simplifies parsing numeric query params. It returns null if the value is not a number or doesn't exist.

Below is the implementation of the class:

case-insensitive-param-map.ts

import { ParamMap, Params } from '@angular/router';

export class CaseInsensitiveParamMap implements ParamMap {
  private params: Params;

  constructor(params: Params) {
    this.params = params || {};
  }

  has(name: string): boolean {
    return Object.keys(this.params).some((key) => key.toLowerCase() === name.toLowerCase());
  }

  private getKeysCaseInsensitively(name: string): string[] {
    return Object.keys(this.params).filter((key) => key.toLowerCase() === name.toLowerCase());
  }

  get(name: string): string | null {
    if (this.has(name)) {
      const keys = this.getKeysCaseInsensitively(name);
      const value = this.params[keys[0]];
      return Array.isArray(value) ? value[0] : value;
    }

    return null;
  }

  getNumber(name: string): number | null {
    const value = this.get(name);
    return !value || isNaN(Number(value)) ? null : Number(value);
  }

  getAll(name: string): string[] {
    if (this.has(name)) {
      const result: string[] = [];
      this.getKeysCaseInsensitively(name).forEach((key) => {
        const value = this.params[key];
        result.push(...(Array.isArray(value) ? value : [value]));
      });
      return result;
    }

    return [];
  }

  get keys(): string[] {
    return Object.keys(this.params);
  }
}

For testing purposes and documentation, here are the accompanying tests:

case-insensitive-param-map.spec.ts

import { Params } from '@angular/router';
import { CaseInsensitiveParamMap } from './case-insensitive-param-map';

describe('CaseInsensitiveParamMap', () => {
  // Test cases go here...
});

Answer №3

If you want a component to display a specific abc item, it's recommended to structure your URLs without query parameters and instead use Routes.

For example, rather than having to display the abc item with an id of 10, you should have a route like

This route would be added as:

 { path: 'abc/:id', component: abcComponent },

where abcComponent is the component responsible for displaying the corresponding item

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Experimenting with viewProvider in a component test

@Component({ selector: 'app-entity-details', templateUrl: './entity-details.component.html', styleUrls: ['./entity-details.component.scss'], viewProviders: [{ provide: ControlContainer, useFactory: (container: ...

What are the steps for creating a custom repository with TypeORM (MongoDB) in NestJS?

One query that arises is regarding the @EntityRepository decorator becoming deprecated in typeorm@^0.3.6. What is now the recommended or TypeScript-friendly approach to creating a custom repository for an entity in NestJS? Previously, a custom repository w ...

React onClick event image attribute is unique because it allows for interactive

Is there a way to dynamically add the onClick attribute to an image, but have the click event not working? //Code const parser = new DOMParser(); const doc = parser.parseFromString(htmlContent, "text/html" ); const imageDa ...

Ways to circumvent ng switch and create a component based on type

In my current code, I have an array called resourceTypes and I am using ngSwitch to create different components/directives based on the TypeName. However, I find this approach cumbersome as I have to update the code every time I add a new resource editor. ...

NextJS middleware API receives an uploaded image file form, but the request is undefined

Currently, I'm utilizing NextJS to handle form data processing and database uploads, with a pit stop at the NextJS API middleware for image editing. pages/uploadImage.tsx This is the client-side code handler. ... async function handleImageUpload(imag ...

There was an issue with loading resources in ASP.NET MVC with Angular 2 as the server responded with a 404 (Not Found) error

Encountering some unexpected behavior with typescript imports in ASP.Net MVC using Angular 2. The issue arises when the code errors at runtime stating it cannot locate the ng2-highcharts package from the root directory, rather than within node_modules. Al ...

"Error message: 'ng' command cannot be found even after completing the installation of Node

Recently, I set up a fresh MacOS Catalina operating system on my computer. When I attempted to run my old project using 'ng serve', I encountered the error message 'ng: command not found'. To troubleshoot, I installed npm 6.12.1 via nod ...

Best practice for importing ts files from an npm package

When faced with the need to divide a ts project into multiple repositories/packages for creating microservices, the challenge arises in combining these packages efficiently. Some packages are required in one microservice, others in another, and some in all ...

Angular 6's subscribe method is causing the UI to not update

I'm currently facing an issue where my component does not refresh the UI after I input data. I always have to manually refresh the page to see the changes. I suspect there might be a problem with the .subscribe method in Angular 6. Previously, when I ...

Angular 4 project occupying significant disk space

After discovering that my Angular 4 project takes up approximately 300 MB on disk, I realized that the node_modules folder is to blame for this large size. Would it be advisable to exclude this folder from the repository in order to save space and reduce d ...

Encountered an error while trying to install @material-ui/core through npm: Received an unexpected end of JSON input

npm install @material-ui/core npm ERR! Unexpected end of JSON input while parsing near '...X1F+dSMvv9bUwJSg+lOUX' npm ERR! A complete log of this run can be found in: npm ERR! C:\Users\WR-022\AppData\Roaming\npm-cach ...

Rule of authentication using Firebase Database

I need to establish a rule in my Firebase Database to prevent unauthorized access for reading and writing purposes. Within my database, there is a collection of words, each containing a "uid" field that corresponds with the uid of the authUser key stored ...

Struggling to send information to the data layer on every page in Angular 9

Currently, I am in the process of integrating a GTM snippet into my Angular project. However, I have noticed that when the page is hard reloaded, it pushes data but does not do so during normal navigation. I have already added the GTM snippet provided by ...

Local hosting of Angular 8 application with Universal and i18n integration encountered issues

I have integrated Angular Universal into my existing project that already has i18n. I am able to build the project, but facing issues while trying to serve it. Currently, I am encountering the following error: Cannot find module '/home/my-user/my-ap ...

The absence of the function crypto.createPrivateKey is causing issues in a next.js application

For my next.js application, I am utilizing the createPrivateKey function from the crypto module in node.js. However, I encountered an issue as discussed in this thread: TypeError: crypto.createPrivateKey is not a function. It seems that this function was a ...

Utilize Angular's $state service within a configuration setting to automatically redirect to a specific state using an interceptor

I'm working with restangular and have set up an interceptor to handle 401 responses by redirecting to another state. The issue is that angular only allows the injection of providers, not services, in config. Is there a way to access the $state: ng.u ...

The process of extracting all arrays from a JSON object

Within my JSON object, there is a list of countries each with multiple regions stored in an array. My goal is to extract and combine all the regions into one single list. However, when I attempt to map the data, it does not consolidate all the regions as e ...

Creating intricate structures using TypeScript recursively

When working with Angular and TypeScript, we have the power of generics and Compile-goodness to ensure type-safety. However, when using services like HTTP-Service, we only receive parsed JSON instead of specific objects. Below are some generic methods that ...

What is the best way to incorporate a formArray into a formGroup?

Before anything else, I want to apologize for any errors in my English. I seem to be having trouble adding an array field to a formGroup. My issue arises when attempting to use the push method to add a formArray to my rate formGroup. It appears that the ...

Style will be applied to Angular2 when the object's ID exceeds 100

I am working with object markers that have different Id's assigned to them. Now, I am trying to apply additional styling when the id > 100. Check out the code snippet below: <span *ngIf="result.object.reference > 100" class="tooltip-data"&g ...