104
let httpParams = new HttpParams().set('aaa', '111');
httpParams.set('bbb', '222');

为什么这不起作用?它只设置 'aaa' 而不是 'bbb'

另外,我有一个对象 { aaa: 111, bbb: 222 } 如何在不循环的情况下设置所有值?

更新(这似乎有效,但如何避免循环?)

let httpParams = new HttpParams();
Object.keys(data).forEach(function (key) {
     httpParams = httpParams.append(key, data[key]);
});
4

15 回答 15

102

5.0.0-beta.6 之前

let httpParams = new HttpParams();
Object.keys(data).forEach(function (key) {
     httpParams = httpParams.append(key, data[key]);
});

从 5.0.0-beta.6 开始

自 5.0.0-beta.6 (2017-09-03) 以来,他们添加了新功能(接受 HttpClient 标头和参数的对象映射)

以后可以直接传递对象而不是 HttpParams。

getCountries(data: any) {
    // We don't need any more these lines
    // let httpParams = new HttpParams();
    // Object.keys(data).forEach(function (key) {
    //     httpParams = httpParams.append(key, data[key]);
    // });

    return this.httpClient.get("/api/countries", {params: data})
}
于 2017-08-01T04:22:38.170 回答
95

HttpParams 旨在是不可变的。setandappend方法不会修改现有实例。相反,它们会返回新实例,并应用更改。

let params = new HttpParams().set('aaa', 'A');    // now it has aaa
params = params.set('bbb', 'B');                  // now it has both

这种方法适用于方法链:

const params = new HttpParams()
  .set('one', '1')
  .set('two', '2');

...尽管如果您需要将它们中的任何一个包装在条件中,这可能会很尴尬。

您的循环有效,因为您正在获取对返回的新实例的引用。您发布的代码不起作用,不起作用。它只是调用 set() 但不获取结果。

let httpParams = new HttpParams().set('aaa', '111'); // now it has aaa
httpParams.set('bbb', '222');                        // result has both but is discarded
于 2017-07-31T23:35:29.993 回答
54

在更新的版本@angular/common/http(从外观上看,5.0 及更高版本)中,您可以使用fromObjectHttpParamsOptions直接传递对象:

let httpParams = new HttpParams({ fromObject: { aaa: 111, bbb: 222 } });

不过,这只是在引擎盖下forEach运行一个循环:

this.map = new Map<string, string[]>();
Object.keys(options.fromObject).forEach(key => {
  const value = (options.fromObject as any)[key];
  this.map !.set(key, Array.isArray(value) ? value : [value]);
});
于 2017-12-21T15:48:53.877 回答
29

几个简单的选择

不使用HttpParams对象

let body = {
   params : {
    'email' : emailId,
    'password' : password
   }
}

this.http.post(url, body);

使用HttpParams对象

let body = new HttpParams({
  fromObject : {
    'email' : emailId,
    'password' : password
  }
})

this.http.post(url, body);
于 2018-06-27T12:11:38.097 回答
22

对我来说,链接set方法是最干净的方法

const params = new HttpParams()
.set('aaa', '111')
.set('bbb', "222");
于 2017-07-26T14:32:42.700 回答
18

另一种方法是:

this.httpClient.get('path', {
    params: Object.entries(data).reduce((params, [key, value]) => params.set(key, value), new HttpParams());
});
于 2017-09-06T10:47:33.457 回答
9

由于 HTTP Params 类是不可变的,因此您需要链接 set 方法:

const params = new HttpParams()
.set('aaa', '111')
.set('bbb', "222");
于 2018-05-16T13:21:20.673 回答
7

使用它可以避免循环。

// obj is the params object with key-value pair. 
// This is how you convert that to HttpParams and pass this to GET API. 

const params = Object.getOwnPropertyNames(obj)
               .reduce((p, key) => p.set(key, obj[key]), new HttpParams());

此外,我建议在您常用的服务中制作toHttpParams函数。因此,您可以调用该函数将对象转换为HttpParams

/**
 * Convert Object to HttpParams
 * @param {Object} obj
 * @returns {HttpParams}
 */
toHttpParams(obj: Object): HttpParams {
    return Object.getOwnPropertyNames(obj)
        .reduce((p, key) => p.set(key, obj[key]), new HttpParams());
}

更新:

自 5.0.0-beta.6 (2017-09-03) 以来,他们添加了新功能(接受 HttpClient 标头和参数的对象映射

以后可以直接传递对象而不是 HttpParams。

这是另一个原因,如果您使用了上面提到的toHttpParams 之类的常用函数,您可以轻松删除它或在需要时进行更改。

于 2017-11-09T21:34:15.197 回答
3

据我从https://github.com/angular/angular/blob/master/packages/common/http/src/params.ts的实现中可以看出

您必须单独提供值 - 您无法避免循环。

还有一个构造函数,它接受一个字符串作为参数,但它的形式是这样的param=value&param2=value2,所以对你来说没有任何交易(在这两种情况下,你都将完成循环你的对象)。

您始终可以向 Angular 报告问题/功能请求,我强烈建议您这样做: https ://github.com/angular/angular/issues

setPS:记住和方法之间的区别append;)

于 2017-07-20T10:19:46.343 回答
2

由于@MaciejTreder 确认我们必须循环,这里有一个包装器,可以选择让您添加到一组默认参数:

function genParams(params: object, httpParams = new HttpParams()): object {
    Object.keys(params)
        .filter(key => {
            let v = params[key];
            return (Array.isArray(v) || typeof v === 'string') ? 
                (v.length > 0) : 
                (v !== null && v !== undefined);
        })
        .forEach(key => {
            httpParams = httpParams.set(key, params[key]);
        });
    return { params: httpParams };
}

你可以像这样使用它:

const OPTIONS = {
    headers: new HttpHeaders({
        'Content-Type': 'application/json'
    }),
    params: new HttpParams().set('verbose', 'true')
};
let opts = Object.assign({}, OPTIONS, genParams({ id: 1 }, OPTIONS.params));
this.http.get(BASE_URL, opts); // --> ...?verbose=true&id=1
于 2017-08-16T20:31:10.613 回答
2

我的助手类(ts)将任何复杂的 dto 对象(不仅是“字符串字典”)转换为 HttpParams:

import { HttpParams } from "@angular/common/http";

export class HttpHelper {
  static toHttpParams(obj: any): HttpParams {
    return this.addToHttpParams(new HttpParams(), obj, null);
  }

  private static addToHttpParams(params: HttpParams, obj: any, prefix: string): HttpParams {    
    for (const p in obj) {
      if (obj.hasOwnProperty(p)) {
        var k = p;
        if (prefix) {
          if (p.match(/^-{0,1}\d+$/)) {
            k = prefix + "[" + p + "]";
          } else {
            k = prefix + "." + p;
          }
        }        
        var v = obj[p];
        if (v !== null && typeof v === "object" && !(v instanceof Date)) {
          params = this.addToHttpParams(params, v, k);
        } else if (v !== undefined) {
          if (v instanceof Date) {
            params = params.set(k, (v as Date).toISOString()); //serialize date as you want
          }
          else {
            params = params.set(k, v);
          }

        }
      }
    }
    return params;
  }
}

console.info(
  HttpHelper.toHttpParams({
    id: 10,
    date: new Date(),
    states: [1, 3],
    child: {
      code: "111"
    }
  }).toString()
); // id=10&date=2019-08-02T13:19:09.014Z&states%5B0%5D=1&states%5B1%5D=3&child.code=111
于 2019-08-02T13:25:06.373 回答
2

只是想添加,如果您想添加多个具有相同键名的参数,例如:www.test.com/home?id=1&id=2

let params = new HttpParams();
params = params.append(key, value);

使用append,如果使用set,它会用相同的键名覆盖之前的值。

于 2020-06-09T12:55:28.620 回答
2

appendAll 函数

import { HttpParams } from "@angular/common/http";

export class BuildUrl {

    /**
     * append all params
     * @param args {unknown[]}
     * @returns {HttpParams}
     */
    static appendAll(...args: unknown[]): HttpParams {
        let params = new HttpParams();
        args.forEach(param => {
            Object.keys(param).forEach((key) => {
                params = params.append(key, param[key]);
            });
        });
        return params;
    }
}

我们如何在服务中使用它。

getData( pag: PaginationRequest, description: string = ''): Observable<any> {
    const params = BuildUrl.appendAll(pag,
      { description },
    );
    return this.http.get(url, { params });
  }
于 2021-03-11T14:43:41.853 回答
1

这个解决方案对我有用,

let params = new HttpParams(); Object.keys(data).forEach(p => { params = params.append(p.toString(), data[p].toString()); });

于 2019-06-27T19:15:33.760 回答
0

使用 set()

来自set() 的 Angular 官方文档

set(param: string, value: string | number | boolean): HttpParams

返回 HttpParams:具有新值的新主体。

现在,让我们看看如何添加一些参数 -

const params = new HttpParams()
    .set('aaa', '111')
    .set('bbb', "222");

请注意,我们通过链接 set() 方法来构造 HTTPParams 对象。原因是HTTPParams 是不可变的

每次调用 set 方法都会返回一个带有新值的新 HttpParams 对象。我们需要首先获取返回的 HttpParams 对象,然后使用它进行进一步修改。

因此,如果我们执行以下操作,它将不起作用

const params = new HttpParams(); // empty HttpParams object

params.set('aaa', '111'); // lost
params.set('bbb', "222"); // lost

我们只调用set但不保留返回的HttpParams对象。因此,最后我们将有一个空的 HttpParams 对象,并且对 set 的两次调用将没有任何效果。为了使其工作,我们需要执行以下操作 -

const params = new HttpParams(); // empty HttpParams object

params = params.set('aaa', '111'); // storing the returned HttpParams object, now **it has aaa**
params = params.set('bbb', "222"); // add another parameter and store it. so now **it has both aaa and bbb**

使用 fromString

您还可以使用 fromString 创建 httpParams。当您已经准备好查询参数字符串时,这很好。你可以使用以下语法来做到这一点

const params = new HttpParams({
  fromString: 'aaa=111&bbb=222'
});
于 2021-08-19T07:56:23.463 回答