How to Construct a URL Search Query with JavaScript

How to Construct a URL Search Query with JavaScript

Today We will be dealing with URL query parameters. I will show you how you can save search parameters based on the values provided by a user and then construct a URL with such parameters.

We won't actually be needing a form for this.

LET'S BEGIN

I will start with a fake URL that allows me to pull up { x } number of records using the parameter (limit), search through { x } number of records using the parameter (filter), and filter through the records by their respective Id's using the parameter (id).

So I have my fake base URL as

api.test.com/users

And the query URL as

api.test.com/users?limit=&filter=&id=

So I'll show you how to construct the query URL, still retaining the values of the other parameters.

Input Elements

We have 3 input elements that will enable us to get values from users based on how they want to filter the data.

<!-- limit -->
<select id="select_limit">
    <option value="">Select One </option>
    <option value="50">50 records</option>
    <option value="100">100 records</option>
</select>
<!-- search input -->
<input type="search" id="inp_filter">
<!-- id -->
<input type="text" id="inp_id">

Now we will create a variable that will store the user's query along with its default values.

This variable will help us to retrieve a new set of filtered data because we will store the value of the other parameters.

let userQuery = {
    "limit" : 50,
    "filter" : "",
    "id" :  1
}

If your page does not send the request through Ajax, you need to store the value of userQuery in the browser's local storage and then retrieve that value on page reload.

//check if it exists and rewrite the variable
let userQuery = (localStorage.getItem('userQuery')) ? 
                    JSON.parse(localStorage.getItem('userQuery')) : 
                           { "limit" : 50,"filter" : "","id" :  1 };

//save user query
localStorage.setItem('userQuery', JSON.stringify(userQuery));

Build Your Query

Now let's create a function that will loop through our object, build our query parameter and return the URL for us to send.

function buildQuery(){
    //store query parameters in a temporary variable
    var query = [];
    //loop through user query object
    for (var key in userQuery) {
        //encode the keys and values this is most necessary for search inputs 
        query.push(encodeURIComponent(key) + '=' + encodeURIComponent(userQuery[key]));
    }
    //construct new URL
    let new_url = "https://api.test.com/users"+ (query.length ? '?' + query.join('&') : '');
    return(new_url);
}

When dealing with a search form, it is necessary to encode the search value using encodeURICompenent and decode on the backend.

Listen for changes

Now we will listen for changes in the input elements, and rebuild the query parameter.

We will also create a variable that will store the value of these input elements to prevent sending duplicate requests.

//handle limit change
let limitNo;
document.querySelector("#select_limit").addEventListener('change', function(){
    //check if value is not empty and has not been used before
    if((this.value !== "") && (limitNo !== this.value)){
        //set the variable to contain this value( this means that is used)
        limitNo = this.value;
        //build userQuery
        userQuery["limit"] = limitNo;
        //do something with the url
        let url = buildQuery();
        //window.location.assign(url);
    }
})

//handle search input
let searchTxt;
document.querySelector("#inp_filter").addEventListener('change', function(){
    //check if search value has not been used before
    if(searchTxt !== this.value){
        //set the variable to contain this value( this means that is used)
        searchTxt = this.value;
        //build userQuery
        userQuery["filter"] =searchTxt;
        //do something with the url
        let url = buildQuery();
        //window.location.assign(url);
    }
})

//handle id input
let inpID;
document.querySelector("#inp_id").addEventListener('change', function(){
    //check if search value has not been used before
    if((this.value !== "") && (inpID !== this.value)){
        //set the variable to contain this value( this means that is used)
        inpID = this.value;
        //build userQuery and format the value to number
        userQuery["id"] = parseInt(inpID);
        //do something with the url
        let url = buildQuery();
        //window.location.assign(url);
    }
})

So anytime any input element changes value, we will rebuild the query parameter and return the URL which we can send to the browser.

Here's the full script

//check if it exists and rewrite the variable
let userQuery = (localStorage.getItem('userQuery')) ? 
                    JSON.parse(localStorage.getItem('userQuery')) : 
                           { "limit" : 50,"filter" : "","id" :  1 };

//save user query
localStorage.setItem('userQuery', JSON.stringify(userQuery));

//build your query
function buildQuery(){
    //store query parameters in a temporary variable
    var query = [];
    //loop through user query object
    for (var key in userQuery) {
        //encode the keys and values this is most necessary for search inputs 
        query.push(encodeURIComponent(key) + '=' + encodeURIComponent(userQuery[key]));
    }
    //construct new URL
    let new_url = "https://api.test.com/users"+ (query.length ? '?' + query.join('&') : '');
    return(new_url);
}

//handle limit change
let limitNo;
document.querySelector("#select_limit").addEventListener('change', function(){
    //check if value is not empty and has not been used before
    if((this.value !== "") && (limitNo !== this.value)){
        //set the variable to contain this value( this means that is used)
        limitNo = this.value;
        //build userQuery
        userQuery["limit"] = limitNo;
        //do something with the url
        let url = buildQuery();
        //window.location.assign(url);
    }
})

//handle search input
let searchTxt;
document.querySelector("#inp_filter").addEventListener('change', function(){
    //check if search value has not been used before
    if(searchTxt !== this.value){
        //set the variable to contain this value( this means that is used)
        searchTxt = this.value;
        //build userQuery
        userQuery["filter"] =searchTxt;
        //do something with the url
        let url = buildQuery();
        //window.location.assign(url);
    }
})

//handle id input
let inpID;
document.querySelector("#inp_id").addEventListener('change', function(){
    //check if search value has not been used before
    if((this.value !== "") && (inpID !== this.value)){
        //set the variable to contain this value( this means that is used)
        inpID = this.value;
        //build userQuery and format the value to number
        userQuery["id"] = parseInt(inpID);
        //do something with the url
        let url = buildQuery();
        //window.location.assign(url);
    }
})

You can modify the code to suit your app's logic.

The reason I decided not to use a form for this is because of a web page structured like this

image.png

You can see the input and select elements responsible for filtering the records are beautifully structured and not under a single form, so using the approach above will help users filter records with ease, retaining the previous query parameters.

USING THE URL() OBJECT CONSTRUCTOR

We can make things very easy for us by using the url() object constructor, to construct the URL.

To begin, I will create a function doQuery that will have just 2 parameters.

  • The first parameter is a URL ( this URL may have a search query already ).

  • The second parameter is an object that contains the user's search query.

Then we will use the set() method to either set new parameters from the userQuery object or rewrite the existing parameters.

function doQuery(url, userQuery){
    //construct a new url 
    let res = new URL(url);
    //check if userquery contians properties
    if(Object.keys(userQuery).length !== 0){
        //loop through object
        let ind = 0;
        while (ind < Object.keys(userQuery).length){
            //get the parameter
            const param = Object.keys(userQuery)[ind];
            //get the value
            const value = userQuery[param];
            //set or replace the parameter   
            res.searchParams.set(param, value);
            //increment counter
            ind++;
        }
    }
    //return the full URL
    return ( res.href );
}

To use this function, just pass in your URL for the search, then the userQuery object as the second parameter.

const userQuery = {
    uname : "Simon",
    pass : "OctaHenryX6D"
}
//store url
let url = doQuery('http://mywebsite.com/check-record', userQuery);
//send to the browser
window.location.href=url;

This is what the return value looks like with a URL without a search query.

image.png

What if we attached a search query to the URL?

image.png

The values of the search parameters will be rewritten with the one from the userQuery object!

You've reached the end of my article.

EXTRA

I recently launched a JavaScript package that validates your HTML forms using validation rules, regular expressions, and form input attributes.

I will appreciate it if you spared a few seconds to check it out.

Thank You