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();
}
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
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: