jqueryajaxasp.net-coreasp.net-ajax

how to Upload the file during for loop


I have a list in which I upload a file for each record with Ajax, but because I am in a loop and I used ID for input, only the first record file is uploaded and the rest of the records are not uploaded.Please check the code

public class TaxParvande
{
    public int id { get; set; }

    public int projectId { get; set; }

    public String projectName { get; set; }

    public int listId { get; set; }

    public int year { get; set; }
    public bool state { get; set; }
    [NotMapped]
    public IFormFile? prosessMastand { get; set; }
    public int prosessId { get; set; }

    public String prosessName { get; set; }
    public String FilePath { get; set; }
  
    public String NaoaParvane { get; set; }
}
    <form asp-controller="Tax" asp-action="SabtEditTaxParvanedAsync" method="post" enctype="multipart/form-data">


        <div class="container-fluid" style="overflow: auto; overflow-x: hidden; direction:ltr ">

            <table class="table table-bordered table-striped table-hover  display" width="100%" style="direction:rtl;font-size:12px">
                <thead>

                    <tr class="table-head-blue text-center" style="background-color: #416992; color: white; position: sticky; top: 0;">

                        <th style="width:150px">وضعیت</th>
                        <th>پروسه پرونده</th>
                        <th>مستندات</th>
                        <th>تاریخ</th>

                    </tr>

                </thead>
                @{ var count = 0;}

                @for (var i = 0; i < Model.Count(); i++)

                {
            <tr>
                <td style="width:150px">

                    <label class="switch">
                        <input type="checkbox" onchange="DisableRow(this)" asp-for="@Model.ToList()[i].state" value="True">
                        <span class="slider round"></span>
                    </label>
                </td>

                <td style="font-size: 12px">
                    <span>@Model.ToList()[i].prosessName</span>
                    <input class="d-none" value="@Model.ToList()[i].prosessName" name="[@i].prosessName" />

                </td>

                <td>
                    <div class="d-flex justify-content-around">
                        <div>

                            <span class="text-center mt-2" id="spnImageCartMlie" style="color: black;font-size: 12px"></span>

                        </div>
                        <div>
                            <input type="button" required onclick="UploadImage()" value="Upload" class="btn btn-outline-danger " id="btnUpLoad" />

                            <div id="divmessage" class="text-center hidden m-2"></div>


                        </div>

                        <input id="mostanadPath" name="[@i].prosessMastand" type="file" class="">
                    </div>

                </td>
                <td style="font-size: 12px" hidden>
                    <span>@Model.ToList()[i].prosessId</span>
                    <input class="d-none" value="@Model.ToList()[i].prosessId" name="[@i].prosessId" />
                </td>

                <td>
                </td>


            </tr>
                    count++;
                }



            </table>
        </div>


        <div class=" text-center">
            <button class="btn btn-success  col-4 mb-2 " type="submit">ثبت اطلاعات</button>
        </div>

    </form>
//--------------------------------------------------------------------------

  [HttpPost]
    public async Task<IActionResult> SabtEditTaxParvanedAsync([FromForm]IEnumerable<TaxParvande> taxParvandes)
    {
        if (taxParvandes == null)
        {
            return Content("File not selected");
        }
        foreach (var item in taxParvandes)
        {
            var path = Path.Combine(_webHostEnvironment.WebRootPath, "ListUpload", item.prosessMastand.FileName);
            using (FileStream stream = new FileStream(path, FileMode.Create))
            {
                await item.prosessMastand.CopyToAsync(stream);
                stream.Close();
            }

           
            var taxparvand = new TaxParvande
            {
                prosessId =item.prosessId,
                prosessName = item.prosessName,
                state = item.state,                    
                FilePath = path,
            };
            _context.Add(taxparvand);
            await _context.SaveChangesAsync();
        }
     

        return View();
    }

enter image description here


Solution

  • Update:

    Based on your comment, here is the complete view along with additional explanations:

    @model IEnumerable< DotNet6MVCWebApp.Models.TaxParvande>
    <form asp-controller="YourContorllerName" asp-action="SabtEditTaxParvanedAsync" method="post" enctype="multipart/form-data">
        <div class="container-fluid" style="overflow: auto; overflow-x: hidden; direction:ltr ">
    
            <table class="table table-bordered table-striped table-hover  display" width="100%" style="direction:rtl;font-size:12px">
                <thead>
    
                    <tr class="table-head-blue text-center" style="background-color: #416992; color: white; position: sticky; top: 0;">
    
                        <th style="width:150px">وضعيت</th>
                        <th>پروسه پرونده</th>
                        <th>مستندات</th>
                        <th>تاريخ</th>
    
                    </tr>
    
                </thead>
                @{
                    var count = 0;
                }
    
                @for (var i = 0; i < Model.Count(); i++)
    
                {
                    <tr>
                        <td style="font-size: 12px" hidden>
                            <span>@Model.ToList()[i].prosessId</span>
                            <input class="d-none" value="@Model.ToList()[i].prosessId" name="[@i].prosessId" />
    
                        </td>
                        <td style="width:150px">
    
                            <label class="switch">
                                <input type="checkbox" onchange="DisableRow(this)" asp-for="@Model.ToList()[i].state" value="True">
                                <span class="slider round"></span>
                            </label>
                        </td>
    
                        <td style="font-size: 12px">
                            <span>@Model.ToList()[i].prosessName</span>
                            <input class="d-none" value="@Model.ToList()[i].prosessName" name="[@i].prosessName" />
    
                        </td>
    
                        <td>
                            <div class="d-flex justify-content-around">
                                <div>
    
                                    <span class="text-center mt-2" id="spnImageCartMlie" style="color: black;font-size: 12px"></span>
    
                                </div>
                                <div>
                                    <input type="button" required onclick="UploadImage()" value="Upload" class="btn btn-outline-danger " id="btnUpLoad" />
    
                                    <div id="divmessage" class="text-center hidden m-2"></div>
    
    
                                </div>
    
                                <input id="mostanadPath" name="[@i].prosessMastand" type="file" class="">
                            </div>
    
                        </td>
    
    
                        <td>
                        </td>
    
    
                    </tr>
                    count++;
                }
    
            </table>
        </div>
    
        <div class=" text-center">
            <button class="btn btn-success  col-4 mb-2 " type="submit"> Submit ثبت اطلاعات</button>
        </div>
    
    </form>
    

    IWebHostEnvironment:

    Regarding the error on _environment you could replace to your constructor name this error is obvious as our constructor name was different. As I kept the name as below:

     private readonly IWebHostEnvironment _environment;
    

    You can set anything convenient for you.

    Controller Name:

    Even if you set controller action as SabtEditTaxParvaned it will works because it will check if there os any POST method within the controller. It will not works if there are many POST action. However, you can replace it to SabtEditTaxParvanedAsync

    Previous Answer:

    I have a list in which I upload a file for each record with Ajax, but because I am in a loop and I used ID for input, only the first record file is uploaded and the rest of the records are not uploaded

    Based on your shared code it appeared that, you have two scenario

    1. Single Upload When Click on Upload Button
    2. All Upload Together When Click on Submit Button

    As I have checked Single Upload which seems working as expected. However, for List Upload or All Upload you should required few modification in your code. Please follow the steps below:

    Model For List Upload:

    public class TaxParvande
        {
            public IFormFile? prosessMastand { get; set; }
            public int prosessId { get; set; }  
            public bool state { get; set; }  
            public string prosessName { get; set; }
        }
    

    Note: As you said "In a loop and I used ID for input" Therefore, I have added prosessId which we will use in View later on.

    Controller:

        [HttpPost]
        public async Task<IActionResult> SabtEditTaxParvanedAsync([FromForm]IEnumerable<TaxParvande> taxParvandes)
        {
            if (taxParvandes == null)
            {
                return Content("File not selected");
            }
            foreach (var item in taxParvandes)
            {
                var path = Path.Combine(_environment.WebRootPath, "ListUpload", item.prosessMastand.FileName);
                using (FileStream stream = new FileStream(path, FileMode.Create))
                {
                    await item.prosessMastand.CopyToAsync(stream);
                    stream.Close();
                }
    
               
                var taxDomainModel = new TaxDomainModel
                {
                    prosessId =item.prosessId,
                    prosessName = item.prosessName,
                    state = item.state,                    
                    FilePath = path,
                };
                _context.Add(taxDomainModel);
                await _context.SaveChangesAsync();
            }
         
    
            return View();
        }
    

    Note: As you are submitting FormData thus we should redefine the controller as [FromForm] and the List of IEnumerable<TaxParvande>. As it is list therefore, we are looping through the items and saving image in folder finally getting the path location so that we can save in database.

    View:

    In View we will modify two things.

    Firstly, for Multiple FromData we should use this attribute enctype="multipart/form-data" to submit bulk file at once. Final change would as below

    <form asp-controller="LoopUpload" asp-action="SabtEditTaxParvaned" method="post" enctype="multipart/form-data">
    

    Secondly, Use additional one td for prosessId and set the attribute as hidden just as below:

      <td style="font-size: 12px" hidden>
           <span>@Model.ToList()[i].prosessId</span>
           <input class="d-none" value="@Model.ToList()[i].prosessId" name="[@i].prosessId" />
      </td>
    

    Note: You are all done to to upload a list together now. You can see the output below.

    Output:

    enter image description here