Reputation: 697
I don't understand how to describe @helper
.repeat in play2.2.1.
@helper.form(action = routes.Application.send) {
@helper.repeat(
field = form1("input"), min = 3
) {fld =>
@helper.inputText(
field = fld, '_label ->"input"
)
}
}
It is the part fld => @helper.inputText(field = fld)
that I can't understand.
What does it mean?
I know Java, so I assume it is a functional writing, but in above code, where does the variable fld
come from?
And why the tip of the arrow indicates @helper.inputText(field = fld)
?
why is fld
the value of field in @helper.inputText
?
I have googled, but I couldn't find an enough explanation for a beginner.
I am not sure of Scala's grammar.
Please explain above code for a beginner?
Upvotes: 0
Views: 624
Reputation: 5699
This seems to be a bit overcomplicated. There is no need to assign values by hand. Usually you would write a repeater like this:
@helper.repeat(form1("input"), min = 3) { fld =>
@helper.inputText(fld, '_label ->"input")
}
In functional programming this is a so called higher-order function. You may know other scala built in higher-order functions like map
, filter
or foreach
. @helper.repeat
is very similar to foreach
. form1("input")
refers to a collection of values you want to display. min = 1
tells the repeater to show at least one field. Finally within { fld => ... }
you iterate over all values defined in your collection.
In other words: { fld => ... }
is just an anonymous function that takes a single Field
parameter (fld
) and displays a text input for that specific field.
Ok, I'm trying to follow up your questions from the comments. Let's start by the signature of helper.repeat
. There is no magic involved here, it's just a regular Scala function:
helper.repeat(field: Field, min: Int)(fieldRenderer: (fld: Field) => Html): Seq[Html]
In Scala, functions can have multiple parameter lists. Here we have two. The first parameter list takes two parameters: field
and min
. The second parameter list takes a single function as parameter: fieldRenderer
. fieldRenderer
itself takes again a single parameter (fld
) and returns Html
.
The important thing is, you are not passing "data" but a function instead. To clear this up:
The signature fieldRenderer: (fld: Field) => Html
is equal to def fieldRenderer(fld: Field): Html
This means, you can do anything within this function, as long as it returns Html. That's exactly what happens in the example at the very top. You pass a Field
and return Html
. You do that by calling @helper.inputText
.
Now repeat
first gets a List[Field]
from field
you pass as first parameter. This list corresponds to the String List of your container class. Also repeat
ensures there is at least one element in that list. This is, because you passed 1
as min
. Then the function fieldRenderer
is applied to all elements in our list.
A pseudo code implementation of repeat
could look like this:
def repeat(field: Field, min: Int)(fieldRenderer: (fld: Field) => Html): Seq[Html] {
val list: List[Field] = field.getFields
var output: List[Html] = List()
for (i = 0; i < list.length; i++) {
val element: Field = list.get(i)
val html: Html = fieldRenderer(element)
output += html
}
return output
}
Upvotes: 2