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');works. для тех, кто устанавливает только 2, также хорош ответ от другого пользователя ниже.
Angela P
1
просто используйте присвоение (=), как предложил @AngelaPan, и вам не нужно использовать цикл. Также читайте об изменчивом и неизменном.
Junaid
пожалуйста, проголосуйте за функцию условного обновления набора HttpParams: github.com/angular/angular/issues/26021
Serge

Ответы:

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
Киран
2
Параметры строки типа с нулевым значением вернут «null» и не поддерживают число, логическое значение и дату
Омар АМЕЗУГ
Вот ссылка на отчет об ошибке из-за отсутствия поддержки 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, это была точка блокировки и должен быть принятый ответ
Николас,
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? Это может быть любой объект.
Кристиан Мэтью,
@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 (), назначающего вывод новой переменной, как предлагал OP в своем обновлении.
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);
Debojyoti
источник
Это должен быть принятый ответ. Просто и чисто.
Карсус
14

Другой вариант сделать это:

this.httpClient.get('path', {
    params: Object.entries(data).reduce(
    (params, [key, value]) => params.set(key, value), new HttpParams());
});
Лейбале Эйдельман
источник
Вы можете добавить полифилл ( stackoverflow.com/questions/42410029/… )
Лейбале Эйдельман
придется попробовать это волшебство
Кристиан Мэтью
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);

Используйте append, если вы используете set, оно перезапишет предыдущее значение с тем же именем ключа.

Луиджи Кордова Гранера
источник
0

Эти решения работают для меня,

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

Ротче
источник