Glob Dug
Glob Dug

Reputation: 71

JavaScript - Array of data to URL string encoding only keys and values

I am trying to encode URI parameters for an ajax call in Wordpress without using JQuery. I think I achieved this, but I really don't know if it is a usefull function or it is just useless because already exists in a native JS function that I don't know.

Are there better solutions?

I also don't like the if (!recur) res = res.slice(0, -1); at the end, but I didn't found better solutions to delete the very last "&".

Here is what I wrote (also made a Pen https://codepen.io/globdug/pen/mdarxRo )

const action = "action_name";
const nonce = "nonce_value";
const data = [
    [1, 2, "abc", 3, false, "ciao"],
    "ciao",
    123,
    5213515,
    {
        name: "Tanto va la gatta al lardo",
        slug: "tanto-va-la-gatta-al-lardo"
    },
    {
        key: "ciao",
        test: ["a", "b", "ciao"]
    },
    {
        name: "Tre tigri contro tre tigri",
        slug: "tre-tigri-contro-tre-tigri"
    }
];

function arrayToEncodedString(
    obj, // Array of data to be processed
    varName = "data", // Name of variable that will be processed by the PHP function. It will receive an array
    encode = true, // Just for testing, if true keys and values will be encoded with encodeURIComponent
    prevKey = "", // Blank only during the first call
    recur = false // A flag to check if it is the last "&" at the end of the string.
) {
    let res = "";

    for (const key in obj) {
        const value = obj[key];

        let currentKey =
            prevKey === "" ? varName + "[" + key + "]" : prevKey + "[" + key + "]";

        /**
         * If current value is an object,
         * I will call the function again to iterate it.
         */
        if (typeof value === "object") {
            /*
             * This time I call the function with recur = true
             * to avoid deletion of the last "&"
             */
            res += arrayToEncodedString(value, varName, encode, currentKey, true);
        } else {
            /**
             * I add this check just for debugging and readability
             */
            if (encode) {
                res += `${encodeURIComponent(currentKey)}=${encodeURIComponent(value)}&`;
            } else {
                res += `${currentKey}=${value}&`;
            }
        }
    }

    /**
     * Remove last "&". Only if "recur" is true
     * to avoid deletion of the last "&" of data processed recursively
     */
    if (!recur) res = res.slice(0, -1);

    return res;
}

function prepareForAjax(data, action, nonce, encode = true, varName) {
    return `action=${action}&nonce=${nonce}&${arrayToEncodedString(
        data,
        varName,
        encode,
        undefined,
        undefined
    )}`;
}

/**
 * Thanks ChatGPT
 */
function highlightURLParameters(paramString) {
    // Regex per individuare chiavi e valori
    const regex = /([^&=]+)=([^&]+)/g;

    // Sostituisci la stringa con HTML formattato
    const formattedString = paramString.replace(
        regex,
        function (match, key, value) {
            return (
                '<span class="key">' +
                key +
                '</span>=<span class="value">' +
                value +
                "</span>"
            );
        }
    );

    return formattedString;
}

document.getElementById("resRaw").innerHTML = highlightURLParameters(
    prepareForAjax(data, action, nonce, false)
);

document.getElementById("res").innerHTML = highlightURLParameters(
    prepareForAjax(data, action, nonce)
);
.wrapper {
  font-family: monospace;
}

pre {
  background-color: #232323;
  border: 2px solid #000;
  padding: 10px;
  color: white;
  white-space: pre-wrap;
}

.key,
.value {
  font-weight: bold;
  margin: 0 5px;
}

.key {
  color: cyan;
}

.value {
  color: orange;
}
<div class="wrapper">
  <b>Data to send:</b><br>
  <pre id="resRaw"></pre>
  <b>String encoded:</b><br>
  <pre id="res"></pre>
</div>

Upvotes: 0

Views: 126

Answers (1)

mplungjan
mplungjan

Reputation: 178383

Yes there is a built-in function URL.searchParams.

No need to encode.

const url = new URL("https://example.com/page.php");
const parms = {"action":"action_name","nonce":"nonce_value"};
Object.entries(parms).forEach(([key, value]) => url.searchParams.set(key,value))
console.log(url.toString())

In your case with the nested array, I would use JSON.stringify and pass the complete object instead of data[0][1] etc

Send JSON data from Javascript to PHP?

In your case:

Client:

const action = "action_name";
const nonce = "nonce_value";
const data = [
  // ... Your data
];

const payload = {
  action,
  nonce,
  data // No need to stringify data here; it will be part of the entire JSON payload
};

fetch('your-php-file.php', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(payload) // Stringify the entire payload
})
.then(response => response.json())
.then(data => {
  console.log('Success:', data);
})
.catch((error) => {
  console.error('Error:', error);
});

Server:

// Get the payload from frontend
$rawData = file_get_contents("php://input");

// Decode the JSON payload
$decodedData = json_decode($rawData, true);

$action = $decodedData['action'];
$nonce = $decodedData['nonce'];
$data = $decodedData['data']; // Data is already an array or object, as it was part of the JSON payload

// Here you have $action, $nonce, and $data to be used in the program

PS: To not remove the last thing in something, create an array and join on the thing. For example (but don't, use the above suggestions)

const keyValues = []; 
keyValues.push("action=action_name"); // loop here of course
keyValues.push("nonce=nonce_value"); 
const url = `${serverUrl}?${keyValues.join("&")}`

Upvotes: 0

Related Questions