2

Simplified example.

I have a Model which has a few fields:

OwnerFirstName
OwnerLastName
List<Pet> Pets (Pet is a few string fields)

The UI needs to allow the user to add any number of new Pets. The UI for the Pet entry is an MVC template _petEditor.cshtml

Client side, how do I add a new Pet to the Model's Pet collection, then add a new set of fields for the Pet from _petEditor.cshtml ?

When the user submits the form, MVC will get a model with all the Pets added.

tereško
  • 58,060
  • 25
  • 98
  • 150
Ian Vink
  • 66,960
  • 104
  • 341
  • 555
  • If you want to dynamically add pet one by one on your form you probably can only do this manually. – Stan Jun 03 '14 at 23:04
  • Please include the petEditor.cshtml and the simplified View where you're including it (removing stuff not relevant to the question). It helps to address the question more clearly. – arserbin3 Jun 03 '14 at 23:10
  • -1 You need to provide some code. – ataravati Jun 03 '14 at 23:47

1 Answers1

6

You could use javascript to dynamically create indexed inputs for post back. As an example create a dummy set of inputs that are cloned and displayed when you click an 'add pet' button (assumes Pet properties are displayed in a table with id='Pets')

<div id="NewPet" style="display:none">
  <tr>
    <td><input type="text" name="Pets[#].Type value /></td>
    <td><input type="text" name="Pets[#].Breed value /></td>
    <td>.....</td> // more properties of Pet
    <td><input type="hidden" name="Pets[#].Index" value ="%"/></td>
  </tr>
</div>

Note the use of a dummy indexer to prevent this one being posted back

And the script

$('#AddButton').click(function() {
  var index = (new Date()).getTime(); 
  var clone = $('#NewPet').clone();
  // Update the index of the clone
  clone.html($(clone).html().replace(/\[#\]/g, '[' + index + ']'));
  clone.html($(clone).html().replace(/"%"/g, '"' + index  + '"'));
  $('#Pets tbody').append(clone.html());
}
  • why do you have two lines that are cloning? – Abdul Ahmad Oct 24 '14 at 14:20
  • also, what does adding the hidden "Pets[#].Index" do? I don't have an Index property in my model – Abdul Ahmad Oct 24 '14 at 14:50
  • 1
    @AbdulAhmad. When posting back collections, the `DefaultModelBinder` requires the indexers to start and zero and be consecutive. Adding `Pets[#].Index` (it can be just `Pets.Index`) allows the `ModelBinder` to use non consecutive indexers (in fact the indexers could be `"ABC", "XYZ"` instead of `0, 1, 2`). So long as the value of `Index` matches the properties name indexer (the bit between the square brackets), then then the collection will be successfully posted. Index is not a property of your model (and should not be). It is just a property used internally by the `ModelBinder`. –  Oct 25 '14 at 00:19
  • I see, the clone.html line in the javascript isn't working for me for some reason, is there a syntax error? – Abdul Ahmad Oct 25 '14 at 00:23
  • 1
    @AbdulAhmad, The last line of the script has a error and should be `$('...').append(clone.html());` I assume OP picked this up. Note also if you want to be able to delete also, then setting `var index` to the number of existing items wont work (you could end up with identical indexers) so you can use `var index = (new Date()).getTime();` so the indexer is always a unique value. –  Oct 25 '14 at 00:48
  • Name seems to missing closing quotations, and value does not have anything assigned to it? – JsonStatham Jan 29 '16 at 14:13
  • 1
    I dont fully understand why but for my dummy indexer I could not use `Collection[#].Index` for the name. It would only work for me when using a name of `Collection.Index` for the dummy indexer. – GER Jun 13 '17 at 12:57