3

私は過去にこれを行ったことがあり、もう一度やらなければならないかもしれませんが、その前に、人々がそれをどのように扱うかを見るためにそれをそこに捨てたいと思います。

かみそりのビュー:

<ul>
   @Html.EditorFor(model => model.Questions)
</ul>

生成される可能性があるもの:

<ul>
   <li><input type="text" id="Questions_0__Title" name="Questions[0].Title" value="hi"/></li>
   <li><input type="text" id="Questions_1__Title" name="Questions[1].Title" value="hi2"/></li>
<ul>

かなりシンプル。

ここで、ユーザーがこれらの「質問」を追加、編集、または削除できるようにする必要があります。

編集の場合、それは簡単です-作業は必要ありません。ただし、追加/削除の場合、jQueryを使用して行う場合は、「id」属性と「name」属性を生成する方法を賢くする必要があります(たとえば、存在する数のカウントを取得する、1を追加するなど)。 )、およびdeleteの場合、一部の要素を「再レンダリング」します(たとえば、1つが削除された場合、後続のすべての要素の「id」属性と「name」属性を-1に変更する必要があります)。

これはすべて、フォームであり、モデルにバインドする必要があるためです。

それは私にはあまりにも毛深いので、過去に、フォーム上にあるものを使用してサーバーに対してAJAX呼び出しを行い、コントローラーで要素を追加/削除して、部分的なビューをレンダリングしました。このようにして、すべての要素が「モデルにバインドされる準備ができています」。私はまだ少しだけjQueryが必要ですが、それほど多くはありません。

誰かがより良い方法を見つけましたか?

4

3 に答える 3

3

私もまったく同じ状況に対処しなければなりませんでした。私が思いついた最も簡単な解決策は、次のようなラッパーモデルを使用することでした。

public class QuestionListModel
{
    public IList<QuestionModel> Questions { get; set; }

    public IList<QuestionModel> Template
    {
        get
        {
            return new List<QuestionModel>
                       {
                           new QuestionModel {/* defaults for new question */}
                       };
        }
    }

    public QuestionListModel()
    {
        Questions = new List<QuestionModel>();
    }
}

重要なのは、Templateプロパティを持っていることです。これも、IEnumerable<T>必要な実際のモデルと同じタイプです。そうすれば、MVCによって自動番号付けが行われます。したがって、このモデルを使用すると、「Questions_0__Title」の番号が付けられたコレクションが取得され、「Template_0__Title」の名前が付けられた1つのテンプレート行も取得されます。

テンプレート行をUIから非表示にして、新しい行を追加するときに使用します。

かみそりでは、通常の質問をバインドするのと同じようにテンプレートをバインドします。唯一の違いは、非表示になっていること<div>です。Countまた、質問リストのを非表示フィールドにバインドする必要もあります。私の場合、質問用のエディターテンプレートがあり、<div>後で簡単にアクセスできるように、特定のセレクターを使用して内部にレンダリングします。したがって、最終的には次のようなものになります。

<div class="templateContainer">
  <div class="question">
    [Template]
  </div>
</div>
<div class="items">
  [for each of your items]
  <div class="question">
    [Question]
  </div>
</div>

行を追加するときの秘訣は、javascriptを使用することです。

  1. 非表示フィールドからカウントを取得し、インクリメントします。

        var counter = $("#QuestionsListCount");
        var count = parseInt(counter.val());
        count++;
    
  2. テンプレートブロック全体を取得し、クローンを作成し(jqueryなどを使用.clone(true))、一意の名前を付け(たとえば、手順1のカウンター値を使用)、質問があるセクションに追加します。

        var template = $("#templateContainer");
        var newItem = template.clone(true);
        var newId = "item_" + count;
        var newQuestion = newItem.children().first();
        newQuestion.attr("id", newId);
        newQuestion.appendTo('#items');
    
  3. 新しく追加されたブロックへの入力(割り当てた新しいIDで見つけることができます)などの各項目について、ids => "Template_0"をステップ2の"Questions__count"に置き換え、names => "Template [ 0]」と「質問[ステップ2からのカウント]」。

        $("#" + newId + " :input").each(function (index, input) {
            input.id = input.id.replace("Template_0", "Questions_" + (count - 1));
            input.name = input.name.replace("Template[0]", "Questions[" + (count - 1) + "]");
        });
    
  4. カウンターの非表示フィールドを更新します=>counter.val(count);

  5. ..。
  6. 利益!

さて、削除に関しては、私が行う方法は、それに対する私のViewModelには実際にIsDeletedフラグがあり、それを質問エディターテンプレート内の非表示フィールドにもバインドします。そうすれば、削除は特定の質問を非表示にするのと同じくらい簡単で(質問セレクターが便利です)、そのIsDeletedフィールドをtrueに設定します。リスト全体をデフォルトのモデルバインダーに戻すときは、削除されたものをすべて破棄する必要があります(または、バックエンドデータモデルによっては実際の削除を発行します)。

このようにして、削除されたアイテムを識別する個々の方法を処理したり、UI内のすべてのアイテムの番号を付け直したりする必要がなくなります。さらに、サーバー側のコードで、削除時に実際に何が発生するか(アクションの検証や取り消しなど)を決定できるという利点があります。

これは長い投稿ですが、実装はそれほど難しく(または長く)なく、一般的な方法で簡単に再利用できます。

乾杯!

于 2012-05-14T12:56:37.113 に答える
0

これらのものには主キーIDフィールドがあると思いますか?

それが最善の方法かどうかはわかりませんが、deletedIdsなどの非表示の入力フィールドがあります。入力要素をレンダリングするときに、次のような属性を追加します。

data-rowId='@Model.Id'

次に、[削除]をクリックすると、非表示のリストにIDを追加するか、cssクラスで行を削除済みとしてマークし、送信する前に最後にそれらをすくい上げます。たとえば、次のようになります。

var deletedIds = [];
$('myselector').each(function(){ deletedIds.push($(this).attr('data-rowId'));});
$('deletedIds').val(deletedIds.join(','));

次に、文字列をサーバー上の配列に分割します。

それらを位置的に処理していて、サーバー上のシーケンスがリクエスト間で変更できないことが確実な場合は、同じアプローチを使用しますが、IDではなく配列のインデックスを使用します。

于 2012-05-14T09:34:04.127 に答える
-5

だから私はもっと良い解決策を考えました、それはまったくJSを必要としません。

  1. 私のコントローラーでは、約100個の要素を持つモデルを作成します。すべて空ですが、「新しく」なり、cssクラスが「非表示」になっています
  2. 入力されている既存の値の数に基づいて、「非表示」のcssクラスを削除するなど、要素を更新します。
  3. 次に、CSSを使用して、「非表示」のcssクラスを持つものを非表示にします。
  4. [さらに追加]をクリックすると、最初の3つの要素から「非表示」クラスが削除されます。
  5. 「削除」をクリックすると、「非表示」クラスをに追加し直すだけです。

簡単です、なぜ私は以前にこれを考えなかったのですか。

于 2012-05-25T06:50:21.113 に答える