63

This is my array of actors:

['Elvis', 'Jane', 'Frances']

How to pass this array within a query string in HttpClient?

I tried to use:

1)

let params = new HttpParams();
params = Params.append('actors[]', ['Elvis', 'Jane', 'Frances']);
this.http.get(url, { params: Params });
let params = new HttpParams().set('actors[]', ['Elvis', 'Jane', 'Frances']);
this.http.get(url, { params: Params });
let Params = new HttpParams();
Params = Params.append('actors[]', 'Jane');
Params = Params.append('actors[]', 'Elvis');
Params = Params.append('actors[]', 'Frances');
this.http.get(url, { params: Params }); 

1st and 2nd snippets don't work because of TypeScript error:

[ts] Argument of type 'string[]' is not assignable to parameter of type 'string'.

3rd snippet sends only one item 'actors[]': 'Frances'

4
  • 2
    This totally depends on what your backend expects. Of course, 1 and 2 won't work because it expects a string. You can stringify an array accordingly to the expectations. Commented Nov 10, 2017 at 7:51
  • This doesn't really explain anything. Does it expect actors=Elvis,... query? A solution from the answer should be used then. I personally had to use npmjs.com/package/qs package for params because it worked better for arrays and nested objects with my Express backend. Commented Nov 10, 2017 at 7:58
  • @estus I'm using nodejs too. Thank you for your answer Commented Nov 10, 2017 at 8:01
  • Your 3rd attempt does actually pass them all as ?actors[]=Jane&actors[]=Elvis&actors[]=Frances. I'm guessing that your backend is only seeing the first one because it does not recognize this format for query string arrays, as Estus Flask mentioned. Commented Nov 8, 2022 at 17:15

16 Answers 16

50

I think the best way is to add them to parameters as a string and have your back-end convert it back to an array or list.

let actorList = ['Elvis', 'Jane', 'Frances']
let params = new HttpParams();
params = params.append('actors', actorList.join(', '));
this.http.get(url, { params: params });
Sign up to request clarification or add additional context in comments.

3 Comments

This is a terrible solution. There should be a way to send a request with an array, like it's possible in angularJS
Terrible solution. What if you don't own the backend, and it's impossible to make that change?
This isn't a terrible solution. It is use-case dependent, but all of the answers here are. Since there isn't a defined standard for passing arrays in a query string, you are always going to have to match the format that you send them to the format the backend is expecting. If the backend doesn't already have a defined way to process array values, you'll have to add your own. In that case, this is a quick and easy way to do so.
26

According the interface you can do that like

const params = new HttpParams({ 
   fromObject: { 'actors[]': ['Elvis', 'Jane', 'Frances'] } 
});
this.http.get(url, { params });

2 Comments

in my case it worked but without the brackets const params = new HttpParams({ fromObject: { 'actors': ['Elvis', 'Jane', 'Frances'] } }); this.http.get(url, { params });
This is functionally equivalent to the 3rd attempt tried by the OP. It creates the same URL for the request. If that attempt didn't work with the OP's backend, then this won't either.
15

Works on Angular 6.0.6:

private getParams(query) {
let params: HttpParams = new HttpParams();
for (const key of Object.keys(query)) {
  if (query[key]) {
    if (query[key] instanceof Array) {
      query[key].forEach((item) => {
        params = params.append(`${key.toString()}[]`, item);
      });
    } else {
      params = params.append(key.toString(), query[key]);
    }
  }
}
return params;

}

Result:

/api/message?page=1&per=2&order_by=name&order_direction=asc&base_object%5B%5D=2&base_object%5B%5D=1

3 Comments

After trying everything else, this was the only solution that worked for me. Thank you. I don't want to modify the backend, surprised angular doesn't support this out of the box
Works great. Is toString() on key really needed, however?
This is just a method to return an HttpParams object that is the same as the OP's 3rd attempt. It creates the same URL for the request. If that attempt didn't work with the OP's backend, then this won't either.
12

You can simply do this by using JSON.stringify()

    let params = new HttpParams();
    const actors = ['Elvis', 'Jane', 'Frances'];
    params.append('actors', JSON.stringify(actors);
    this.http.get(url, { params });

1 Comment

This has some syntax errors and the edit queue is full, probably with fixes for those. But even with those fixed, this is very unlikely to actually work on its own. It results in the query string being ?actors=[\"Elvis\",\"Jane\",\"Frances\"]. It's possible there is some backend library that recognizes this format and will automatically parse it out to an array, but it seems unlikely. You would probably have to add code to the backend to parse it back to an array yourself.
11

This worked for me.

let params = new HttpParams();

['Elvis', 'Jane', 'Frances'].forEach((actorName:string) =>{
  params = params.append(`actors[]`, actorName);
})

OR

let params = new HttpParams();
let actorsArray:Array<string> = ['Elvis', 'Jane', 'Frances'];

actorsArray.forEach((actorName:string) =>{
  params = params.append(`actors[]`, actorName);
})

1 Comment

These just create an HttpParams object that is the same as the OP's 3rd attempt. It creates the same URL for the request. If that attempt didn't work with the OP's backend, then this won't either
8
const actors = ['Elvis', 'Jane', 'Frances'];
let params = new HttpParams();
for (const actor of actors) {
  params = params.append('actors', actor);
}

this.http.get(url, { params: params }); 

2 Comments

This generates a query string of ?actors=Elvis&actors=Jane&actors=Frances, which is a format recognized by some popular backend libraries/frameworks. If that's a format your backend recognizes, this should work fine.
This worked for my, .NET7 backend
4

I'm using URLSearchParams instead of HttpParams.

With URLSearchParams you need to stringify your array to set it to your Params "Key-Value-Store".

import { URLSearchParams } from '@angular/http';


let params: URLSearchParams = new URLSearchParams();
params.set('actors', JSON.stringify(yourArrayHere));

I think this should work on the same way with HttpParams because both using a Key-Value mapping in the set method so give it a try.

I hope this can help you.

UPDATE:

let options = new RequestOptions({search: params});

this._http.get(url, options).map(...)

with RequestOptions you can also edit Header and other request options.

3 Comments

[ts] Argument of type '{ params: URLSearchParams; }' is not assignable to parameter of type '{ headers?: HttpHeaders; observe?: "body"; params?: HttpParams; reportProgress?: boolean; respons...'. Types of property 'params' are incompatible. Type 'URLSearchParams' is not assignable to type 'HttpParams'. Property 'map' is missing in type 'URLSearchParams'.
[ts] Argument of type 'RequestOptions' is not assignable to parameter of type '{ headers?: HttpHeaders; observe?: "body"; params?: HttpParams; reportProgress?: boolean; respons...'. Types of property 'headers' are incompatible. Type 'Headers' is not assignable to type 'HttpHeaders'. Property 'headers' is missing in type 'Headers'.
Note that URLSearchParams and RequestOptions were part of the old HttpModule that was deprecated when Angular 5 was released in September 2016 and removed from Angular 7 and later versions. They don't work with the HttpClient from the HttpClientModule, which is probably why Dmitry got errors when trying to use them.
4
let actorsArray = ['Elvis', 'Jane', 'Frances'];
this.http.get(url, { params: { actors: actorsArray } });

1 Comment

This generates a query string of ?actors=Elvis&actors=Jane&actors=Frances, which is a format recognized by some popular backend libraries/frameworks. This overload of the params property, where you just set it to an Object rather than an HttpPararms, gives you less control, but it also uses some sensible defaults. I would generally try doing it this way first, and only go to HttpParams if this doesn't work.
0

You can do the following:

this.http.get(url, { params: { "actors[]": actorsArray } });

1 Comment

This is functionally equivalent to the 3rd attempt tried by the OP. It creates the same URL for the request. If that attempt didn't work with the OP's backend, then this won't either.
0

I've used this method and it worked for me in Angular 10:

private paramMaker(data) : HttpParams
{
    let httpParams = new HttpParams();
    Object.keys(data).forEach((key) = > {
        if (Array.isArray(data[key]))
        {
            data[key].forEach((item, index) = > {
                httpParams = httpParams.append(key + '[' + index + ']', item);
            });
        }
        else
        {
            httpParams = httpParams.append(key, data[key]);
        }
    });
    return httpParams;
}

1 Comment

This generates a query string of ?actors[0]=Jane&actors[1]=Elvis&actors[2]=Frances. This isn't a format used very often, but some libraries do support it. If that's a format your backend recognizes, this should work fine.
0

Try this:

let params = new HttpParams();
let actorList = ['Elvis', 'Jane', 'Frances'];

actorList.forEach((actor: any)=> {
  params = params.append('actors[]', actor);
})

Comments

0

For .NET 7, this works for me:

public async Task<IActionResult> GetItems([FromQuery(Name = "categoryIds")] List<int> categoryIds) {
   ...
}

Then in Angular:

getItems(categoryIds: number[]): Observable<Item[]> {
    const params = new HttpParams({ fromObject: { categoryIds: categoryIds.map(String) } });
    return this.http.get<Item[]>(`${environment.apiUrl}/api/ControllerName/Items`, { params });
}

Comments

0

For me it worked as expected by passing the params directly in the options of the request.

const params: HttpParams = new HttpParams().set('attendeeIds', args.attendeeIds.join(','));

        return this.http.get(`/url`,{params});

results in an url that looks like this /url?&attendeeIds=Some-id-1,Some-id-2"

which is not what the server expects

when passing the params directly like below

    return this.http.get(`/url`,{params: {attendeeIds: args.attendeeIds});

the url looks like this /url?&attendeeIds=Some-id-1&attendeeIds=Some-id-2, which is more what the server expects.

hope this helps someone

2 Comments

You're making a huge assumption about what the server expects. There is no standard for this, so what the server expects will be dependent on what technologies/frameworks/libraries are being used on the server.
yes of course, this was for my specific use case.
0

Use appendAll:

let params = new HttpParams();
params = params.appendAll({ 'roleIds': [10, 20] });

Comments

-1

Here is a simple way to do it:

this.http.get(url, { 
    params: ['Elvis', 'Jane', 'Frances'].reduce((accumulator, name) => accumulator.append('names', name), new HttpParams())
});

1 Comment

This generates a query string of ?names=Elvis&names=Jane&names=Frances. I think the other answers that generate a query string in this format are simpler and easier to read, but if this is a format your backend recognizes, it will work.
-2

Adding this in case anybody comes across it. I was able to override the default behavior, but only by overriding the HttpParams class and utilizing an interceptor. It changes the arrayed-values' parameter name to be appended with the expected '[]'.

class ArrayHttpParams extends HttpParams {
    constructor(options?: any) {
        if (options.cloneParams) {
            const {encoder} : {encoder: HttpUrlEncodingCodec} = options.cloneParams;
            options.encoder = encoder;
        }
        super(options);
        if (options.cloneParams) {
            const {updates, cloneFrom, map} : {updates: any[], cloneFrom: any, map: Map<string, string>} = options.cloneParams;
            (<any>this).updates = updates;
            (<any>this).cloneFrom = cloneFrom || null;
            (<any>this).map = map;
        }
    }
    toString(): string {
        super.toString();
        const {encoder} : {encoder: HttpUrlEncodingCodec} = <any>this;

        return this.keys()
            .map(key => {
                const values = this.getAll(key);
                const encodedKey = encoder.encodeKey(key) + (values.length > 1 ? '[]' : '');

                return values.map(value => encodedKey + '=' + encoder.encodeValue(value)).join('&');
            })
            .filter(param => param !== '')
            .join('&');
    }
}

class MyInterceptor implements HttpInterceptor {
    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        let params = null;
        if (req.method === 'GET' && req.params) {
            params = new ArrayHttpParams({cloneParams: req.params});
        }
        req = req.clone({
            setHeaders: headers,
            params: params || req.params
        });

        return next.handle(req);
    }
}

2 Comments

As a caveat to my solution from Feb 2021, it only works when the expected array has more than 1 entry. This is due to the way that Angular's HttpParams initializes from an object and stores all parameter values as an array, regardless of whether the value is intended as an array or not.
As other answers have provided, it's possible to generate a query string with this format in much simpler ways than this, using the HttpParams as is, or even with just a plain Object.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.