0

I have project on ASP MVC 5. I have a model "Article". This model have HashSet and ICollection of Author. Author - second model:

 public partial class Article
{
    public Article()
    {
        Authors = new HashSet<Author>();
    }

    [DisplayName("Авторы")]
    public virtual ICollection<Author> Authors { get; set; }

I need to add page of creating Article, on which you can increase the number of authors(using AJAX), and each author to register the fields. I decided to use partial view of Author's model, without "Create" button(Create button used only view of creating Article). I need in unlimited adding new partial views, and after fill them - get all data from them. How make it? I newbie in MVC, and can't imagine how it will works.

https://i.stack.imgur.com/0RHD0.png - an illustration of how it should look

Vasiliy Terkin
  • 165
  • 2
  • 15
  • Some options [here](http://stackoverflow.com/questions/28019793/submit-same-partial-view-called-multiple-times-data-to-controller/28081308#28081308) and [here](http://stackoverflow.com/questions/29161481/post-a-form-array-without-successful/29161796#29161796) –  Aug 13 '15 at 22:23

2 Answers2

0

It is not that hard. Your partial views will be posted as a collection.

Suppose that your partial view has 2 values, FirstName and LastName. It should be something like this:

@{
    Guid index = Guid.NewGuid();
}
<input type="hidden" name="People.index" value="@index" />
<input type="text" name="People[@index].FirstName" value="" />
<input type="text" name="People[@index].LastName" value="" />

The final output would be:

<input type="hidden" name="People.index" value="B756DAD8-5D5D-449E-A4B4-E61F75C1562C" />
<input type="text" name="People[B756DAD8-5D5D-449E-A4B4-E61F75C1562C].FirstName" value="" />
<input type="text" name="People[B756DAD8-5D5D-449E-A4B4-E61F75C1562C].LastName" value="" />

<input type="hidden" name="People.index" value="B78B7BBC-EB0E-41CB-BE18-C1E3F7526F32" />
<input type="text" name="People[B78B7BBC-EB0E-41CB-BE18-C1E3F7526F32].FirstName" value="" />
<input type="text" name="People[B78B7BBC-EB0E-41CB-BE18-C1E3F7526F32].LastName" value="" />

Your model must have a collection People object.

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
} 

public class Article
{
    //other properties...

    public ICollection<Person> People { get; set; }
}

Your Controller:

public ActionResult YourAction (Article model)
{
    //...
}

Untested code, but it should work fine.

Fabio
  • 11,892
  • 1
  • 25
  • 41
  • sorry, when I say `YourViewModel` I mean `Article` model. I edited the answer – Fabio Aug 21 '15 at 18:05
  • Yes, i understand you. But where i put [index],if i have this: Html.LabelFor(model => model.surname, htmlAttributes: new { class = "control-label col-md-2" })
    Html.EditorFor(model => model.surname, new { htmlAttributes = new { class = "form-control" } }) Html.ValidationMessageFor(model => model.surname, "", new { class = "text-danger" })
    and how i will get Authors in controller? I known't GUID that generated in cshtml
    – Vasiliy Terkin Sep 01 '15 at 20:28
  • You put the index before all the inputs. Instead of `Html.EditorFor(model => model.surname, new { htmlAttributes = new { class = "form-control" } })` you have to use `Html.Editor("Authors[" + index + "].surname", model.surname, new { htmlAttributes = new { class = "form-control" } })`. Just follow the answer and everything will work fine – Fabio Sep 01 '15 at 21:23
  • This also should work `@Html.TextBoxFor(model => model.surname, new { Name = "Author[index].surname", @class= "form-control"})` – Fabio Sep 01 '15 at 21:50
0

Is there a need to use partials? wouldnt it be easier to write a small script that would instead clone the first author enclosing element and just change the names of the elements involved to create a new author?

<div id="enclosingDiv" data-count="x">
  <div class="someClass"  data-index='x1' >
    Author1 name Aurthor1 Textboxname="CollectionList[Index].Property"...
  </div>

Now when creating a new Authouther, you can just create:

<script>
  function createNewAuthor()
  {
       //clone first author
       var count = $('encolsingDiv').attr('data-count');
      //var count = $('encolsingDiv').children().length;
      var author = $('enclosingDiv').first().clone();
      //change name and id,etc using data-count
      author.find('*[name$='value'])attr('name','ListCollection[count  + 1]");
      author.find('*[name$='value'])attr('id',....);
      author.attr('data-index',count +1)
      $('enclosingDiv').append(author);
      $('enclosingDiv').attr('data-count',count + 1 to it);//makes life easier

  }

  function deleteAuthor(authourIndex)
  {
        //assumes that an author can be removed
        $('div[data-index="'+authorIndex+'"]").remove();
        $('enclosingDiv').children.each(function()
       {
           //if delete functionality exists, change the names of the element                       indices using the count variable
           change all indices of element properties concerned
           $(this).find('*[name$='value']).attr('name','ListCollection['+count+'].sumproperty");

           count++;
       });
  }
</script>

So you can use that for create and delete methods, you don't need partials for that. The code might need some work as what I show is the concept

mahlatse
  • 1,322
  • 12
  • 24