Angular 4.3-HttpClient设置参数


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

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

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

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

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

3
我同意您的httpParams.set('bbb', '222');建议。我先尝试了一下,感到很困惑。但是用httpParams = httpParams.set('bbb','222');工程代替那条线。对于仅设置2的用户,来自下面另一个用户的链接答案也很好。
安吉拉·P

1
只需使用@AngelaPan建议的赋值(=),就不必使用循环。另请参阅有关可变和不变的内容。
Junaid

请投票给有条件的HttpParams集更新功能:github.com/angular/angular/issues/26021
Serge

Answers:


92

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})
}

我使用的是5.2.6,除非我明确将其设置为,否则肯定不会为params编写字典any。那真的是预期用途吗?
石像鬼'18

6
@Gargoyle-您可以将对象强制转换为任何对象,{ params: <any>params }以避免ts编译器问题
Kieran

2
字符串类型的PARAMS是空将返回“空”,不支持数字,布尔和日期
奥马尔AMEZOUG

这是缺少Number,Boolean和Date支持的错误报告的链接:github.com/angular/angular/issues/23856
EpicVoyage

83

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

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

1
不变的HttpParams的选择多么奇怪,这是一个障碍,应该成为公认的答案
Nicolas

45

@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]);
});

为什么要说fromObject?它可以是任何对象。
克里斯蒂安·马修·

@ChristianMatthew的构造函数的HttpParams 不能采取“任何对象”,它需要HttpParamsOptions。如果您的意思是可以将任何对象作为参数传递给请求:是的,但仅限于v5。否则,我不确定您要问什么。
jonrsharpe

fromObject的词<<什么是正确的
基督徒Matthew

@ChristianMatthew我不知道你在问什么。您想知道那是什么财产吗?您看过API文档了吗?还是答案中的例子?
jonrsharpe

1
@ChristianMatthew我不知道你在问什么。您的意思是“ API版本”。版本?您可以在答案中看到我链接到的提交,我明确说它是在5.0中引入的。您也可以立即在master中查看它:github.com/angular/angular/blob/master/packages/common/http/src/…。我不清楚你有什么问题
jonrsharpe

21

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

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

3
HttpParams像HttpHeaders一样是不可变的,这意味着第二个.set()调用在这种情况下将不起作用。它需要一键设置,也可以使用.append()方法将输出分配给新变量,如OP在更新时建议的那样。
WPalombini

2
@WPalombini我刚刚尝试了Mike的链套。它确实有效!我认为对只有2个参数的人来说很好。很容易理解。
安吉拉·P

19

几个简单的选择

不使用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);

这应该是公认的答案。简单干净。
Karsus



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这样的通用功能,则可以轻松删除它或根据需要进行更改。


嗨,它的工作
原理

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

PS:记住setappend方法之间的区别;)


有什么区别?
克里斯蒂安·马修·

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

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

您真的不需要这个,Angularparams.ts有自己的编码。检查实施:github.com/angular/angular/blob/master/packages/common/http/src/...
Davideas

1

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

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

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


0

这个解决方案对我有用,

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.