scala-js/scala-js-dom

can't iterate over URLSearchParams

rhz opened this issue · 6 comments

rhz commented

Given

val urlParams = new URLSearchParams(
  dom.window.location.search)

the following code

for ((k, v) <- urlParams)
  println(k, "->", v)

or

for ((k, v) <- urlParams.entries())
  println(k, "->", v)

should compile?
I get this error for the former

[error] A.scala:458:10: constructor cannot be instantiated to expected type;
[error]  found   : (T1, T2)
[error]  required: org.scalajs.dom.experimental.URLSearchParams
[error]     for ((k, v) <- urlParams)
[error]          ^

and this for the latter

[error] A.scala:458:10: constructor cannot be instantiated to expected type;
[error]  found   : (T1, T2)
[error]  required: scala.scalajs.js.Iterator[scala.scalajs.js.Tuple2[String,String]]
[error]     for ((k, v) <- urlParams.entries())
[error]          ^

However, this compiles

for (k <- urlParams.keys())
  println(k)
raquo commented

Note that URLSearchParams is an Iterable over scala.scalajs.js.Tuple2, and that is not the same type as scala.Tuple2, the former is basically just a two-element js.Array. URLSearchParams uses this js.Tuple2 type because that's what the corresponding Javascript class provides.

Tuple matching like for ((k, v) <- ...) is a Scala language feature that works on Scala's native tuples (that is, scala.Tuple2, not js.Tuple2). I don't know if Scala.js could potentially implement such language support for js.Tuple2. Seems unlikely but you can serach scalajs project issues or ask in scalajs gitter.

The scala-js-dom project itself is a very thin layer over the underlying JS APIs.

rhz commented

I thought there would be an implicit transformation from js.Tuple2 to scala.Tuple2 that would make the two almost interchangeable and, hence, make the for ((k, v) <- ...) work.

What is then the idiomatic way to iterate over instances of URLSearchParams?

raquo commented

There are in fact such implicit conversions defined (see object Tuple2 in the scalajs repo) but they're not enough.

I guess you could just say

x.forEach((k, v) => {
  println(k + " -> " + v)
})

(note the capital E in forEach – that's because it's from Javascript)

sjrd commented
for (js.Tuple2(k, v) <- urlParams.entries())
  ...

Hello,

This looks like a question on using Scala.js, rather than a bug report. The GitHub Issues in this repo are for bug reports and feature requests only. Please ask questions on StackOverflow or on Gitter, where more than just the core developers can see and answer.

Thank you for your understanding.

rhz commented

Thank you both.

Just for the record, the order of the parameters in forEach is opposite to the intuitive one.

x.forEach((v, k) => {
  println(k + " -> " + v)
})
rhz commented

And, also for the record, the following line gives type Any to v (instead of String).

for (js.Tuple2(k, v) <- urlParams.entries())
  ...