Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

An attempt to port Formlets to Scala

branch: master

Fetching latest commit…

Octocat-spinner-32-eaf2f5

Cannot retrieve the latest commit at this time

Octocat-spinner-32 src
Octocat-spinner-32 .gitignore
Octocat-spinner-32 LICENSE
Octocat-spinner-32 LICENSE.tupil
Octocat-spinner-32 README.md
Octocat-spinner-32 build.sbt
README.md

Formaggio

Formlets for Scala

From the Haskell Wiki: "Formlets are a way of building HTML forms that are type-safe, handle errors, abstract and are easy to combine into bigger forms." The key feature of formlets is that they are composable: formlets can be combined to produce larger forms using applicative functors.

I started writing this because I thought the idea Formlets was very clever, and I was impressed by the Haskell implementations: Formlets and Digestive-Functors.
I also thought it would be a good way to get to grips with Scalaz which is pretty much essential when trying to port ideas from Haskell to Scala. I generally tried to follow the Haskell implementations, especially digestive-functors, but it was necessary to diverge a little in order to reuse scalaz' Validators.

There are implementations of the formlets concept in several languages including:

This is not meant to be a web framework. It is concerned solely with form handling.

Using in your project

See (https://github.com/wrwills/formaggio-examples) for an example of using Formaggio in a project.

"formaggio repo" at "http://wrwills.github.com/formaggio/repository/"
"com.github.wrwills" %% "formaggio" % "0.2.2"

How it Works

The best way to get understanding of how Formaggio works is to have a play on the command line:

 sbt 'project core' console  
 scala> import formaggio.SampleData.{personForm, sampleEnv}
 import formaggio.SampleData.{personForm, sampleEnv}
 scala> sampleEnv
 res0: scala.collection.immutable.Map[java.lang.String,java.lang.String] = Map(age::3 -> 30, name::2 -> Bob, password::7 -> password, name::1 -> Jim, nickname::5 -> Jimbo, password::6 -> password)
 scala> runFormState(personForm, sampleEnv)
 res1: (formaggio.Formlets.ValidForm[formaggio.SampleData.Person], scala.xml.NodeSeq) = (Failure(NonEmptyList((terms::8,GenericError(<function1>)))),NodeSeq(<h1>Errors...

The last result is a form failure because the terms and conditions field is not present in the environmont: ie it hasn't been filled in. To fill it in we can just add to the sampleEnv map:

 scala> runFormState(personForm, sampleEnv + ("terms::8" -> "true"))
 res2: (formaggio.Formlets.ValidForm[formaggio.SampleData.Person], scala.xml.NodeSeq) = (Success(Person(FullName(Jim,Bob),30,false,Some(Jimbo),password,Favourites(GreenEggs,List()))),NodeSeq(, <label for="name:...

This form now succeeds. As you can see when a form succeeds you get a Success object which contains the datatype that the form produces as well as the filled in form html. If it fails you get a Failure object which contains a list of entries that have failed as well as the form html along with an html representation of the errrors that have been produced.

To see how to actually go about making forms have a look at core/src/main/scala/scormlets/SampleData.scala to see how personForm is constructed.

TODO:

  • handle file uploads
  • handle radio, multiple checkboxes, drop down selects
  • recaptchas?
  • create examples using lift framework
  • support for different backends eg scalate, commandline
  • i18n support for error messages, field names, etc

THANKS:

  • To Runar Bjarnason for the name.
Something went wrong with that request. Please try again.