Home > other >  Proper way to generate a URL with parameters in Angular
Proper way to generate a URL with parameters in Angular

Time:09-22

I am trying to generate a string (which will be formed by concatenating the apiUrl queryParams) with the data I receive from a form (Reactive Form). I have already found a solution, but I think it is the ugliest and less professional thing ever created. I provide some code next.

component.ts

stringFinal : string = ''

this.myForm= this.fb.group({
      input1: new FormControl(),
      input2: new FormControl(),
      input3: new FormControl(),
      
    });

generateUrl() {
    let qry1 = this.myForm.get("input1")?.value
    let qry2 = this.myForm.get("input2")?.value
    let qry3 = this.myForm.get("input3")?.value
    
    if(qry1 != null) {
      this.stringFinal  = `qry1=${qry1}&`
    }

    if(qry2 != null) {
      this.stringFinal  = `qry2=${qry2}&`
    }

    if(qry3 != null) {
      this.stringFinal  = `qry3=${qry3}&`
    }
    
    console.log(this.stringFinal);
  }

This works fine, but it is not really scalable, and if I wanted, in the future, add 50 more inputs to the form, I would have to add manually 50 more conditions.

Also, in some cases, instead of receiving only strings from the form, I will also receive objects, and in that case, I will not be able to retrieve the data. I provide an example.

input4: (2) [{...},{...}]

My questions are 2:

  1. How to improve the URL generation without doing what I showed.
  2. How to retrieve an specific field (for example, the name), when I receive an array instead of a string.

CodePudding user response:

You can improve on your url generation by iterating over the controls property of your FormGroup:

stringFinal: string = "";

generateUrl() {
  for(const control in this.myForm.controls){
    const val = this.myForm.controls[control].value;
    if(val !== null){
      this.stringFinal  = `${control}=${val}&`;
    }
  }
}

If you not only have strings but also objects as values in your form, you have to verify the type of the control value first, for example with a typeguard:

interface Person 
  name: string;
  id: number;
}

function isPerson(a_obj: any): a_obj is Person {
  return `name` in a_obj && 'id' in a_obj;
}

And to put it alltogether:

interface Person {
  name: string;
  id: number;
}

stringFinal: string = "";

generateUrl() {
  for(const control in this.myForm.controls){
    const val = this.myForm.controls[control].value;
    if(val === null) continue;
    if(isPerson(val)){
        this.stringFinal  = `${control}=${val.name}&`;
    } else {
        this.stringFinal  = `${control}=${val}&`;
    }
  }
}

function isPerson(a_obj: any): a_obj is Person {
  return `name` in a_obj && 'id' in a_obj;
}
  • Related