0

My question is about full power solution for parsing ANY complex URI parameters using just normal browser's Javascript. Like it do PHP, for simple code compatibility between JS and PHP sources.

But the first, let us see some particular known decisions:


1. There is popular question and answers on StackOverflow, see How can I get query string values in JavaScript?

You can find there quite simple solutions for common SIMPLE cases. For example, like handling this scalar parameters like this one:

https://example.com/?name=Jonathan&age=18

It has no answers for handling complex query params. (As far as I could see for answers with source codes and author comments)


2. Also you may use an URL object in modern browsers, see https://developer.mozilla.org/en-US/docs/Web/API/URL, or exactly https://developer.mozilla.org/en-US/docs/Web/API/URL/searchParams

It is enought powerful and you don't need to write or load any code for parsing URI parameters - just use

var params = (new URL(document.location)).searchParams;
var name = params.get("name"); // is the string "Jonathan"
var age = parseInt(params.get("age")); // is the number 18

This approach has such disadvantage that URL is available only in most of modern browsers, - other browsers or outdated versions of browsers will fail.


So, what I need. I need parsing any complex URI params, like

https://example.com/?a=edit&u[name]=Jonathan&u[age]=18&area[]=1&area[]=20&u[own][]=car&u[own][]=bike&u[funname]=O%27Neel%20mc%20Fly&empty=&nulparam&the%20message=Hello%20World

to

{
    'a': 'edit',
    'u': {
        'name': 'Jonathan',
        'age': '18',
        'own': ['car', 'bike'],
        'funname': 'O\'Neel mc Fly'
    },
    'area': [1, 20],
    'empty': '',
    'nulparam': null,
    'the message': 'Hello World'
}

Preferrable answer is just plain readable javascript source. Simple and small wide-used library can be accepted too, but this question is not about them.

`

PS: To start I just publish my own current solution for parsing URI params and vice versa for making URI from params. Any comments for it are welcome.

Hope this helps to save time for lot of coders later.

FlameStorm
  • 944
  • 15
  • 20
  • I realize you put a lot of effort into this Q&A and the solution, but I don't find it to be a good question for SO purpose. An on-topic question doesn't ask people to write code, but to help with already written code – Adelin Jul 18 '18 at 11:23
  • Is that a valid query string? `u[age]=18&area[]=1`? How would you achieve such a query string? – Adelin Jul 18 '18 at 11:26
  • @Adelin, yes, it is available valid query string parameters style. To achieve this you can type it manually in browser (half a joke, yes) or just use `` – FlameStorm Jul 18 '18 at 11:37
  • @Adelin, so, see also that PHP a lot, lot, lot of years handle such params just from box - you request `HTTP GET ....&u[age]=18&...` and PHP just gives to your php-script `echo $_GET['u']['age']; // prints 18` So it is very usable way. – FlameStorm Jul 18 '18 at 11:45
  • Interesting. Didn't know of that. Although checking looks like [`$.param`](http://api.jquery.com/jquery.param/) handles this starting with version `1.4` – Adelin Jul 18 '18 at 11:48

2 Answers2

0

My solution

Usage:

var params = getQueryParams(location.search);
var params = getQueryParams();

var params = {...};
var path = '...';
var url = path;
var urlSearch = getQueryString(params);
if (urlSearch) {
    url += '?' + urlSearch;
}
history.replaceState({"autoUrl": url}, "autoreplace", url);

Code:

function getQueryParams(qs) {
  if (typeof qs === 'undefined') {
    qs = location.search;
  }

  qs = qs.replace(/\+/g, ' ');

  var params = {},
      tokens,
      re = /[?&]?([^=]+)=([^&]*)/g;

  while (tokens = re.exec(qs)) {
    var name = decodeURIComponent(tokens[1]);
    var value = decodeURIComponent(tokens[2]);
    if (value.length == 0) {
      continue;
    }

    if (name.substr(-2) == '[]') {
      name = name.substr(0, name.length - 2);
      if (typeof params[name] === 'undefined') {
        params[name] = [];
      }
      if (value === '') {
        continue;
      }
      params[name].push(value);
      continue;
    }

    if (name.substr(-1) == ']') {
      var nameParts = name.split('[');
      name = nameParts[0];
      for (var i = 1; i < nameParts.length; i++) {
        nameParts[i] = nameParts[i].substr(0, nameParts[i].length - 1);
      }
      var ptr = params;
      for (var i = 0; i < nameParts.length - 1; i++) {
        name = nameParts[i];
        if (typeof ptr[name] === 'undefined') {
          ptr[name] = {};
        }
        ptr = ptr[name];
      }
      name = nameParts[nameParts.length - 1];
      ptr[name] = value;
      continue;
    }

    params[name] = value;
  }

  return params;
}

function getQueryString(params) {
  var paramsStringParts = [];

  for (var name in params) {
    if (params[name] instanceof Array) {
      paramsStringParts.push( name + '[]=' + params[name].join('&' + name + '[]=') );
    } else if (typeof params[name] === 'object') {

      var makeFlattern = function(obj){
        var result = [];

        if (obj instanceof Array) {
          for (var i = 0; i < obj.length; i++) {
            result.push('[]=' + obj[i]);
          }
          return result;
        }

        for (var i in obj) {
          if (typeof obj[i] === 'object') {
            var subResult = makeFlattern(obj[i]);
            for (var j = 0; j < subResult.length; j++) {
              result.push('[' + i + ']' + subResult[j]);
            }
            continue;
          }
          result.push('[' + i + ']=' + obj[i]);
        }
        return result;
      };

      paramsStringParts.push( name + makeFlattern(params[name]).join('&' + name) );
    } else {
      paramsStringParts.push( name + '=' + params[name] );
    }
  }

  return paramsStringParts.join('&');
}
FlameStorm
  • 944
  • 15
  • 20
0

A bit late, but just struggled over the same problem, solution was very simple:

use encodeURIComponent(...) for the stringified complex objects, the result can then be used as normal queryString-Part.

In the result-side the query-string-parameters have to be un-stringified.

Example:

var complex_param_obj = {
value1: 'Wert1',
value2:4711
};
console.log(restored_param_obj);

var complex_param_str = encodeURIComponent(JSON.stringify(complex_param_obj));
console.log(complex_param_str);
var complex_param_url = 'http://test_page.html?complex_param=' + complex_param_str;

//on the result-side you would use something to extract the complex_param-attribute from the URL
//in this test-case:

var restored_param_obj = decodeURIComponent(complex_param_str);
console.log(restored_param_obj);
ludwig
  • 488
  • 4
  • 8
  • This way can be useful too in some cases, but normally you can just use `form`s with `input name="arr[]" ...` [or `input name="child[name]" ... input name="child[age]" ...`] and get ready to use [assoc] arrays at backends like PHP&other. – FlameStorm Oct 03 '19 at 22:10