18

I wish to convert a JS object into x-www-form-urlencoded. How can I achieve this in angular 2?

export class Compentency {
  competencies : number[];
}
postData() {
        let array =  [1, 2, 3];
        this.comp.competencies = array;
        let  headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' });
        let options = new RequestOptions({ headers: headers, method: 'post' });
        return this.http.post(this.postUrl, JSON.stringify(this.comp), options)
        .map(res => res.json().data.competencies)
        .catch(this.handleError);
    }
Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
Manohar
  • 1,095
  • 2
  • 10
  • 16
  • Possible duplicate of [How to make Angular 2 send all requests as application/x-www-form-urlencoded](http://stackoverflow.com/questions/34704654/how-to-make-angular-2-send-all-requests-as-application-x-www-form-urlencoded) – ulou Sep 30 '16 at 08:41
  • From my understanding you are trying to do what jQuery does with it's $.param function. If you look at Rafal's answer from here (https://stackoverflow.com/a/31387918) he says Angular has a built in function that does the same. You may already have your answer but I would imagine this would be a better implementation since you are using existing code that is within the framework vs writing your own. – Eddie Oct 06 '20 at 18:59

7 Answers7

23

let o = { a:1, b:'2', c:true };
let s = new URLSearchParams(Object.entries(o)).toString();
console.log(s); 
Joundill
  • 6,828
  • 12
  • 36
  • 50
Denis TRUFFAUT
  • 1,017
  • 10
  • 11
  • 3
    You can also pass the object into URLSearchParams directly, like so: `new URLSearchParams(o).toString()` – nkhil Sep 10 '21 at 09:20
7

application/x-www-form-urlencoded

Control names and values are escaped. Space characters are replaced by +, and then reserved characters are escaped as described in [RFC1738], section 2.2: Non-alphanumeric characters are replaced by %HH, a percent sign and two hexadecimal digits representing the ASCII code of the character. Line breaks are represented as "CR LF" pairs (i.e., %0D%0A). The control names/values are listed in the order they appear in the document. The name is separated from the value by = and name/value pairs are separated from each other by &.

Therefore you will need to transform your JSON object. I would simply iterate over the JSON and output:encodeURIComponent(propertyKey) + "=" + encodeURIComponent(propertyValue) and will combine them using the & sign. e.g.

   var str = [];
    for (var key in obj) {
         if (obj.hasOwnProperty(key)) {
               str.push(encodeURIComponent(key) + "=" + encodeURIComponent(obj[key]))                  
               console.log(key + " -> " + obj[key]);
         }
    }
    return str.join("&");
Community
  • 1
  • 1
Omri L
  • 739
  • 4
  • 12
5

use querystring,

npm install querystring

var querystring = require('querystring')

var inputJson = {
   name: "Asdf",
    age: 23
}

console.log(querystring.stringify(inputJson))

This will convert your json into application/x-www-form-urlencoded

Deepak
  • 1,373
  • 2
  • 10
  • 31
  • really i need this function to do a post to the backend restful, why tutorials don't speak about that; they just send directly, by example ** the service ** return this.http.post(this.actionUrl , JSON.stringify( body), { headers: this.headers }) .map((response: Response) => response.json()) .catch(this.handleError); ** the component that call the service: ** this.accountsService .insert(this.account) .subscribe((data) => { console.log(data); this.account = data }, error => console.log(this.account), () => console.log('Insert complete')); – stackdave Dec 01 '16 at 12:11
3

Assume have an object named postdata as below:

const postdata = {
  'a':1,
  'b':2,
  'c':3
};

and, you want convert it into x-www-form-urlencoded format, like: a=1&b=2&c=3

with URLSearchParams it's very easy to do it.

const rawData = new URLSearchParams(Object.keys(postdata).map(key=>[key,postdata[key]]));
console.log(rawData.toString());//a=1&b=2&c=3
朱小江
  • 99
  • 1
  • 3
2

The non-recursive variant can be expressed as a one-liner with ES6 / TypeScript:

const formEncodedBody = Object.keys(obj).filter(k => obj.hasOwnProperty(k)).map(
        k => encodeURIComponent(k) + '=' + encodeURIComponent(obj[k])).join('&');

Note that this algorithm (as the other solution as well) makes some assumptions:

  • The properties of the objects are all non-null (but that could be filtered)
  • The string representation of each property is exactly what shall be sent (e.g. no special treatment of arrays, booleans as true/false, not as 0/1 or yes/no...)
  • No recursion (no property is an object).
Florian Albrecht
  • 2,266
  • 1
  • 20
  • 25
1

I've found the simplest solution for that in a issue of fetch polyfill repo.

// params -> the JSON object to convert
const searchParams = Object.keys(params).map((key) => {
  return encodeURIComponent(key) + '=' + encodeURIComponent(params[key]);
}).join('&');

It works for me and i hope to you too.

Carlos Rodríguez
  • 745
  • 11
  • 20
-1
private String toFormString(Object t)
{
    boolean needConectFlag = false;
    StringBuilder result = new StringBuilder();
    BeanInfo info;
    try
    {
        info = Introspector.getBeanInfo(t.getClass());
    }
    catch (IntrospectionException e)
    {
        throw new HttpMessageConversionException("failed  to getBeanInfo", e);
    }
    PropertyDescriptor[] descriptors = info.getPropertyDescriptors();

    for (PropertyDescriptor d : descriptors)
    {
        Method getMethod = d.getReadMethod();//Read对应get()方法
        Object retValue = null;
        try
        {
            retValue = getMethod.invoke(t);
        }
        catch (IllegalAccessException e)
        {
            throw new HttpMessageConversionException("failed  to invoke,IllegalAccess", e);
        }
        catch (IllegalArgumentException e)
        {
            throw new HttpMessageConversionException("failed  to invoke,IllegalArgument", e);
        }
        catch (InvocationTargetException e)
        {
            throw new HttpMessageConversionException("failed  to invoke,InvocationTarget", e);
        }
        if (retValue != null && !d.getName().equals("class"))
        {
            if (needConectFlag)
            {
                result.append("&");
            }
            result.append(d.getName()).append("=").append(retValue);

            needConectFlag = true;
        }
    }
    return result.toString();
}