Play framework2(Scala)でAjaxによる非同期通信


Play framework2(Scala)で、Ajaxを使って画面遷移せずにコメントを投稿するプログラムです。
[JavaScriptルーティング](http://www.playframework-ja.org/documentation/2.1.5/ScalaJavascriptRouting)を使って実装します。

以下、実装。


コントローラのApplication.scala

```scala:Application.scala
package controllers

import play.api._
import play.api.mvc._
import models.Comment

object Application extends Controller {

  def index = Action {
    Ok(views.html.index(Comment.all()))
  }

  def postComment(comment: String) = Action { implicit request =>
    Comment.insertDB(comment)
    Ok
  }

  def javascriptRoutes = Action { implicit request =>
    import routes.javascript._
    Ok(
       Routes.javascriptRouter("jsRoutes")(routes.javascript.Application.postComment)
    ).as("text/javascript")
  }
}
```

ビューのmain.scala

```html:main.scala
@(title: String)(content: Html)

<!DOCTYPE html>
<html>
    <head>
        <title>@title</title>
        <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/main.css")">
        <link rel="shortcut icon" type="image/png" href="@routes.Assets.at("images/favicon.png")">
        <script src="@routes.Assets.at("javascripts/jquery-1.9.0.min.js")" type="text/javascript"></script>
        <script type="text/javascript" src="@routes.Application.javascriptRoutes"></script>
    </head>
    <body>
        @content
    </body>
</html>
```

ルータをヘッダに書き、読み込ませます。


ビューのindex.scala

```html:index.scala
@(comments: List[Comment])

@main("Ajax Comment") {

<form class="form-inline" id="comment-form">
  <input type="text" id="input-comment" placeholder="comment" />
  <button type="submit" id="comment-submit">post</button>
</form>

<!-- コメントを表示 -->
<ul id="comments">
  @comments.map { comment =>
    <li>@comment.comment</li>
  }
<ul>

<script>
$('#comment-form').submit(function(event) {
  event.preventDefault();
  var comment = $("#input-comment").val();
  jsRoutes.controllers.Application.postComment(comment).ajax({
    // 送信したらボタンを使用不可にし二重投稿を防ぐ
    beforeSend: function() {
      $("#comment-submit").attr('disabled', true);
    },
    // 完了したらボタン使用不可を解除する
    complete: function() {
      $("#comment-submit").attr('disabled', false);
    },
    // 投稿が成功したら新しいコメントを表示する
    success: function(datetime) {
      $("#input-comment").val("");
      $('#comments').append("<li>" + comment + "</li>")
    },
    error: function() {
      alert("error")
    }
  })
});
</script>

}
```

モデルのComment.scala

```scala:Comment.scala
package models

import anorm._
import anorm.SqlParser._
import play.api.db._
import play.api.Play.current

case class Comment(id: Long, comment: String)

object Comment {

  def all(): List[Comment] = DB.withConnection { implicit c =>
    SQL("select * from comment").as(comment *)
  }

  def insertDB(comment: String) {
    DB.withConnection { implicit c =>
      SQL("""
          insert into comment (comment)
          values ({comment})
          """
      ).on(
        'comment -> comment
      ).executeUpdate()
    }
  }

  val comment = {
    get[Long]("id") ‾
    get[String]("comment") map {
      case id ‾ comment => Comment(id, comment)
    }
  }
}
```

routes

```yaml
# Routes
# This file defines all application routes (Higher priority routes first)
# ‾‾‾‾

# Home page
GET     /                           controllers.Application.index

POST    /comment                    controllers.Application.postComment(comment: String)

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

GET     /javascriptRoutes           controllers.Application.javascriptRoutes
```

それ以外のファイルは[github](https://github.com/shzero5/Ajax-Comment-Form)にあげています。