2011-07-21 60 views
3

我正在構建一些粗略的CMS類功能(以獲得Play Framework的認可)。對於這個測試用例,我構建了2個頁面,1個用於列出標籤,1個用於創建/編輯/保存標籤。玩框架:如何使用datamodel在驗證失敗時重新填充表單?

的流動是這樣的(路由文件):

#list tags 
GET /tags Application.listTags 

#view/edit existing tag 
GET /tag/{<(?!new$)(.+)>name} Application.showTag 

#new tag 
GET /tag/new Application.showTag 

創建/查看/編輯頁面顯示形式得到它的從tagDTO值。 正常流程沒有問題,但當表單提供驗證錯誤(例如:標記名稱必須存在)時,我想再次顯示該頁面,用編輯後的值重新填充表單。我可以使用包含這些最後值的'flash'對象,但是表單已經綁定到tagDTO(在重定向時爲空),而不是'flash' -目的。

首先代碼: Application.java

..... 

public static void showTag(String name) { 
    TagDTO tagDTO = TagDTO.buildDTOFromModelOrNew(name); 
    render(tagDTO); 
} 


/** 
* Save tag and redirect to Show 
* 
* @param name 
* @param displayname 
* @param isnew 
*/ 
public static void saveTag(
     @Required(message="Name is required") String name, 
     String displayname, 
     boolean isnew) 
{ 
    checkAuthenticity(); 
    if(validation.hasErrors()) { 
     params.flash(); 
     validation.keep(); 
     showTag(null); 
    } 

    //fetch tagDTO based on backend or create new if not exist 
    TagDTO tag = TagDTO.buildDTOFromModelOrNew(name); 

    // Append/Overwrite values 
    tag.displayname = displayname; 
    tag.name = name; 

    //save result to model 
    TagDTO.buildAndSaveModelFromDTO(tag); 

    flash.success("Thanks for " + (isnew?"creating":"updating") + " tag " + tag.name); 

    //redirect to show 
    showTag(tag.name); 
} 

而且ShowTag.html

#{extends 'main.html' /} 
    #{if flash.success} 
     <p class="success">${flash.success}</p> 
    #{/if} 

    #{ifErrors} 
     <p class="errors">Oops...</p> 
    #{/ifErrors} 

    #{form @Application.saveTag()} 
     #{authenticityToken /} 
     <p> 
      <label for="name">Name: </label> 
      <input type="text" name="name" id="name" value="${tagDTO.name}" /> 
      <span class="error">#{error 'name' /}</span> 
     </p> 
     <p> 
      <label for="displayname">Displayname: </label> 
      <input type="text" name="displayname" id="displayname" value="${tagDTO.displayname}" /> 
      <span class="error">#{error 'displayname' /}</span> 
     </p> 
     <p> 
      <input type="hidden" name="isnew" value="${tagDTO.isnew}" /> 
      <input type="submit" value="Submit your comment" /> 
     </p> 
    #{/form} 

現在我能想到的一些方法,使其工作,但沒有真正的優雅:

  1. 將表單綁定到flash對象(或params對象)並填充flas/params - 對象來自標記DTO

  2. 在驗證失敗時,重新獲取tagDTO(不再有效,因此DB調用是必需的),並使用Flash對象中可用的值覆蓋tagDTO中的值,將表單綁定到tagDTO。

  3. 2一樣,但使用某種緩存快速獲取tagDTO(所以不需要DB-調用)

  4. 一些通用的機制從/列席會議,(反)序列tagDTO。

總之,我不喜歡他們中的任何一個。 在這種情況下,您認爲什麼是最佳實踐?或者,我缺少Play框架中的任何功能?

回答

2

這是顯式渲染調用派上用場的地方。保留先前提交的表單值,並給它回(如果驗證失敗)如下,

checkAuthenticity(); 
if(validation.hasErrors()) { 
    render("@showTag", name, displayname, isnew); 
} 

這將避免額外的重定向(在播放的情況下,307!),這將發生,如果你有所謂的「行動從另一個行動'。

+0

很高興知道顯式的render-call構造(使用另一個動作的模板)。我改變了一下你的建議,通過重新制作我的tagDTO和suppyling,e。 g:render(「@ showTag」,tagDTO); –

+0

也很好知道(並且當你想到它時非常合乎邏輯)你不需要params.flash();和/或validation.keep();在做渲染之前(「@ showTag」,tagDTO); (如果你這樣做,你會被上一篇文章中的錯誤搞砸)。再次感謝 –

0

再次渲染表單並避免重定向是一個解決方案。我認爲如果用戶按下F5,他會再次出現錯誤。但我認爲你應該創建一個重載/取消按鈕,這樣用戶可以關閉所有信息。

要始終具有正確的URL,您可以在路線中執行以下操作。conf:

GET /tag/create  TagController.create 
POST /tag/create  TagController.insert 

Flash解決方案的缺點是您的cookie可能變得非常大。

+0

謝謝,我確實已經改變了路線文件到類似的東西。可以肯定的是,你實際上正在推出與上面「sjn」相同的解決方案? (所以渲染沒有重定向,並沒有使用閃存對象)? –

+0

@ Geert-Jan:是的。 – niels

相關問題