Skip to content

Instantly share code, notes, and snippets.

@EdgeCaseBerg
Created January 12, 2017 14:15
Show Gist options
  • Select an option

  • Save EdgeCaseBerg/cc7651edcc55af4129dd97cd51d1a735 to your computer and use it in GitHub Desktop.

Select an option

Save EdgeCaseBerg/cc7651edcc55af4129dd97cd51d1a735 to your computer and use it in GitHub Desktop.
For a blog post later on (and maybe a PR to Play's documentation)

Looking at the source code, there's something useful tips for handling this:

In the binding there's code like this:

def bindFromRequest(data: Map[String, Seq[String]]): Form[T] = {
bind {
  data.foldLeft(Map.empty[String, String]) {
    case (s, (key, values)) if key.endsWith("[]") => s ++ values.zipWithIndex.map { case (v, i) => (key.dropRight(2) + "[" + i + "]") -> v }
    case (s, (key, values)) => s + (key -> values.headOption.getOrElse(""))
  }
}
}

Which indicates that no integer will mean they automatically get one added in. The seq mapping itself though has code like:

...
def indexes(key: String, data: Map[String, String]): Seq[Int] = {
	val KeyPattern = ("^" + java.util.regex.Pattern.quote(key) + """\[(\d+)\].*$""").r
	data.toSeq.collect { case (KeyPattern(index), _) => index.toInt }.sorted.distinct
}
...
//in the bind method for seq
...
    val allErrorsOrItems: Seq[Either[Seq[FormError], T]] = RepeatedMapping.indexes(key, data).map(i => wrapped.withPrefix(key + "[" + i + "]").bind(data))
...
...

which indicates that if the form mapping's value between the [] is not a number, then it won't be pulled from the list. Testing this in the console shows this to be true:

import play.api.data._
import play.api.data.Forms._

val f = Form(single("s" -> seq(boolean)))

f.bind(Map("s[0]" -> "true", "s[1]" -> "false", "s[x]" -> "true")).get
// Seq[Boolean] = List(true, false) <-- we lose that last one from s[x]

But also it means the number doesn't actually matter:

f.bind(Map("s[1000]" -> "true", "s[2000]" -> "false", "s[320]" -> "true")).get
// Seq[Boolean] = List(true, true, false)

And lastly, to demostrate that a request being bound can just be handled by not putting numbers at all:

f.bindFromRequest(Map("s[]" -> Seq("true", "false","true"))).get
// Seq[Boolean] = List(true, false, true)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment