Form

io.eezo.http.Form
See theForm companion object
trait Form[A]

Renders a case class as an HTML form, and reads one back.

Form emits the whole `` element rather than a bag of inputs, because it is the one place that knows both the target verb and the encoding, and so it is the only place that can own the _method override. A Resource hands it Method.PUT without knowing the override exists. The CSRF token is the other reserved input for unsafe forms, and it is a required parameter of render rather than a default or a given: callers cannot accidentally omit it from a form that needs protection, and the caller already holds it as request.csrf.

The key is never rendered. A form that carried its own key would either need a placeholder value meaning "not set", which is a real value the server cannot tell from a real one, or a hidden input, which the browser lets the user edit. Instead parse takes the key as raw text from the caller: Id.gen().show on create, the path parameter on update, decoded through the key field's own Field so there is one decoder rather than two.

Attributes

Companion
object
Source
Form.scala
Graph
Supertypes
class Object
trait Matchable
class Any

Members list

Value members

Abstract methods

def fields: Seq[FormField]

Declaration order, with the key absent.

Declaration order, with the key absent.

Attributes

Source
Form.scala
def parse(data: Map[String, Seq[String]], key: Option[String]): Either[FormErrors, A]

Reads a submission.

Reads a submission.

key is the caller's, and is required exactly when the model has a key field. Extra keys in data are ignored, which is what lets _method and _csrf travel in the same body without either being declared here.

Attributes

Throws
BadRequest

if the key is present but will not decode.

IllegalArgumentException

if the model has a key and the caller supplied none. That is a bug in the caller rather than bad input, so it is not a FormErrors.

Source
Form.scala
def render(action: Url | String, method: Method, value: Option[A], token: Token, errors: FormErrors = ..., raw: Map[String, Seq[String]] = ...): Html

The whole ``, including its submit button, the CSRF token and, when the verb needs one, _method.

The whole ``, including its submit button, the CSRF token and, when the verb needs one, _method.

token is the request's, request.csrf inside a handler and Csrf.Token.gen() in a test that renders outside one. It sits after value and before the defaulted parameters because it has no default: see the class comment.

raw is submitted text, winning field by field over value. A rejected submission has no A to render from, which is why it was rejected, so without raw the user gets an empty form back with error messages beside it and their typing gone.

action is a union rather than two overloads because only one alternative of an overloaded method may carry default arguments, and errors and raw have them. A String is a finished address; a Url.Mounted is one that still travels with Route.under.

Attributes

Source
Form.scala
def show(value: A): Seq[(FormField, String)]

One record's fields paired with their values, as a show page renders them.

One record's fields paired with their values, as a show page renders them.

The values come from the same Field.show the inputs use, so a show page and the edit form for the same record cannot disagree about one field's text. The alternative, reading productElement(i).toString, prints Some(3) for an Option field and disagrees on the spot. The key is absent, exactly as it is from fields.

Attributes

Source
Form.scala
def without(name: String): Form[A]

The same form with one named field gone from everything a page shows, and still read by parse.

The same form with one named field gone from everything a page shows, and still read by parse.

That split is the whole of it. An owned model's owner field is filled by the handler from who is signed in, so it must not be an input the browser can edit, a heading on an index or a row on a show page; but the record still has to be built, and building it is parse's job, from a value the caller puts into data under this same name. Suppressing it from parse too would leave the field with nothing to hold.

By name rather than by index, because the caller holds an io.eezo.core.OwnerOf, whose name is the model's own field label. A name that names no field changes nothing, which is what a Form derived from a Mirror can honestly promise: it has no way to know whether the caller meant a field of another model.

Attributes

Source
Form.scala