Кутовий 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, і вам не потрібно використовувати цикл. Також читайте про змінні та незмінні.
Джунайд

проголосуйте, будь ласка, за умовну функцію оновлення набору HttpParams
Серж

Відповіді:


93

До 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. Це насправді передбачуване використання?
Гаргулья

6
@Gargoyle - ти можеш просто передати свій об'єкт будь-якому, { params: <any>params }щоб уникнути проблем із компілятором ts
Kieran,

2
Параметри типу string, які мають значення null, повертають значення "null" і не підтримують номер, логічне значення та дату
Omar AMEZOUG

Ось посилання на звіт про помилку через відсутність підтримки номера, булевого значення та дати: 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, це було блокуючим моментом і повинно бути прийнятою відповіддю
Ніколас

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

чому ти кажеш відObject? Це може бути будь-який предмет.
Крістіан Метью

@ChristianMatthew конструктор HttpParams не може взяти "будь-який об'єкт", він приймає HttpParamsOptions. Якщо ви маєте на увазі, ви можете передати будь-який об'єкт як параметри запиту: так, але тільки з v5. Інакше я не впевнений, про що ви питаєте.
jonrsharpe

слово fromObject << що це правильно
Крістіан Матвій

@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 (), призначаючи висновок новій змінній, як запропоновано ОП у його оновленні.
WPalombini

2
@WPalombini Я щойно спробував набір ланцюжків Майка. і це працює! Я думаю, це приємно для людей, які мають лише 2 параметри. Це легко зрозуміти.
Angela 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);

Це має бути прийнятою відповіддю. Просто і чисто.
Карсус,


9

Оскільки клас HTTP Params є незмінним, тож вам потрібно встановити ланцюжок методу set:

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

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: Пам'ятайте про різницю між set і appendметодами;)


які відмінності?
Крістіан Метью

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

Вам це дійсно не потрібно, у 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);

Використовуйте додаток, якщо ви використовуєте set, він перезапише попереднє значення з тим самим іменем ключа.


0

Ці рішення працюють для мене,

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.