How to Construct a URL Search Query with JavaScript
Published: 2022-06-03 02:06:51

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

> https://api.test.com/users

 And the query URL as

> https://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.

```html
<!-- 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.

```javascript
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. 

```javascript
//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.

```javascript
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.

```javascript
//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

```javascript
//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](https://cdn.hashnode.com/res/hashnode/image/upload/v1649503049158/4srUWLQ7z.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 can 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.

```javascript
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 as the first argument, then the userQuery object as the second argument.

```javascript
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](https://cdn.hashnode.com/res/hashnode/image/upload/v1654221081697/6oVDDY1jA.png)

What if we attached a search query to the URL?

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1654221384644/bF-Cr9Yf0.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.

{% embed https://www.producthunt.com/posts/octavalidate %}

Thank You