1

Good day

I really need your help as I am currently stuck, need your opinions on how to solve this problem, please kindly look at my code .

Views:

@using (Html.BeginForm("Test", "Student", FormMethod.Post))
{
    for (int i = 0; i < Model.Count(); i++)
     {
         @Html.TextBoxFor(model => Model[i].Name)
          <input class="btn btn-default" type="submit" value="submit all student names"/>

         <form action="/Student/Upload/@Model[i].Id" method="post" enctype="multipart/form-data">
             <input class="btn btn-default" type="file" name="photofile" value="photofile" style="width: 100%;"/>
             <input class="btn btn-default" value="submit files" type="submit"/>
         </form>
     }
}

Controller:

 public async Task<IActionResult> Upload(int id, IFormFile photofile)

 [HttpPost, Route("Student/Upload/{id:int=0}")]
 public IActionResult Test(List<Student> students)

So basically what I am trying to do is that when the form is being loaded, there will be student names and a button to submit all names, so when the user modify any changes in the textbox and click submit, the entire collections will be passed into the Test as List students and modified accordingly, it works perfectly fine until I have to introduce the Upload into it as well.

So now I have upload and once the form is loaded, names of student textbox and an submit buttons and also numbers of input based on the number of students as well as input button to submit the file, I need to submit one file at a time only and only one is affected, the upload is working successfully too EXCEPT now when I modify the student names and submit, only the first Index is working, the rest the List students only accept first index modification, the rest it will always show List = 0, I believe it is due to the problem of form being replicated, invalid html, but is there any way to override this to make it works?

I need the upload form to be inside because I need the method"post" enctype="" and also I need the input to be aside/above the student name textbox.

Thanks a lot

Sahil Aggarwal
  • 1,311
  • 1
  • 12
  • 29
Sarah
  • 329
  • 5
  • 21
  • Nested forms are invalid html and are not supported (and there is no guarantee how it will behave across different browsers and versions of browsers) –  Jan 31 '18 at 04:46
  • What makes you think you need nested forms for this? –  Jan 31 '18 at 04:48
  • @StephenMuecke So should I just remove entirely the Upload files there and put it somewhere? – Sarah Jan 31 '18 at 04:48
  • @StephenMuecke I am newbie, need some advice – Sarah Jan 31 '18 at 04:49
  • @StephenMuecke and I really want it to be on the same page along with the student names – Sarah Jan 31 '18 at 04:49
  • I'm not understanding what your wanting to do and why you think you need to upload one file at a time. Why not a file input associated with each student, and then upload all the changes in one action –  Jan 31 '18 at 04:50
  • @StephenMuecke So you are saying combining the Test and Upload files at the same time is it? I thought about doing that but then the Test function, the IFormFile will always be null – Sarah Jan 31 '18 at 04:52
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/164223/discussion-between-stephen-muecke-and-krayon2). –  Jan 31 '18 at 04:53
  • Its not possible to have form inside i dont know . i think i am not getting what u want to have – Pravin Poudel Jan 31 '18 at 04:54

1 Answers1

1

Nested forms are invalid html and not supported and there is no guarantee what the behavior will be across different browsers or even across different versions of the same browser.

If you want to upload just one file at a time, then you could use ajax (with Formdata) to submit the just the file and the associated ID for the student (refer this answer for an example), however since you posting all the other properties of each Student then you can also post a file associated with each student in one action.

Create a view model to bind your view to

public class StudentVM
{
    public int ID { get; set; }
    public string Name { get; set; }
    ....
    public IFormFile { get; set; }
    public string FileName { get; set; }
    public string FilePath { get; set; }
}

and pass a List<StudentVM> to the view in the GET method

Your view will then be

@model List<StudentVM>
@using (Html.BeginForm("Test", "Student", FormMethod.Post, new { enctype="multipart/form-data" }))
{
    for (int i = 0; i < Model.Count; i++)
    {
        @Html.TextBoxFor(m => m[i].Name)
        ....
        @Html.TextBoxFor(m => m[i].File, new { type = "file" })
        ....
    }
    <input type="submit" ... />
}

which will then post back to

[HttpPost] 
public IActionResult Test(List<StudentVM> model)

and the collection will be correctly bound.