Angular 4.3 - HttpClient setzt Parameter

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

Warum funktioniert das nicht? Es wird nur das 'aaa' und NICHT das 'bbb' gesetzt.

Außerdem habe ich ein Objekt {aaa: 111, bbb: 222}. Wie kann ich alle Werte ohne Schleife festlegen?

UPDATE (dies scheint zu funktionieren, aber wie kann die Schleife vermieden werden?)

let httpParams = new HttpParams();
Object.keys(data).forEach(function (key) {
     httpParams = httpParams.append(key, data[key]);
});
Michalis
quelle
3
Ich stimme Ihnen zu, dass httpParams.set('bbb', '222');das funktionieren sollte. Ich habe das zuerst versucht und war sehr verwirrt. Aber ersetzen Sie diese Zeile durch httpParams = httpParams.set('bbb','222');Werke. Für diejenigen, die nur 2 setzen, ist die Verkettungsantwort eines anderen Benutzers unten ebenfalls nett.
Angela P
1
Verwenden Sie einfach die Zuweisung (=), wie von @AngelaPan vorgeschlagen, und Sie müssen keine Schleife verwenden. Lesen Sie auch über veränderlich und unveränderlich.
Junaid
Bitte stimmen Sie für die bedingte Update-Funktion von HttpParams ab: github.com/angular/angular/issues/26021
Serge

Antworten:

88

Vor 5.0.0-beta.6

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

Seit 5.0.0-beta.6

Seit 5.0.0-beta.6 (03.09.2017) wurde eine neue Funktion hinzugefügt (Objektzuordnung für HttpClient-Header und -Parameter akzeptieren).

In Zukunft kann das Objekt direkt anstelle von HttpParams übergeben werden.

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})
}
Michalis
quelle
Ich verwende 5.2.6 und es wird definitiv kein Wörterbuch für das params-Stück benötigt, es sei denn, ich mache es ausdrücklich any. Ist das wirklich der Verwendungszweck?
Gargoyle
6
@ Gargoyle - Sie können Ihr Objekt einfach in ein beliebiges Objekt umwandeln { params: <any>params }, um Probleme mit dem Compiler zu vermeiden
Kieran
2
Parameter vom Typ string, die null sind, geben "null" zurück und unterstützen nicht Number, Boolean und Date
Omar AMEZOUG
Hier ist ein Link zum Fehlerbericht für den Mangel an Unterstützung für
Zahlen
80

HttpParams soll unveränderlich sein. Die Methoden setund appendändern die vorhandene Instanz nicht. Stattdessen geben sie neue Instanzen mit den vorgenommenen Änderungen zurück.

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

Dieser Ansatz funktioniert gut mit Methodenverkettung:

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

... obwohl das unangenehm sein kann, wenn Sie einen von ihnen unter bestimmten Bedingungen einwickeln müssen.

Ihre Schleife funktioniert, weil Sie einen Verweis auf die zurückgegebene neue Instanz abrufen. Der Code, den Sie gepostet haben und der nicht funktioniert, funktioniert nicht. Es ruft nur set () auf, erfasst aber nicht das Ergebnis.

let httpParams = new HttpParams().set('aaa', '111'); // now it has aaa
httpParams.set('bbb', '222');                        // result has both but is discarded
Reich
quelle
Wie bizarr die Wahl eines unveränderlichen HttpParams war, dies war der Blockierungspunkt und sollte die akzeptierte Antwort sein
Nicolas
45

In neueren Versionen von @angular/common/http(5.0 und höher , wie es aussieht) können Sie den fromObjectSchlüssel von verwenden HttpParamsOptions, um das Objekt direkt zu übergeben:

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

Dies führt jedoch nur eine forEachSchleife unter der Haube :

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]);
});
Jonrsharpe
quelle
warum sagst du fromObject? Es kann jedes Objekt sein.
Christian Matthew
@ChristianMatthew, der Konstruktor von HttpParams, kann "kein Objekt" annehmen, sondern HttpParamsOptions. Wenn Sie meinen, Sie können jedes Objekt als Parameter an eine Anfrage übergeben: Ja, aber nur ab Version 5. Ansonsten bin ich mir nicht sicher, was du fragst.
Jonrsharpe
das Wort vonObject << was ist das richtig
Christian Matthew
@ChristianMatthew Ich weiß nicht, was Sie fragen. Möchten Sie wissen, was diese Eigenschaft ist? Haben Sie sich die API-Dokumente angesehen? Oder das Beispiel in der Antwort?
Jonrsharpe
1
@ChristianMatthew Ich weiß nicht, was Sie fragen. Was meinst du mit "API-Version". Winkelversion ? Sie können in der Antwort sehen, mit welchem ​​Commit ich verlinkt habe, und ich habe ausdrücklich gesagt, dass es in 5.0 eingeführt wurde. Sie können es jetzt auch im Master anzeigen : github.com/angular/angular/blob/master/packages/common/http/src/… . Mir ist nicht klar, welches Problem Sie haben.
Jonrsharpe
21

Verkettungsmethoden setsind für mich der sauberste Weg

const params = new HttpParams()
.set('aaa', '111')
.set('bbb', "222");
Mike Kovetsky
quelle
3
HttpParams ist wie HttpHeaders unveränderlich, was bedeutet, dass der zweite Aufruf von .set () in diesem Fall nicht funktioniert. Es muss mit einem Schlag festgelegt werden oder geht mit der .append () -Methode einher, die die Ausgabe einer neuen Variablen zuweist, wie es das OP bei seinem Update vorgeschlagen hat.
WPalombini
2
@WPalombini Ich habe gerade Mikes Verkettungsset ausprobiert. und es funktioniert! Ich finde es schön für Leute, die nur 2 Parameter haben. Es ist leicht zu verstehen.
Angela P
18

Ein paar einfache Alternativen

Ohne HttpParamsObjekte zu verwenden

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

this.http.post(url, body);

Mit HttpParamsObjekten

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

this.http.post(url, body);
Debojyoti
quelle
Dies sollte die akzeptierte Antwort sein. Einfach und sauber.
Karsus
14

Eine andere Möglichkeit, dies zu tun, ist:

this.httpClient.get('path', {
    params: Object.entries(data).reduce(
    (params, [key, value]) => params.set(key, value), new HttpParams());
});
Leibale Eidelman
quelle
Sie können eine Polyfüllung hinzufügen ( stackoverflow.com/questions/42410029/… )
Leibale Eidelman
Ich werde diese Zauberei ausprobieren müssen
Christian Matthew
9

Da die HTTP-Params-Klasse unveränderlich ist, müssen Sie die set-Methode verketten:

const params = new HttpParams()
.set('aaa', '111')
.set('bbb', "222");
Adnan Abdul Khaliq
quelle
7

Auf diese Weise können Sie die Schleife vermeiden.

// 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());

Darüber hinaus empfehle ich, toHttpParams in Ihrem häufig verwendeten Dienst funktionsfähig zu machen. Sie können also die Funktion aufrufen, um das Objekt in die HttpParams zu konvertieren .

/**
 * 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());
}

Aktualisieren:

Seit 5.0.0-beta.6 (03.09.2017) wurde eine neue Funktion hinzugefügt ( Objektzuordnung für HttpClient-Header und -Parameter akzeptieren ).

In Zukunft kann das Objekt direkt anstelle von HttpParams übergeben werden.

Dies ist der andere Grund, warum Sie, wenn Sie eine allgemeine Funktion wie die oben genannten toHttpParams verwendet haben , diese einfach entfernen oder bei Bedarf Änderungen vornehmen können.

Lahar Shah
quelle
Hallo, es funktioniert gut, aber füge einen zusätzlichen undefinierten Schlüsselwert als Parameter hinzu
Abhijit Jagtap
3

Soweit ich aus der Implementierung unter https://github.com/angular/angular/blob/master/packages/common/http/src/params.ts ersehen kann

Sie müssen Werte separat angeben - Sie können Ihre Schleife nicht umgehen.

Es gibt auch einen Konstruktor, der eine Zeichenfolge als Parameter verwendet, diese jedoch in der Form vorliegt, param=value&param2=value2sodass für Sie kein Deal besteht (in beiden Fällen beenden Sie die Schleife Ihres Objekts).

Sie können Angular jederzeit eine Problem- / Funktionsanforderung melden, was ich dringend empfehle: https://github.com/angular/angular/issues

PS: Denken Sie an den Unterschied zwischen setund appendMethoden;)

Maciej Treder
quelle
Was sind die Unterschiede?
Christian Matthew
2

Da @MaciejTreder bestätigt hat, dass eine Schleife ausgeführt werden muss, finden Sie hier einen Wrapper, mit dem Sie optional eine Reihe von Standardparametern hinzufügen können:

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

Sie können es so verwenden:

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
James Irwin
quelle
2

Meine Hilfsklasse (ts) zum Konvertieren eines komplexen dto-Objekts (nicht nur "String-Wörterbuch") in 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
iliakolesnikov
quelle
Das brauchen Sie wirklich nicht, der Angular params.tshat eine eigene Codierung. Überprüfen Sie die Implementierung: github.com/angular/angular/blob/master/packages/common/http/src/…
Davideas
0

Diese Lösungen funktionieren für mich,

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

Rotceh
quelle
0

Ich wollte das nur hinzufügen, wenn Sie mehrere Parameter mit demselben Schlüsselnamen hinzufügen möchten, zum Beispiel: www.test.com/home?id=1&id=2

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

Verwenden Sie Anhängen. Wenn Sie set verwenden, wird der vorherige Wert mit demselben Schlüsselnamen überschrieben.

Luigi Cordoba Granera
quelle