Angular 4.3 - พารามิเตอร์ชุด HttpClient


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

3
ฉันเห็นด้วยกับคุณว่าhttpParams.set('bbb', '222');ควรทำงาน ฉันลองครั้งแรกและรู้สึกสับสนมาก แต่แทนที่บรรทัดนั้นด้วยhttpParams = httpParams.set('bbb','222');ผลงาน สำหรับผู้ที่กำลังตั้งค่า 2 เท่านั้นคำตอบของผู้ใช้รายอื่นด้านล่างก็ดีเช่นกัน
Angela P

1
เพียงใช้การกำหนด (=) ตามที่ @AngelaPan แนะนำและคุณไม่ต้องใช้ loop อ่านเพิ่มเติมเกี่ยวกับการเปลี่ยนแปลงและไม่เปลี่ยนรูป
Junaid

โปรดโหวตคุณสมบัติการอัปเดตชุด HttpParams ตามเงื่อนไข: github.com/angular/angular/issues/26021
เสิร์จ

คำตอบ:


94

ก่อน 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เว้นแต่ฉันอย่างชัดเจนกรณีที่มันจะ นั่นคือวัตถุประสงค์การใช้งานจริงๆหรือ
Gargoyle

6
@Gargoyle - คุณสามารถโยนวัตถุของคุณไปที่ใดก็ได้{ params: <any>params }เพื่อหลีกเลี่ยงปัญหาคอมไพเลอร์ ts
Kieran

2
Params ของสตริงประเภทที่เป็น null จะส่งคืน "null" และไม่รองรับ Number, Boolean และ Date
Omar AMEZOUG

นี่คือลิงค์ไปยังรายงานข้อบกพร่องสำหรับการขาดการสนับสนุน Number, Boolean และ Date: github.com/angular/angular/issues/23856
EpicVoyage

83

HttpParams มีวัตถุประสงค์เพื่อไม่เปลี่ยนรูป setและappendวิธีการไม่แก้ไขอินสแตนซ์ที่มีอยู่ แต่จะส่งคืนอินสแตนซ์ใหม่โดยใช้การเปลี่ยนแปลง

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 ขึ้นไปตามรูปลักษณ์ของมัน) คุณสามารถใช้fromObjectคีย์HttpParamsOptionsเพื่อส่งผ่านวัตถุใน:

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? มันสามารถเป็นวัตถุใดก็ได้
Christian Matthew

@ChristianMatthew ผู้สร้างHttpParams ไม่สามารถใช้ "วัตถุใด ๆ " ได้ต้องใช้ HttpParamsOptions หากคุณหมายความว่าคุณสามารถส่งผ่านวัตถุใด ๆ เป็นพารามิเตอร์ไปยังคำขอได้: ใช่ แต่จาก v5 เท่านั้น ไม่งั้นฉันไม่แน่ใจว่าคุณกำลังถามอะไร
jonrsharpe

คำจากวัตถุ << ที่ถูกต้อง
คริสเตียนแมทธิว

@ChristianMatthew ฉันไม่รู้ว่าคุณกำลังถามอะไร คุณอยากรู้ไหมว่าทรัพย์สินนั้นคืออะไร? คุณดูเอกสาร API หรือไม่ หรือตัวอย่างในคำตอบ?
jonrsharpe

1
@ChristianMatthew ฉันไม่รู้ว่าคุณกำลังถามอะไร คุณหมายถึงอะไร "เวอร์ชัน API" รุ่นเชิงมุม ? คุณสามารถดูว่าฉันเชื่อมโยงไปถึงข้อใดในคำตอบและฉันบอกอย่างชัดเจนว่ามันถูกนำมาใช้ใน 5.0 คุณสามารถเข้าไปดูในมาสเตอร์ได้ทันที: 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 ฉันเพิ่งลองชุดโซ่ของไมค์ และมันได้ผล! ฉันคิดว่ามันดีสำหรับคนที่มี 2 พารามิเตอร์เท่านั้น เป็นเรื่องง่ายที่จะเข้าใจ
Angela P

19

ทางเลือกง่ายๆคู่หนึ่ง

โดยไม่ต้องใช้HttpParamsObjects

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

this.http.post(url, body);

การใช้HttpParamsObjects

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 ที่กล่าวถึงข้างต้นคุณสามารถลบออกหรือทำการเปลี่ยนแปลงได้อย่างง่ายดายหากจำเป็น


สวัสดีมันทำงานได้ดี แต่ต่อท้ายค่าคีย์ที่ไม่ได้กำหนดพิเศษเป็นพารามิเตอร์
Abhijit Jagtap

3

เท่าที่ฉันเห็นจากการใช้งานที่https://github.com/angular/angular/blob/master/packages/common/http/src/params.ts

คุณต้องระบุค่าแยกกัน - คุณไม่สามารถหลีกเลี่ยงการวนซ้ำของคุณได้

นอกจากนี้ยังมีตัวสร้างที่ใช้สตริงเป็นพารามิเตอร์ แต่มันอยู่ในรูปแบบparam=value&param2=value2ดังนั้นจึงไม่มีข้อตกลงสำหรับคุณ (ในทั้งสองกรณีคุณจะจบด้วยการวนซ้ำวัตถุของคุณ)

คุณสามารถรายงานปัญหา / คำขอคุณสมบัติเป็นเชิงมุมได้ตลอดเวลาสิ่งที่ฉันแนะนำเป็นอย่างยิ่ง: https://github.com/angular/angular/issues

PS: จำเกี่ยวกับความแตกต่างระหว่างsetและappendวิธีการ;)


อะไรคือความแตกต่าง?
Christian Matthew

2

เนื่องจาก @MaciejTreder ยืนยันว่าเราต้องวนซ้ำนี่คือ Wrapper ที่จะให้คุณเพิ่มลงในชุดพารามิเตอร์เริ่มต้น:

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

คุณไม่ต้องการสิ่งนี้จริงๆ Angular params.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()); });

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.