2

手がかりのリストを含む「TreasureHuntDetails」オブジェクトにバインドするビュー モデルがあります。これがそのデータモデルの一部です。

    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 ループ内のテーブル要素は非常に大きいですが、テーブル要素列の 1 つの例を次に示します。

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

これまでのところ、すべて順調です。次に、JQuery UI を使用して、次のように、ドラッグ アンド ドロップを使用してテーブルの項目を並べ替えることができるようにしています。

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

要素をドラッグ アンド ドロップできます。

問題は、要素の新しい順序を保存してデータベースに保存する方法がわからないことです。

私が最初に試みたのは、単に手がかりのリストをコントローラー メソッドに渡すことでしたが、手がかりのリストがコントローラー メソッドに到達すると、それは常に null であることがわかりました。

例えば:

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

@Model 全体を送信しても、その中の手がかりのリストは常に null です。データ モデルのコンストラクターから新しいリストのインスタンス化を削除しても、この問題は解決しませんでした。

私が試したもう 1 つのことは、テーブル全体を HTML フォームにラップすることでしたが、それでも手がかりのリストは null のままです。

つまり、基本的に、この質問は実際には 2 つの質問です。

1) モデル オブジェクトをコントローラーに送信した後、手がかりのリストが常に null になるのはなぜですか。

2) アイテムのリストの新しい順序を保存する方法は?

更新: @recursive による提案に従って、手がかり要素を HTML フォームに送信しようとしたときにどこでエラーが発生したかがわかります。

手がかり要素を反復処理する for ループの外側でこれを使用しました。

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

for ループ内 (手がかりアイテムごと) に HiddenFor 行を追加し、手がかりアイテムの各プロパティに追加する必要がありました。

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

リスト項目をコントローラーに送信できるようになることは一歩前進ですが、コントローラーに送信されたときに手がかり項目の新しい順序を反映するコードが必要だと思います。現在、JQuery の sortable() メソッドを使用して画面上の要素の順序を並べ替えても、要素はビューにバインドされたデータ モデル (@Model.Clues) に格納されているため、要素の順序は変更されません。

4

3 に答える 3

5

1) @resursive がコメントで述べたように、Clueクラスのプロパティにマップする非表示の要素がページに必要です。

2) 手がかりの順序を保持するには、リスト内の各手がかりの位置を保持する列をデータベースに追加し、位置プロパティをクラスに追加する必要があります。したがって、クラスに含める必要があります

public int Position {get;set;}

ページの作成時にデータベースからプルする必要があります。次に、ページをレンダリングする直前に、Position 変数に基づいて手がかりリストを並べ替える必要があります。

編集: jquery の sortable 属性を使用します。このスレッドを参照してください。ドラッグ停止イベント (または送信の直前) で、ドラッグ可能な各オブジェクトをループし、オブジェクトの非表示の各位置プロパティの値を設定します。

var positionIndex = 0;
$('.draggableObjectClass).each(function () {
    $(this).find('input[id$=_Position]').val(positionIndex++);
});
于 2013-04-24T18:29:05.667 に答える
0

しかし、コントローラーに送信されたときに手がかりアイテムの新しい順序を反映するコードがまだ必要だと思います。

ループで繰り返し処理してforいるため、ビューに送信した順序でインデックスが作成されます。注文はすでに維持されている必要があります。

于 2013-04-24T18:52:49.583 に答える
0

すでにここに投稿された回答からアドバイスを受けて、次の解決策を思いつきました。

UI 要素のドラッグ アンド ドロップによる並べ替えを実装するために、このメソッドが既に配置されているため、

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

項目の新しい順序で読み取り、MVC コントローラーに送信できる方法が必要でした。これを行うために、次のように、Razor @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」メソッドを呼び出し、シリアル化されたバージョンのデータ モデル (元の順序での手がかりアイテムのリストを含む) と、次のリストを含む配列を渡します。手がかりIDは新しい順序です。コントローラー (.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 が Entity Framework データベース コンテキストです。

于 2013-04-25T19:05:05.660 に答える