04 The comments page

簡介

BLOG首頁已設定完成,緊接著繼續編輯文章細節的頁面。此頁面將呈現文章內所有的評論,並運用form來新增評論。


Creating the ‘show’ action

若要顯示文章詳細頁面,我們需要在Application controller新增一個show()方法:

public static void show(Long id) { Post post = Post.findById(id); render(post); }

你會看到這個action非常簡單。我們宣告方法內的參數為id,則就會自動檢索HTTP id參數為Long Java物件。這個參數將被提取出來無論是從查詢句或是URL路徑或是Request本體。

如果我們嚐試送出一個id HTTP參數是不是有效的,該id變數若是null,Play會自動
增加驗證錯誤(validation error)到錯誤容器(rrors container)中。

這個action將顯示在 /yabe/app/views/Application/show.html模板中:

#{extends 'main.html' /} #{set title:post.title /} #{display post:post, as:'full' /}

先前,我們已準備好display tag,所以,該網頁可以很簡單的編輯


Adding links to the details page

之前display tag中將超連結失效(#符號)。但是現在要將超連結指向Application.show() action。隨著Play你可以很簡單的去超連結模版並運用@{....}符號。這個語法使用路徑並反轉調用URL指定action。讓我們來編輯 /yabe/app/views/tags/display.html tag:

... <h2 class="post-title"> <a href="@{Application.show(_post.id)}">${_post.title}</a> </h2> ...

接著重新整理網頁並點選文章標題列超連結,就可以顯示其結果。



但它缺少了回到首頁的超連結。編輯/yabe/app/views/main.html模版來完成標題超連結:

... <div id="title"> <span class="about">About this blog</span> <h1><a href="@{Application.index()}">${blogTitle}</a></h1> <h2>${blogBaseline}</h2> </div> ...

現在,我們可以在首頁和文章細節頁面之間反覆瀏覽了


Specifying a better URL

文章細節頁面的URL網址正如你所看見的 -->  /application/show?id=1

這是Play採用預設的路徑 --> * /{controller}/{action} {controller}.{action}

我們可以使用更好的方式來為Application.show action自定義URL網址路徑。編輯 /yabe/conf/routes檔案並在第一行上面新增自定義路徑。

GET /posts/{id} Application.show


這種方式將id參數提取出來調用URL路徑。你可以閱讀更多關於URL模式文件。重新

整理瀏覽器後,並檢查網址URL路徑是否正確。


Adding pagination

為了能夠讓使用者瀏覽文件更方便,我們將新增分頁功能在此將繼續擴充Post class並增加previous 及 next方法:

public Post previous() { return Post.find("postedAt < ? order by postedAt desc", postedAt).first(); } public Post next() { return Post.find("postedAt > ? order by postedAt asc", postedAt).first(); }

我們將調用這些方法在多次請求時能夠被優化,但它們現在仍不夠完善。此外,增加分頁連結在show.html模版頂層(#{display /} tag之前加入原始碼):

<ul id="pagination"> #{if post.previous()} <li id="previous"> <a href="@{Application.show(post.previous().id)}"> ${post.previous().title} </a> </li> #{/if} #{if post.next()} <li id="next"> <a href="@{Application.show(post.next().id)}"> ${post.next().title} </a> </li> #{/if} </ul>

#{display post:post, as:'full' /}


這樣就可以運行成功了!!!

Adding the comment form

現在我們須要設定各文章的評論表單。我們需要增加postComment action方式至Application controller之中。

public static void postComment(Long postId, String author, String content) { Post post = Post.findById(postId); post.addComment(author, content); show(postId); }


正如你所看見我們調用addComment()方法,我們之前新增在Post class之中。接著,來我們來編輯show.html模版的 form表單(加入原始碼在#{display /}之後)

#{display post:post, as:'full' /}

<h3>Post a comment</h3>
 
#{form @Application.postComment(post.id)}
    <p>
        <label for="author">Your name: </label>
        <input type="text" name="author" id="author" />
    </p>
    <p>
        <label for="content">Your message: </label>
        <textarea name="content" id="content"></textarea>
    </p>
    <p>
        <input type="submit" value="Submit your comment" />
    </p>
#{/form}


現在來試著新增評論,應該是可行。




Adding validation

目前,我們沒有驗證表單機制的功能。我們必須使用這項機制,以確保正確的HTTP參數填寫修改postComment action並新增@Required驗證並檢查沒有錯誤發生:

public static void postComment(Long postId, @Required String author, @Required String content) { Post post = Post.findById(postId); if (validation.hasErrors()) { render("Application/show.html", post); } post.addComment(author, content); show(postId); }

別忘了要import play.data.validation.* !!!

正如你所見的,在案件的驗證錯誤,我們必須重新顯示在該文章詳細信息頁面。 我們要修改原始碼的形式顯示錯誤信息:

<h3>Post a comment</h3> #{form @Application.postComment(post.id)} #{ifErrors} <p class="error"> All fields are required! </p> #{/ifErrors} <p> <label for="author">Your name: </label> <input type="text" name="author" id="author" value="${params.author}" /> </p> <p> <label for="content">Your message: </label> <textarea name="content" id="content">${params.content}</textarea> </p> <p> <input type="submit" value="Submit your comment" /> </p> #{/form}

注意,我們已經發佈的參數,並再利用以填補至HTML input中。

為了讓使用者UI介面更好,我們將新增一些JavaScript並自動設置,以防發生錯誤。由於該Script使用jQueryjQuery Tools工具,你必須去額外下載並加入 yabe/public/javascripts/ 資料夾,以及修改main.html模版加入它們:

... <script src="@{'/public/javascripts/jquery-1.3.2.min.js'}"></script> <script src="@{'/public/javascripts/jquery.tools.min.js'}"></script> </head>

現在你可以增加一些Script到show.html模版中(最好寫在底層):

<script type="text/javascript" charset="utf-8"> $(function() { // Expose the form $('form').click(function() { $('form').expose({api: true}).load(); }); // If there is an error, focus to form if($('form .error').size()) { $('form').expose({api: true, loadSpeed: 0}).load(); $('form input').get(0).focus(); } }); </script>



這樣評論表單看起來很不錯。我們再繼續增加兩個效果。


首先,我們將顯示成功訊息在成功發表評論之後。為此,我們使用flash scope允許我們使用通過驗證訊息從一個action調用到下一個。此刻,修改postComment action來增加一個成功訊息:


public static void postComment(Long postId, @Required String author, @Required String content) { Post post = Post.findById(postId); if(validation.hasErrors()) { render("Application/show.html", post); } post.addComment(author, content); flash.success("Thanks for posting %s", author); show(postId); }

顯示成功訊息在show.html頂層:

... #{if flash.success} <p class="success">${flash.success}</p> #{/if} #{display post:post, as:'full' /} ...




最後,我們將調整postComment action所送出的評論表單設定URL路徑。一如往常,它目前是使用預設的URL路徑,因為目前還沒有自定義任何具體的路徑。所以,就直接新增URL路徑:

POST /posts/{postId}/comments Application.postComment



Comments