3

I tried those two options, without any luck:

let url = new URL(window.location.href);
let key = undefined;

for (let k of url.searchParams) {
    if(url.searchParams[k] == postID) {
        key = k;
    }
}

and

let url = new URL(window.location.href);
const filteredItems = Object.keys(url.searchParams).filter(key =>
  url.searchParams[key] == postID
);
let key = filteredItems.keys.first;

What is wrong?

Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75
János
  • 32,867
  • 38
  • 193
  • 353
  • 3
    In your first piece of code, `k` is an array like `[key, value]` (just console.log stuff) –  Sep 15 '21 at 22:46
  • 1
    Can you share a sample input and the result you're trying to get for it? – Mureinik Sep 15 '21 at 22:48
  • `const params = Array.from(url.searchParams.entries());` creates a two-dimensional array. –  Sep 15 '21 at 22:53
  • `for (let [key,value] of url.searchParams) console.log(key,value)` – Mister Jojo Sep 15 '21 at 22:59
  • `const key = Object.fromEntries(Array.from(new URL(window.location.href).searchParams).reverse().map(([a,b]) => [b, a]))[postId]` – dave Sep 15 '21 at 23:02

1 Answers1

8

Two issues:

  1. While URLSearchParams have iterator semantics (i.e. a Symbol.iterator property), accessing the keys is not performed via normal property access, but via the get method: url.searchParams.get("someKey") === postID.
  2. The iterator protocol of URLSearchParams returns elements as [ key, value ] arrays, not just the keys themselves, so in your forof loop, url.searchParams[k] == postID is like url.searchParams[[ "someKey", "somePostId" ]] == postID, which will be coerced to url.searchParams["someKey,somePostId"] == postID.

A working approach for finding a key (or the keys) for which the value matches postID would look like this:

const searchParams = new URL(window.location.href).searchParams;
// const searchParams = new URLSearchParams(location.search); // Alternative.

const keyCandidates = Array.from(searchParams)
    .filter(([ key, value ]) => value === postID)
    .map(([ key ]) => key);
const keyCandidate = Array.from(searchParams)
    .find(([ key, value ]) => value === postID)[0];
const lastKeyCandidate = Array.from(searchParams)
    .reverse()
    .find(([ key, value ]) => value === postID)[0];

console.log("List of candidate keys: ", keyCandidates);
console.log("Single candidate key: ", keyCandidate);

If you’re in an environment where Iterator Helpers are supported, this can be rewritten as:

const keyCandidates = searchParams.entries()
    .filter(([ key, value ]) => value === postID)
    .map(([ key ]) => key)
    .toArray();
const keyCandidate = searchParams.entries()
    .find(([ key, value ]) => value === postID)[0];

The lastKeyCandidate may have an easy equivalent in the future with the Double-Ended Iterator proposal.

const lastKeyCandidate = searchParams.entries()
    .filter(([ key, value ]) => value === "1")
    .map(([ key ]) => key)
    .next("back") // Get last entry in iterator.
    .value;

More iteration examples:

const url = "https://example.com/?some=value&search=1&param=&etc";

// Equivalent to `new URL(url).search`.
const urlSearch = "?some=value&search=1&param=&etc";

// Equivalent to `new URLSearchParams(urlSearch)`.
const searchParams = new URL(url).searchParams;

// Equivalent to `Array.from(searchParams.entries())`
console.log(Array.from(searchParams));
// Result: [ [ "some", "value" ], [ "search", "1" ], [ "param", "" ], [ "etc", "" ] ]

// Equivalent to `new Map(searchParams.entries())`
console.log(new Map(searchParams));
// Result: Map { "some" → "value", "search" → "1", "param" → "", "etc" → "" }

console.log(Array.from(searchParams.keys()));
// Result: [ "some", "search", "param", "etc" ]

console.log(Array.from(searchParams.values()));
// Result: [ "value", "1", "", "" ]

for(const [ key, value ] of searchParams){
  console.log(key, value); // "some", "value"; then "search", "1"; then "param", ""; then "etc", "".
}
Sebastian Simon
  • 18,263
  • 7
  • 55
  • 75