【Angular4】urlencoded用にobjectを変換

Angular4にてHttpリクエストをJSONではなくurlencodedで行おうとしたときに、Objectがnestしている場合にうまくいきませんでした。

順を追って記載しますが、お急ぎの方は最終的なコードが記事の下部にありますのでそちらからどうぞ。

さて、本題です。

まずはリクエストパラメータの基本的な指定方法です。

const data = {
  firstName: 'taro',
  lastName: 'yamada',
  age: 30
};

const headers = new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' });

let params = new HttpParams();

params = params.set('firstName', data.firstName);  
params = params.set('lastName', data.lastName);  
params = params.set('age', data.age);  

パラメータを個別にsetしていくわけですね。

これを動的にするために以下のようにしてみました。

const data = {
  firstName: 'taro',
  lastName: 'yamada',
  age: 30
};

const headers = new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' });

let params = new HttpParams();

for (var key in data) {
  params = params.set(key, data[key]);  
}

しかし、これではオブジェクトの中にオブジェクトがあったり、配列があったり、オブジェクトが入れ子になっている場合には対応できません。

例えば、以下のようなオブジェクト構造です。

const data = {
  firstName: 'taro',
  lastName: 'yamada',
  age: 30,
  job: [
    {
      name: 'first-company',
      join: '2015-04-01'
    },
    {
      name: 'second-company',
      join: '2018-04-01'
    }
  ],
  skill: ['skill1', 'skill2', 'skill3']
};

こういった構造の時、前述したコードではパラメータが [object object] という風に設定されてしまいました。

オブジェクトの構造が可変でも、汎用的に利用できるようにしたいところですね。

「サンプルコードはないかな」とJSONデータをURLEncodedに変換するコードを調べてみたところ、ちょうどいいコードがGitHubに公開されていました。

function JSON_to_URLEncoded(element,key,list){
  var list = list || [];
  if(typeof(element)=='object'){
    for (var idx in element)
      JSON_to_URLEncoded(element[idx],key?key+'['+idx+']':idx,list);
  } else {
    list.push(key+'='+encodeURIComponent(element));
  }
  return list.join('&');
}
引用元: JSON_to_URLEncoded.js

ははぁん。なるほど。関数を再帰的に利用するやーつ。

参考にさせていただきましょう。

// TSファイル
setHttpParams(element, httpParams: HttpParams, key?) {
  if (typeof(element) == 'object') {
    for (var idx in element) {
      httpParams = this.setHttpParams(element[idx], httpParams, key ? key + '[' + idx + ']' : idx);
    }
  } else {
    httpParams = httpParams.set(key, element);
  }
  return httpParams;
}

これでオブジェクトの構造がネストしてても対応できます。

呼び出すときには以下のような形になります。

const data = {
  // 素敵なオブジェクト
}

const reqOpts = {
  headers: new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' })
};

let params = new HttpParams();

params = this.setHttpParams(data, params);

this.http.post('https://~~~', params, reqOpts);

前述した入れ子になったオブジェクトを変換すると、以下のような形になります。

firstName: 'taro',
lastName: 'yamada',
age: 30,
job[0][name]: 'first-company',
job[0][join]: '2015-04-01',
job[1][name]: 'second-company',
job[1][join]: '2018-04-01',
skill[0]: 'skill1',
skill[1]: 'skill2',
skill[2]: 'skill3'

人気記事すべて表示

WEBすべて表示