Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I've had to deal with exactly that same situation as well. The easiest solution I came up with, was using a wrapper model, similar to:</p> <pre><code>public class QuestionListModel { public IList&lt;QuestionModel&gt; Questions { get; set; } public IList&lt;QuestionModel&gt; Template { get { return new List&lt;QuestionModel&gt; { new QuestionModel {/* defaults for new question */} }; } } public QuestionListModel() { Questions = new List&lt;QuestionModel&gt;(); } } </code></pre> <p>The important part, is having the <b>Template</b> property, which is also a an <code>IEnumerable&lt;T&gt;</code> of the same type as the actual model you want. That way, the auto-numbering will be done for you by MVC. So using this model, what you get is, your collection, with "Questions_0__Title" numbering, and you also get one template row with "Template_0__Title" naming.</p> <p>I keep my template row hidden from the UI and use it when adding a new row.</p> <p>In razor, you'd bind the template just as you'd bind a regular question, the only difference is it would be in a hidden <code>&lt;div&gt;</code>. You also would need to bind the <code>Count</code> of your Questions list to a hidden field as well. In my case, I have an editor template for a Question, which renders it inside <code>&lt;div&gt;</code> with a specific selector, for easy access later on. So what you end up with is something similar to:</p> <pre><code>&lt;div class="templateContainer"&gt; &lt;div class="question"&gt; [Template] &lt;/div&gt; &lt;/div&gt; &lt;div class="items"&gt; [for each of your items] &lt;div class="question"&gt; [Question] &lt;/div&gt; &lt;/div&gt; </code></pre> <p>When adding a row, the trick is, using javascript: </p> <ol> <li><p>Get the count from the hidden field, increment it.</p> <pre><code> var counter = $("#QuestionsListCount"); var count = parseInt(counter.val()); count++; </code></pre></li> <li><p>Take the entire template block, clone it (using jquery's <code>.clone(true)</code> for example), name it as something unique (using the counter value from step 1 for example), and append it to the section where your questions are.</p> <pre><code> var template = $("#templateContainer"); var newItem = template.clone(true); var newId = "item_" + count; var newQuestion = newItem.children().first(); newQuestion.attr("id", newId); newQuestion.appendTo('#items'); </code></pre></li> <li><p>For each item, such as inputs in your new appended block (you can find it with the new id you assigned to it), you replace ids => "Template_0" with "Questions__count from step 2", and names => "Template[0]" with "Questions[count from step 2]".</p> <pre><code> $("#" + 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) + "]"); }); </code></pre></li> <li><p>Update the hidden field for the counter=> <code>counter.val(count);</code></p></li> <li>...</li> <li>profit!</li> </ol> <p>Now, regarding deletions, the way I do it, is, my ViewModel for it actually has an <code>IsDeleted</code> flag, which i bind to a hidden field within the Question editor template as well. That way, deletions are as simple as hiding the particular Question (the question selector comes handy) and you set that <code>IsDeleted</code> field to true. When you get your entire list back through the default model binder, you need to discard all deleted ones (or issue actual deletes, depending on your back-end data model).</p> <p>This way I avoid having to deal with individual ways of identifying deleted items, and also renumbering all the items in the UI. Plus, you get the advantage of having server-side code determine what should actually happen when deleting (such as validating or undoing the action).</p> <p>It is a long post, but the implementation is not really that difficult (or long), and can easily be reused in a generic way.</p> <p>Cheers!</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload