2013-04-24 88 views
2

我有一個視圖模型綁定到'TreasureHuntDetails'對象,其中包含一個線索列表。這是它的數據模型的一部分。從MVC視圖模型保存重新排序的列表項

public TreasureHuntDetails() 
    { 
     Clues = new List<Clue>(); 
    } 

    [Key] 
    public int TreasureHuntId { get; set; } 

    public List<Clue> Clues { get; set; } 

在頁面上,我有一張桌子。 foreach循環迭代線索列表以將它們添加到表格中,例如,

@for (int i = 0; i < Model.Clues.Count; i++) 

裏面的for循環是相當大的表格元素,但這裏的表格單元列的一個示例:

<td>@Html.DisplayFor(m => Model.Clues[i].Location)</td> 

一切都很好,到目前爲止。然後我使用jQuery UI,使表的項目使用拖放功能,這樣可以重新排序:

 <script type="text/javascript"> 
     $(document).ready(function() 
     { 
      $("#clueTable tbody").sortable().disableSelection(); 
     }); 
     </script> 

一切都很好,我可以拖放的元素。

問題是我不知道如何保存元素的新順序並將它們保存回數據庫。

我嘗試的第一件事就是將線索列表傳遞給控制器​​方法,但我發現一旦線索列表到達控制器方法,它總是空。

例如:

@Url.Action("ViewCluePage", @Model.Clues) 

即使我送全@Model,線索的列表中總是空。從數據模型的構造函數中刪除新的列表實例並沒有解決這個問題。

我試過的另一件事是將整個表格封裝到一個HTML表格中,但仍然是線索列表爲空。

因此,基本上,這個問題實際上是兩個問題:

1)爲什麼線索發送的模型對象控制器後總是空的列表。

2)如何保存項目列表的新訂單?

更新:按照@recursive的建議,當我嘗試將提示線索元素提交給HTML表單時,我發現我犯了一個錯誤。

我用這以外的for循環,其遍歷線索元素:

@Html.HiddenFor(m => m.Clues) 

我不得不把HiddenFor行添加的內部進行循環(每個線索項),以及用於的每個屬性線索項目,例如

@Html.HiddenFor(m => m.Clues[i].Id) 

因此,這將是向前邁出的一步,以便能夠獲取發送到控制器列表中的項目,但我覺得我還是需要代碼時發送到控制器,將反映的線索項目的新秩序。目前,在使用JQuery sortable()方法重新排列屏幕上元素的順序時,這並不會改變元素的順序,因爲它們存儲在綁定到視圖(@ Model.Clues)的數據模型中。

+1

爲了使新列表回到控制器操作中,列表項的生成html必須包含一些像'的元素。你的列表項html是什麼樣的?您可以將其添加到您的問題。 – recursive 2013-04-24 18:15:14

+0

我的回答對你有幫助嗎?你能接受答案嗎? – gwin003 2013-04-25 15:04:55

+0

是的,它確實感謝,它讓我走上了正確的道路,所以我已經提出了你的答案。儘管我已經完成了很多不同的實現,所以我稍後會發布它。 – 2013-04-25 16:43:47

回答

5

1)@resursive在他的評論中說,你需要在頁面上有隱藏的元素映射到Clue類中的屬性。

2)至於堅持線索順序,您需要添加一個列到您的數據庫,該列包含列表中每個線索的位置並將位置屬性添加到您的類。所以你的課程需要包括:

public int Position {get;set;} 

當創建頁面時,它應該從數據庫中提取。然後,在渲染頁面之前,您應該根據位置變量對線索列表重新排序。

編輯:使用jQuery的可排序屬性。 Check out this thread for reference.在停止拖動事件中(或在提交之前),遍歷每個可拖動對象並設置對象的每個隱藏Position屬性的值。

var positionIndex = 0; 
$('.draggableObjectClass).each(function() { 
    $(this).find('input[id$=_Position]').val(positionIndex++); 
}); 
+0

這種方法的缺點是我不得不重構很多代碼才能讓它在Web應用程序中運行。 – 2013-04-24 19:20:17

+0

另外,如何從視圖中真正獲得新的職位?根據您對(1)的建議,我可以成功發送線索列表給控制器,但原始訂單保持不變 - 新訂單未反映。 – 2013-04-24 19:25:33

+1

我編輯了答案給你一個開始。 – gwin003 2013-04-24 19:55:35

0

,但我想我還是需要代碼時發送到控制器,將反映的線索項目的新秩序。

你不會的,因爲你現在在for循環遍歷它們,它們會在你送他們到視圖次序索引。您的訂單必須已經保存。

+0

重新排列線索元素的順序並不會改變它們存儲在數據模型中的順序,儘管... – 2013-04-24 19:18:13

+0

@CiaranG非常真實,除非你正在改變它? – mattytommo 2013-04-24 19:18:55

+0

在重新排列元素並向控制器發送線索列表之後,線索元素仍然處於其原始順序......我需要找出一種方法讓模型獲取元素的新順序。 – 2013-04-24 19:22:04

0

從這裏發佈的答案中獲得建議,我想出了以下解決方案。

有了實現拖放UI元素進行重新排序已經有這種方法,

$(document).ready(function() 
    { 
     $("#clueTable tbody").sortable().disableSelection(); 
    }); 

我需要一種能夠讀取在項目的新秩序,並將其發送到MVC控制器。要做到這一點我用剃刀@ Html.AttributeEncode方法寫入每個項的ID的一列在表的每一行,像這樣:

<td class="Ids" id="@Html.AttributeEncode(Model.Clues[i].Id)">@{var number = i + 1; @number}</td> 

(這是圍繞一個for循環它迭代通過包裹項目列表)

然後,我創建了以下Javascript函數,該函數從一個'SaveNewOrder'按鈕中調用,放在我的元素表上方(用戶在完成對錶上的項目重新排序後按下它):

function getNewOrder() 
    { 
     var positions = new Array(); 
     for (var i = 0; i < $('.Ids').length; i++) 
     { 
      positions[i] = $('.Ids')[i].id; 
     } 
     $.ajax(
      { 
       type: "POST", 
       url: "@Url.Action("ReorderClues", "Clues")", 
       data:{ treasureHuntDetails: $("form").serialize(), ids: JSON.stringify(positions) } 
       contentType:'application/json' 
      }).done(function() 
      { 
       window.location.href = '@Url.Action("Clues", Model)'; 
      }). 
    } 

這是做什麼是從每個表項中讀取Id元素,並將它們寫入數組 - 這樣該數組包含Id的新順序。包含項目的數據模型在重新排序表格元素後不會改變,因此這是必要的。

然後,它使用JQuery Ajax方法在我的'Clues'MVC控制器上調用'ReOrderClues'方法,傳遞數據模型的序列化版本(包含原始順序中的線索項列表)和數組包含新訂單中線索標識的列表。當從控制器(.done)返回結果時,我調用一個刷新頁面元素的控制器。

因此,我所做的不是維護與每個線索相關的位置值(這將涉及代碼中其他地方的重大重構),而是交換線索內容以反映新順序,但保留Id的位置相同。

我這是怎麼實現的,使用的MVC控制器:

public ActionResult ReorderClues(TreasureHuntDetails treasureHuntDetails, int[] ids) 
{ 
    using (var db = new TreasureHuntDB()) 
    { 
     var clues = treasureHuntDetails.Clues; 
     var newClues = NewOrderList(clues, ids); 

     // Save the changes of each clue 
     for (var i = 0; i < newClues.Count;i++) 
     { 
      db.Entry(clues[i]).CurrentValues.SetValues(newClues[i]); 
      db.SaveChanges(); 
     } 

     treasureHuntDetails.Clues = newClues; 
     TempData["Success"] = "Clues reordered"; 
    } 

    return RedirectToAction("Clues", treasureHuntDetails); 
} 

public List<Clue> NewOrderList(List<Clue> clues, int[] ids) 
{ 
    var newClueOrder = new List<Clue>(); 

    // For each ID in the given order 
    for (var i = 0; i < ids.Length; i++) 
    { 
     // Get the original clue that matches the given ID 
     var clue = clues.First(clue1 => clue1.Id == ids[i]); 

     var newClue = Clue.Clone(clue); 

     // Add the clue to the new list. 
     newClueOrder.Add(newClue); 

     // Retain the ID of the clue 
     newClueOrder[i].Id = clues[newClueOrder.Count - 1].Id; 
    } 

    return newClueOrder; 
} 

在上面的代碼片段,TreasureHuntDB是我的實體框架數據庫上下文。