2010-08-17 66 views
2

我的主要問題是在一個動態表單中管理一對多關係時處理pramas地圖,以及處理一對多時通過動態表單編輯/更新域對象。我的問題的輸入如下。在grails中處理來自動態表單的一對多關係的參數

我設法破解了一個表單,允許我在一個Dynamic表單中創建下面顯示的域對象,因爲創建電話號碼並將其分配給聯繫人的單獨表單沒有意義,在我的應用程序中以一種形式創建所有內容是有意義的。我成功地實現類似的東西我都問我Previous Question(感謝誰幫助了人)我基本上成功地從「PARAMS」地圖獲取值和分析他們對我自己和

class Contact{ 

    String firstName 
    String lastName 
    // .... 
    // some other properties 
    // ... 

    static hasMany = [phones:Phone] 
    static mapping = { 
     phones sort:"index", cascade: "all-delete-orphan" 
    } 
} 

class Phone{ 
    int index 
    String number 
    String type 
    Contact contact 

    static belongsTo = [contact:Contact] 
} 

手動創建域對象和關聯。即我沒有使用在默認的腳手架使用相同的邏輯,即

Contact c = new Contact(params) 

等....,我只是通過所有的PARAMS循環和手工製作的我的域對象並保存它們,一切順利罰款。

我的控制器有看起來像這樣的(這是剝離下來,只是展現出點)的代碼塊

//create the contact by handpicking params values 
def cntct = new Contact() 
cntct.firstName = params.firstName 
cntct.lastName = params.lastName 
//etc... 

//get array of values for number,type 
def numbers = params['phone.number'] 
def types = params['phone.type'] 

//loop through one of the arrays and create the phones 
numbers.eachWithIndex(){ num, i -> 
    //create the phone domain object from 
    def phone = new Phone() 
    phone.number = num 
    phone.type = types[i] 
    phone.index = i 
    cntct.addToPhones(phone) 
} 

//save 

我的問題如下:

  • 什麼是最好的做法在這種情況下,如果使用Command對象,在這種情況下會使用Command對象,如果是的話,我可以在哪裏找到關於此的更多信息,我在搜索過程中發現的所有示例都與一對一關係有關,我無法找到示例一對多?
  • 在這種情況下,處理手機關係的最佳方式是在編輯聯繫人對象時添加/刪除手機。我的意思是創建邏輯很簡單,因爲我必須總是在保存時創建新手機,但在處理更新聯繫人時,用戶可能已經刪除了手機和/或編輯正在退出的手機和/或添加了一些新手機。現在我所做的只是刪除聯繫人所擁有的所有電話,並根據表單發佈的內容重新創建它們,但我認爲這不是最好的方式,我也不認爲現有的並與發佈的值進行比較,並做一個手動差異是最好的方法來做到這一點,是否有最佳做法如何處理?

謝謝,希望問題很清楚。

[編輯]只是爲了更多的信息,電話信息,可以添加和使用JavaScript(jQuery的)形式在[/編輯]

回答

1

免責聲明動態刪除:我不知道,如果下面的方法使用Grails工程時。稍後再告訴我。

參見better way for dynamic forms。作者說:

要添加LineItems我有一些js計算新的索引,並將其添加到DOM。當刪除的LineItem 我不得不重新編排所有的索引,這是我想什麼來避免

所以我做什麼

我有存儲的下一個索引

var nextIndex = 0; 
變量

當頁面加載時,我執行一個JavaScript函數,它計算該集合有多少個子項並配置nextIndex變量。您可以使用JQuery或YUI,隨意。

添加子靜態

創建該存儲模板變量(注意:{指數}

var child = "<div>" 
      +=  "<div>" 
      +=   "<label>Name</label>" 
      +=   "<input type="text" name=\"childList[{index}].name\"/>" 
      +=  "</div>" 
      += "</div>" 

當在用戶點擊添加子按鈕,我替換{index} - 使用正則表達式 - 存儲在nextIndex變量中的值並加1。然後我添加到DOM

參見Add and Remove HTML elements dynamically with Javascript

添加子dinamically

Here你可以看到的保羅Bergantino解決方案

通過消除

但我認爲這是刪除時成長的問題。無論您刪除多少個孩子,都不會觸及nextIndex變量。看到這裏

/** 
    * var nextIndex = 3; 
    */ 

<input type="text" name="childList[0].name"/> 
<input type="text" name="childList[1].name"/> // It will be removed 
<input type="text" name="childList[2].name"/> 

想我刪除的childList 1我該怎麼辦???我應該重新編號所有的指標嗎?

在服務器端我使用AutoPopulatingList。由於childList 1已被刪除,AutoPopulatingList 將其視爲空。因此,在初始化我做

List<Child> childList = new AutoPopulatingList(new ElementFactory() { 
    public Object createElement(int index) throws ElementInstantiationException { 
     /** 
     * remove any null value added 
     */  
     childList.removeAll(Collections.singletonList(null)); 

     return new Child(); 
    } 
}); 

這樣,我的收藏只包含兩個子(沒有任何空值)和我不需要重新編排各項指標在客戶端

關於添加/刪除你可以看到這個link我在哪裏顯示一個場景,這可以給你一些見解。

參見Grails UI plugin

1

感謝,

你的答案帶來了一些見解爲我做更廣泛的搜索,我居然發現了一個偉大的職位,涵蓋了我的問題所有的輸入。這僅僅是任何閱讀本文的參考資料。我會寫一篇關於我如何儘快實施我的案例的博客文章,但這個鏈接應該提供一個很好的工作實例來源。

http://www.2paths.com/2009/10/01/one-to-many-relationships-in-grails-forms/

+0

謝謝您分享您的搜索。非常好!(+1) – 2010-08-20 15:14:12

+0

我已經發布了關於我如何完成電話簿示例的指南,主要基於上述文章。希望它會有所幫助。 http://omarello.com/2010/08/grails-one-to-many-dynamic-forms/ – omarello 2010-08-21 10:55:19

+0

現在感謝您分享您的知識。我將通過使用AutoPopulatingList來嘗試它。只是爲了好奇:Grails滿足你的需求嗎? – 2010-08-21 22:23:40

0

大部分時間我使用AJAX來管理這些問題的時間。

因此,當用戶點擊add new phone時,我從服務器獲取模板用戶界面用於管理目的(UI與我用來編輯和更新手機的GSP模板相同),這樣您就不會混淆您的用戶界面js代碼,只要你想改變UI,你只能處理我們的GSP代碼。

然後獲得用戶界面後,我使用jQuery DOM操作將其添加到頁面。然後填寫表格後,他們點擊add(save)該請求通過ajax發送到服務器,並立即堅持。

當用戶點擊edit phone從充滿現有電話數據的服務器加載相同的UI模板,然後單擊更新將立即通過ajax更新相應的電話,同樣的事情適用於刪除操作。

但有一天,我得到了一個額外的場景,用例說:「直到我說保存聯繫人,沒有電話將被保存在後端,也是在將電話添加到用戶界面上的聯繫人後,如果離開另一個頁面,稍後聯繫頁面我添加了手機之前必須仍然存在「啊來..

要做到這一點,我開始使用Session,所以我解釋了上述操作將作用在電話列表對象我存儲在會話而不是數據庫。這是簡單的phonesInSession執行所有操作,但最後不要忘了這樣做(刪除更新):

phonesToBeDeleted = phonesInDB - phonesInSession 

phonesToBeDeleted.each{ 
contact.removeFromPhones(it) 
it.delete() 
} 

我知道我沒有把大量的數據會話,但這是我唯一的解決辦法爲我的場景。

如果有人有類似的問題/解決方案,請留下評論。

0

首先,在所有的輸入字段名稱添加一個@:

<input type="text" name="references[@].name"/> 

二,添加調用一個函數在提交前:

<g:form action="save" onsubmit="replaceAllWildCardsWithConsecutiveNumbers();"> 

第三,這是該函數的代碼您在提交表格前打電話:

function replaceAllWildCardsWithConsecutiveNumbers(){ 
    var inputs = $('form').find("[name*='@']"); 
    var names = $.map(inputs, function(el) { return el.name }); 
    var uniqueNames = unique(names); 

    for (index in uniqueNames) { 
     var uniqueName = uniqueNames[index];          
     replaceWildCardsWithConsecutiveNumbers("input", uniqueName);       
     replaceWildCardsWithConsecutiveNumbers("select", uniqueName); 
    } 
} 

function unique(array){ 
    return array.filter(function(el, index, arr) { 
     return index === arr.indexOf(el); 
    }); 
} 

function replaceWildCardsWithConsecutiveNumbers(inputName, name){ 
    counter = 0; 
    $(inputName + "[name='" + name + "']").each(function (i, el) { 
     var curName = $(this).attr('name'); 
     var newName = curName.replace("@", counter); 
     $(this).attr('name', newName); 
     counter += 1; 
    }); 
} 

基本上,代碼爲replaceAllWildCardsWithConsecu tiveNumbers()的作用是爲所有名稱包含@的輸入(或選擇)元素創建一個列表。刪除重複項。然後用一個數字代替@來迭代它們。

如果您有一張表,並且您在第一次創建域類時將值提交給命令對象的列表,此功能將非常有用。如果您正在更新,我想您必須將計數器的值更改爲更高的值。

我希望這可以幫助別人,因爲我自己在這個問題上停留了一段時間。