Play 2.4: Form: could not find implicit value for parameter messages: play.api.i18n.Messages

22k views Asked by At

I am new to Play framework and tried to mimic the helloworld sample in my local machine but I encountered an error:

enter image description here

routes:

# Home page
GET        /                    controllers.Application.index

# Hello action
GET        /hello               controllers.Application.sayHello


# Map static resources from the /public folder to the /assets URL path
GET        /assets/*file        controllers.Assets.versioned(path="/public", file: Asset)

controller:

package controllers

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

import views._

class Application extends Controller {

  val helloForm = Form(
    tuple(
      "name" -> nonEmptyText,
      "repeat" -> number(min = 1, max = 100),
      "color" -> optional(text)
    )
  )

  def index = Action {
    Ok(html.index(helloForm))
  }

  def sayHello = Action { implicit request =>
      helloForm.bindFromRequest.fold(
      formWithErrors => BadRequest(html.index(formWithErrors)),
      {case (name, repeat, color) => Ok(html.hello(name, repeat.toInt, color))}
    )
  }
}

view:

@(helloForm: Form[(String,Int,Option[String])])

@import helper._

@main(title = "The 'helloworld' application") { 
    <h1>Configure your 'Hello world':</h1> 
    @form(action = routes.Application.sayHello, args = 'id -> "helloform") {
        @inputText(
            field = helloForm("name"),
            args = '_label -> "What's your name?", 'placeholder -> "World"
        )

        @inputText(
            field = helloForm("repeat"),
            args = '_label -> "How many times?", 'size -> 3, 'placeholder -> 10
        ) 
        @select(
            field = helloForm("color"),
            options = options(
                "" -> "Default",
                "red" -> "Red",
                "green" -> "Green",
                "blue" -> "Blue"
            ),
            args = '_label -> "Choose a color"
        ) 
        <p class="buttons">
            <input type="submit" id="submit">
        <p> 
    } 
}

I have Play 2.4 installed and created the project using IntelliJ Idea 14 via activator template.

3

There are 3 answers

4
ps_ttf On BEST ANSWER

After adding implicit messages parameters to views you can just add the following imports and use the old controller classes or even objects without any additional changes:

import play.api.Play.current
import play.api.i18n.Messages.Implicits._
11
Roman On

Using view form helpers (such as @inputText) requires you to pass an implicit play.api.i18n.Messages parameter to your view. You can do this adding (implicit messages: Messages) to the signature in your view. Your view becomes this:

@(helloForm: Form[(String,Int,Option[String])])(implicit messages: Messages)

@import helper._

@main(title = "The 'helloworld' application") { 
  <h1>Configure your 'Hello world':</h1> 
  ...

Then in your application controller you must make this parameter implicitly available in your scope. The simplest way to do this is to implement play's I18nSupport trait.

In your example, this would look like this:

package controllers

import play.api.mvc._
import play.api.data._
import play.api.data.Forms._
import javax.inject.Inject
import play.api.i18n.I18nSupport
import play.api.i18n.MessagesApi

import views._

class Application @Inject()(val messagesApi: MessagesApi) extends Controller with I18nSupport {

  val helloForm = Form(
    tuple(
      "name" -> nonEmptyText,
      "repeat" -> number(min = 1, max = 100),
      "color" -> optional(text)
    )
  )

  def index = Action {
    Ok(html.index(helloForm))
  }

  def sayHello = Action { implicit request =>
    helloForm.bindFromRequest.fold(
      formWithErrors => BadRequest(html.index(formWithErrors)),
      {case (name, repeat, color) => Ok(html.hello(name, repeat.toInt, color))}
    )
  }
}

In your controller you can of course use your own implementation of MessagesApi. Since play knows out of the box how to inject a MessagesApi you can simply annotate your controller with @Inject and let play do the work for you.

As Matthias Braun mentioned, you also have to set

routesGenerator := InjectedRoutesGenerator

in your build.sbt

See https://www.playframework.com/documentation/2.4.x/ScalaI18N for more information about I18n.

1
arvind grey On

Using form helpers requires you to pass an implicit play.api.i18n.Messages parameter to your view. You can do this adding (implicit messages: Messages) to in your view. Your view becomes this:

@(contacts: List[models.Contact], 
  form: Form[models.Contact])(implicit messages: Messages)

Then manually inject into your controllers

import play.api.data.Forms._

import javax.inject.Inject

import play.api.i18n.I18nSupport

import play.api.i18n.MessagesApi 

then finally add on to your main index controller class

class Application @Inject()(val messagesApi: MessagesApi) extends
                                           Controller with I18nSupport {