76

If I had a URL such as

http://localhost/search.php?year=2008

How would I write a JavaScript function to grab the variable year and see if it contains anything?

I know it can be done with location.search but I can’t figure out how it grabs parameters.

Philip Kirkbride
  • 21,381
  • 38
  • 125
  • 225

14 Answers14

75

You may use window.URL class:

new URL(location.href).searchParams.get('year')
// Returns 2008 for href = "http://localhost/search.php?year=2008".
// Or in two steps:
const params = new URL(location.href).searchParams;
const year = params.get('year');
ilyaigpetrov
  • 3,657
  • 3
  • 30
  • 46
60

My favorite way for getting URL params is this approach:

var parseQueryString = function() {

    var str = window.location.search;
    var objURL = {};

    str.replace(
        new RegExp( "([^?=&]+)(=([^&]*))?", "g" ),
        function( $0, $1, $2, $3 ){
            objURL[ $1 ] = $3;
        }
    );
    return objURL;
};

//Example how to use it: 
var params = parseQueryString();
alert(params["foo"]); 
Alex
  • 12,205
  • 7
  • 42
  • 52
  • 43
    That old man always says "when you have a problem that can only be resolved with regular expressions, you actually have two problems". – rscarvalho Nov 15 '13 at 14:44
  • I love this, very cute! is there a reason you capture the '='? you could say /([^?=&]+)=([^&]*)/g and have your params be (match, key, value)? – dtudury Feb 28 '14 at 00:03
  • isn't location.search.split("year=")[1] much simpler? – Rodrigo Nov 25 '16 at 08:31
  • @Rodrigo if you have more than one params it will blow – KTU Mar 22 '17 at 17:31
  • 1
    A more elegant —no regex / more modern (2018) — solution is here: https://stackoverflow.com/a/42316411/328117 – vinyll Feb 28 '18 at 20:56
49

A non-regex approach, you can simply split by the character '&' and iterate through the key/value pair:

function getParameter(paramName) {
  var searchString = window.location.search.substring(1),
      i, val, params = searchString.split("&");

  for (i=0;i<params.length;i++) {
    val = params[i].split("=");
    if (val[0] == paramName) {
      return val[1];
    }
  }
  return null;
}

2020 EDIT:

Nowadays, in modern browsers you can use the URLSearchParams constructor:

const params = new URLSearchParams('?year=2020&month=02&day=01')

// You can access specific parameters:
console.log(params.get('year'))
console.log(params.get('month'))

// And you can iterate over all parameters
for (const [key, value] of params) {
  console.log(`Key: ${key}, Value: ${value}`);
}
Sandra Rossi
  • 11,934
  • 5
  • 22
  • 48
Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
16

This question is old and things have evolved in JavaScript. You can now do this:

const params = {}
document.location.search.substr(1).split('&').forEach(pair => {
  [key, value] = pair.split('=')
  params[key] = value
})

and you get params.year that contains 2008. You would also get other query params in your params object.


Edit: a shorter/cleaner way to do this:

const params = new Map(location.search.slice(1).split('&').map(kv => kv.split('=')))

You can then test if the year param exists with:

params.has('year')  // true

Or retrieve it with:

params.get('year')  // 2008

Edit 2020

You can convert URL params to an Object:

const params = location.search.slice(1).split('&').reduce((acc, s) => {
  const [k, v] = s.split('=')
  return Object.assign(acc, {[k]: v})
}, {})

Then it can be used as a regular JS Object:

params.year  // 2008
vinyll
  • 11,017
  • 2
  • 48
  • 37
  • 1
    You should use a .reduce() instead of .forEach – Olivier Jan 16 '18 at 14:49
  • 1
    Doesn't work with .reduce(). Only first param is written to params object. Checked in Chrome dev tools. Can you please double check and and replace with forEach() instead? – tylik Jan 28 '19 at 11:06
  • @vinyll @tylik ```const getQueryObject = locationSearchString => locationSearchString .substr(1) .split('&') .reduce((queryObject, keyValuePair) => { const [key, value] = keyValuePair.split('='); queryObject[key] = value; return queryObject; }, {});``` – layonez Feb 20 '19 at 10:03
  • 1
    you should use URL but if you're going to do it this way you need to call `decodeURIComponent` on every key and value after splitting by & and =. This is how it's possible to encode = and & in the keys and values themselves as well as other things like # as they'll all be encoded. – gman Jan 31 '20 at 07:05
8

The following uses regular expressions and searches only on the query string portion of the URL.

Most importantly, this method supports normal and array parameters as in http://localhost/?fiz=zip&foo[]=!!=&bar=7890#hashhashhash

function getQueryParam(param) {
    var result =  window.location.search.match(
        new RegExp("(\\?|&)" + param + "(\\[\\])?=([^&]*)")
    );

    return result ? result[3] : false;
}

console.log(getQueryParam("fiz"));
console.log(getQueryParam("foo"));
console.log(getQueryParam("bar"));
console.log(getQueryParam("zxcv"));

Output:

zip
!!=
7890
false
Justin Johnson
  • 30,978
  • 7
  • 65
  • 89
6
function gup( name ) {
    name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
    var regexS = "[\\?&]"+name+"=([^&#]*)";
    var regex = new RegExp( regexS );
    var results = regex.exec( window.location.href );
    if( results == null )
        return "";
    else
        return results[1];
}
var year = gup("year"); // returns "2008"
Evgeny
  • 10,698
  • 9
  • 60
  • 70
Luca Matteis
  • 29,161
  • 19
  • 114
  • 169
  • 3
    You should use `window.location.search` instead of `window.location.href`. This would simplify your expressions not having to check for the hash or query markers – Justin Johnson Sep 10 '09 at 08:01
  • It would be a good idea to **escape all regex meta characters** in "name" before creating a regex off of it. – kangax Sep 11 '09 at 02:25
6

It took me a while to find the answer to this question. Most people seem to be suggesting regex solutions. I strongly prefer to use code that is tried and tested as opposed to regex that I or someone else thought up on the fly.

I use the parseUri library available here: http://stevenlevithan.com/demo/parseuri/js/

It allows you to do exactly what you are asking for:

var uri = 'http://localhost/search.php?year=2008';
var year = uri.queryKey['year'];
// year = '2008'
Chris Dutrow
  • 48,402
  • 65
  • 188
  • 258
  • 3
    var year = parseUri(window.location.search).queryKey['year']; Is a more relevant example. The one above does not work with version 1.2 of the parseUri script. – Yannick Feb 26 '13 at 08:39
5

The easiest way is to have

if (document.location.search.indexOf('yourtext=') >= 0) {
    // your code
} else {
    // what happens?
}

indexOf()

The indexOf(text) function returns

  • A WHOLE NUMBER BELOW 0 when the text passed in the function is not in whatever variable or string you are looking for - in this case document.location.search.
  • A WHOLE NUMBER EQUAL TO 0 OR HIGHER when the text passed in the function is in whatever variable or string you are looking for - in this case document.location.search.

I hope this was useful, @gumbo

Community
  • 1
  • 1
David Sevilla
  • 97
  • 3
  • 9
4

A Simple One-Line Solution:

let query = Object.assign.apply(null, location.search.slice(1).split('&').map(entry => ({ [entry.split('=')[0]]: entry.split('=')[1] })));

Expanded & Explained:

// define variable
let query;

// fetch source query
query = location.search;

// skip past the '?' delimiter
query = query.slice(1);

// split source query by entry delimiter
query = query.split('&');

// replace each query entry with an object containing the query entry
query = query.map((entry) => {

   // get query entry key
   let key = entry.split('=')[0];

   // get query entry value
   let value = entry.split('=')[1];

   // define query object
   let container = {};

   // add query entry to object
   container[key] = value;

   // return query object
   return container;
});

// merge all query objects
query = Object.assign.apply(null, query);
spacefluff432
  • 566
  • 3
  • 13
1

I used a variant of Alex's - but needed to to convert the param appearing multiple times to an array. There seem to be many options. I didn't want rely on another library for something this simple. I suppose one of the other options posted here may be better - I adapted Alex's because of the straight forwardness.

parseQueryString = function() {
    var str = window.location.search;
    var objURL = {};

    // local isArray - defer to underscore, as we are already using the lib
    var isArray = _.isArray

    str.replace(
        new RegExp( "([^?=&]+)(=([^&]*))?", "g" ),
        function( $0, $1, $2, $3 ){

            if(objURL[ $1 ] && !isArray(objURL[ $1 ])){
                // if there parameter occurs more than once, convert to an array on 2nd
                var first = objURL[ $1 ]
                objURL[ $1 ] = [first, $3]
            } else if(objURL[ $1 ] && isArray(objURL[ $1 ])){
                // if there parameter occurs more than once, add to array after 2nd
                objURL[ $1 ].push($3)
            }
            else
            {
                // this is the first instance
                objURL[ $1 ] = $3;
            }

        }
    );
    return objURL;
};
akaphenom
  • 6,728
  • 10
  • 59
  • 109
  • If a param appears more than once, it should only be treated as an array if it ends with `[]` (e.g. `foo[]=1&foo[]=2`). Otherwise, you should use either the first or last occurrence. – Justin Johnson Mar 24 '16 at 23:50
1

I played a bit with this problem and at this end I used this:

function getJsonFromUrl() {
  return Object.assign(...location.search.substr(1).split("&").map(sliceProperty));
}
  • Object.assign to transform a list of object into one object
  • Spread operator ... to transform an array into a list
  • location.search.substr(1).split("&") to get all parameters as array of properties (foo=bar)
  • map walk each properties and split them into an array (either call splitProperty or sliceProperty).

splitProperty:

  function splitProperty(pair) {
    [key, value] = pair.split("=")
    return { [key]: decodeURIComponent(value) }
  }
  • Split by =
  • Deconstruct the array into an array of two elements
  • Return a new object with the dynamic property syntax

sliceProperty:

  function sliceProperty(pair) {
    const position = pair.indexOf("="),
      key = pair.slice(0, position),
      value = pair.slice(position + 1, pair.length);
    return { [key]: decodeURIComponent(value) }
  }
  • Set the position of =, key and value
  • Return a new object with the dynamic property syntax

I think splitProperty is prettier but sliceProperty is faster. Run JsPerf for more information.

aloisdg
  • 22,270
  • 6
  • 85
  • 105
1

Grab the params from location.search with one line:

const params = new Map(this.props.location.search.slice(1).split('&').map(param => param.split('=')))

Then, simply:

if(params.get("year")){
  //year exists. do something...
} else {
  //year doesn't exist. do something else...
}
Nicole Hemenway
  • 563
  • 5
  • 13
0

ES6 answer:

const parseQueryString = (path = window.location.search) =>
  path.slice(1).split('&').reduce((car, cur) => {
   const [key, value] = cur.split('=')
   return { ...car, [key]: value } 
  }, {})

for example:

parseQueryString('?foo=bar&foobar=baz')
// => {foo: "bar", foobar: "baz"}
Kazuya Gosho
  • 996
  • 13
  • 14
0

This is what I like to do:

window.location.search
    .substr(1)
    .split('&')
    .reduce(
        function(accumulator, currentValue) {
            var pair = currentValue
                .split('=')
                .map(function(value) {
                    return decodeURIComponent(value);
                });

            accumulator[pair[0]] = pair[1];

            return accumulator;
        },
        {}
    );

Of course you can make it more compact using modern syntax or writing everything into one line...

I leave that up to you.

Martin
  • 691
  • 1
  • 9
  • 18