Answered by:
Pass IEnumerable List of Specific Type To the Post Action

Question
-
User1185448985 posted
I have a question if any one can help me with tha answer
i'm working with asp.net mvc project
From my understanding the "SentencesList " in the ViewModel would be populated from the get action and passed to the view
then i used it to iterate through and display each record
is there any possible way to pass the "SentencesList" again to the post action if modified and with the new created sentences?
because i want the id's of the passed sentences to update the text if it is modified by the user and create new objects of type "Sentence"
Get Action
public async Task<IActionResult> Edit(int? id) { ........ var story = await _db.Story.FindAsync(id); ..... EditStoryViewModel modelVM = new EditStoryViewModel
{
Child = new Childs(),
Story = story,
ChildrenList = await _db.Childs.Where(c => c.ParentOf.InstitutionId == currentSpecialist.InstitutionId).ToListAsync(),
SentencesList = await _db.Sentence
.Where(s => s.Story.StoryId == story.StoryId)
.Include(s => s.Image)
.ToListAsync()
}; return View(modelVM); }Post Action
[HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Create(CreateStoryViewModel model){}
ViewModel
public class EditStoryViewModel { public IEnumerable<Childs> ChildrenList { get; set; }
public Childs Child { get; set; }
public Story Story { get; set; }
public Sentence Sentence { get; set; }
public IEnumerable<Sentence> SentencesList { get; set; } }cshtml
@model TestApplication.Models.ViewModels.EditStoryViewModel .................... <table id="table-2" class="table order-list datatable"> <thead> <tr> <td class="col-md-4"> <h4> sentence </h4> </td> <td class="col-md-2"> <h4> current image </h4> </td> <td class="col-md-2"> <h4> change image </h4> </td> <td class="col-md-2"> <h4> change audio </h4> </td> <td class="col-md-2"> <a class="deleteRow"></a> <h4> delete </h4> </td> </tr> </thead> <tbody> @foreach (var item in Model.SentencesList) { <tr> <td class="col-md-4"> <input type="text" class="form-control" name="sent" value="@Html.DisplayFor(s => item.SentenceText)" /> </td> <td class="text-center col-md-2"> <img src="@item.Image.ImageSelected" /> </td> <td class="col-md-2"><input type="file" class="form-control-file border" name="img"></td> <td class="col-md-2"><input type="file" class="form-control-file border" name="aud" disabled></td> <td class="col-md-2"><input type="button" class="ibtnDel btn btn-md btn-danger " value="delete"></td> </tr> } </tbody> <tfoot> <tr> <td colspan="5" style="text-align: left;"> <input type="button" class="btn btn-primary btn-lg btn-block " id="addrow" value="add row" /> </td> </tr> </tfoot> </table>
script
@section Scripts { <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script src="http://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/json2/20110223/json2.js"></script> <script type="text/javascript"> var counter = $('tbody tr').length; $(document).ready(function () { $("#addrow").on("click", function () { var newRow = $("<tr>"); var cols = ""; cols += '<td class="col-md-4"><input type="text" class="form-control" asp-for="Sentence.SentenceText" name="sent" /></td>'; cols += '<td class="col-md-2"></td>'; cols += '<td class="col-md-2"><input type="file" class="form-control-file border" name="img"></td>'; cols += '<td class="col-md-2"><input type="file" class="form-control-file border" name="aud" disabled></td>'; cols += '<td class="col-md-2"><input type="button" class="ibtnDel btn btn-md btn-danger" value="delete"></td><hr />'; newRow.append(cols); $('tbody').append(newRow); counter++; }); }); $("table.order-list").on("click", ".ibtnDel", function (event) { console.log("Delete"); $(this).closest("tr").remove(); counter -= 1 }); .................... </script> }
Thank you in advance
Sunday, August 16, 2020 10:47 PM
Answers
-
User711641945 posted
Hi Amani Ai,
Amani Al
is there any possible way to pass the "SentencesList" again to the post action if modified and with the new created sentences?It seems you want to pass the modified item which exsits in the model and new item to the controller.And did different operation for the two types of data.Did I understand correctly?
Here is a working demo like below:
Razor View:
@model EditStoryViewModel <h1>Edit</h1> <form method="post" id="myForm" enctype="multipart/form-data"> <div asp-validation-summary="ModelOnly" class="text-danger"></div> <div class="row"> <div> <div class="row"> <div class="col-md-12"> <table id="table-2" class="table order-list datatable"> <thead> <tr> <td class="col-md-4"> <h4> sentence </h4> </td> <td class="col-md-2"> <h4> current image </h4> </td> <td class="col-md-2"> <h4> change image </h4> </td> <td class="col-md-2"> <h4> change audio </h4> </td> <td class="col-md-2"> <a class="deleteRow"></a> <h4> delete </h4> </td> </tr> </thead> <tbody> @foreach (var item in Model.SentencesList) { <tr> <td class="col-md-4"> <input type="text" class="form-control" name="sent" value="@Html.DisplayFor(s => item.SentenceText)" /> </td> <td class="text-center col-md-2"> <img src="@item.Image.ImageSelected" /> </td> <td class="col-md-2"><input type="file" class="form-control-file border" name="img"></td> <td class="col-md-2"><input type="file" class="form-control-file border" name="aud" disabled></td> <td class="col-md-2"><input type="button" class="ibtnDel btn btn-md btn-danger " value="delete"></td> <td class="col-md-2"><input type="hidden" name="Id" value="@item.Id" /> </tr> } </tbody> <tfoot> <tr> <td colspan="5" style="text-align: left;"> <input type="button" class="btn btn-primary btn-lg btn-block " id="addrow" value="add row" /> </td> </tr> </tfoot> </table> </div> </div> </div> <hr /> <div class="col-md-12"> <div class="text-center"> <input type="submit" id="save" value="Save" class="btn btn-success btn-block btn-icon" /> <button type="button" class="btn btn-danger btn-block btn-icon">Cancel</button> <input type="file" class="form-control-file border" name="img1" multiple /> </div> </div> </div> </form>
Js:
@section Scripts { <script type="text/javascript"> var counter = $('tbody tr').length; $(document).ready(function () { $("#addrow").on("click", function () { var newRow = $("<tr>"); var cols = ""; cols += '<td class="col-md-4"><input type="text" class="form-control" asp-for="Sentence.SentenceText" name="sent" /></td>'; cols += '<td class="col-md-2"></td>'; cols += '<td class="col-md-2"><input type="file" class="form-control-file border" name="img"></td>'; cols += '<td class="col-md-2"><input type="file" class="form-control-file border" name="aud" disabled></td>'; cols += '<td class="col-md-2"><input type="button" class="ibtnDel btn btn-md btn-danger" value="delete"></td><hr />'; cols += '<td class="col-md-2"><input type="hidden" name="Id" value="null" />'; newRow.append(cols); $('tbody').append(newRow); counter++; }); }); $("table.order-list").on("click", ".ibtnDel", function (event) { console.log("Delete"); $(this).closest("tr").remove(); counter -= 1 }); $('#myForm').submit(function (e) { e.preventDefault(); var formData = new FormData($('#myForm')[0]); var value1 = formData.getAll("img"); $('input[name="Id"]').each(function (i, elem) { formData.append('SentencesList[' + i + '].Id', $(elem).val() ); }); $('input[name="sent"]').each(function (i, elem) { formData.append('SentencesList[' + i + '].SentenceText', $(elem).val() ); }); $('input[name="img"]').each(function (i, elem) { formData.append('SentencesList[' + i + '].Image.Name', value1[i].name ); }); $.ajax({ type: "POST", url: "/Stuff/PostEdit", async: true, data: formData, cache: false, processData: false, contentType: false, success: function (data) { console.log("Ok") }, error: function (data) { } }); }); </script> }
Controller:
[HttpPost] public IActionResult PostEdit(EditStoryViewModel model) { //Here you can judge whether your id is Edit or Creat //if id=null or 0,did create operation //if id has value,did edit operation return Json("Ok"); }
Best Regards,
Rena
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Monday, August 17, 2020 9:56 AM
All replies
-
User1120430333 posted
The post action would post back to an Edit action method for post with the Edit view doing a post. I believe that's what you are talking about.
You can look at the AuthorController as an example code out on Github, it uses an Edit() method with two signatures EditIid) is for showing the AuthorVM for edit. it calls the AuthorDM.Update(id) to get the Author record for edit. Edit(AuthorVM) is on the post back, and in turn, it calls AuthorDM.Update(AuthorVM). DM = domain model an object in the Models folder the Edit() actionmethods are calling. Also take note on some of the information in the links.
https://github.com/darnold924/PublishingCompany
https://deviq.com/kinds-of-models/
https://www.geeksforgeeks.org/c-sharp-method-overloading/
https://docs.microsoft.com/en-us/dotnet/architecture/modern-web-apps-azure/architectural-principles
https://www.c-sharpcorner.com/UploadFile/56fb14/understanding-separation-of-concern-and-Asp-Net-mvc/
<copied>
An MVC model contains all of your application logic that is not contained in a view or a controller. The model should contain all of your application business logic, validation logic, and database access logic.
A view should contain only logic related to generating the user interface. A controller should only contain the bare minimum of logic required to return the right view or redirect the user to another action (flow control). Everything else should be contained in the model.
In general, you should strive for fat models and skinny controllers. Your controller methods should contain only a few lines of code. If a controller action gets too fat, then you should consider moving the logic out to a new class in the Models folder.
<end>
Monday, August 17, 2020 12:58 AM -
User711641945 posted
Hi Amani Ai,
Amani Al
is there any possible way to pass the "SentencesList" again to the post action if modified and with the new created sentences?It seems you want to pass the modified item which exsits in the model and new item to the controller.And did different operation for the two types of data.Did I understand correctly?
Here is a working demo like below:
Razor View:
@model EditStoryViewModel <h1>Edit</h1> <form method="post" id="myForm" enctype="multipart/form-data"> <div asp-validation-summary="ModelOnly" class="text-danger"></div> <div class="row"> <div> <div class="row"> <div class="col-md-12"> <table id="table-2" class="table order-list datatable"> <thead> <tr> <td class="col-md-4"> <h4> sentence </h4> </td> <td class="col-md-2"> <h4> current image </h4> </td> <td class="col-md-2"> <h4> change image </h4> </td> <td class="col-md-2"> <h4> change audio </h4> </td> <td class="col-md-2"> <a class="deleteRow"></a> <h4> delete </h4> </td> </tr> </thead> <tbody> @foreach (var item in Model.SentencesList) { <tr> <td class="col-md-4"> <input type="text" class="form-control" name="sent" value="@Html.DisplayFor(s => item.SentenceText)" /> </td> <td class="text-center col-md-2"> <img src="@item.Image.ImageSelected" /> </td> <td class="col-md-2"><input type="file" class="form-control-file border" name="img"></td> <td class="col-md-2"><input type="file" class="form-control-file border" name="aud" disabled></td> <td class="col-md-2"><input type="button" class="ibtnDel btn btn-md btn-danger " value="delete"></td> <td class="col-md-2"><input type="hidden" name="Id" value="@item.Id" /> </tr> } </tbody> <tfoot> <tr> <td colspan="5" style="text-align: left;"> <input type="button" class="btn btn-primary btn-lg btn-block " id="addrow" value="add row" /> </td> </tr> </tfoot> </table> </div> </div> </div> <hr /> <div class="col-md-12"> <div class="text-center"> <input type="submit" id="save" value="Save" class="btn btn-success btn-block btn-icon" /> <button type="button" class="btn btn-danger btn-block btn-icon">Cancel</button> <input type="file" class="form-control-file border" name="img1" multiple /> </div> </div> </div> </form>
Js:
@section Scripts { <script type="text/javascript"> var counter = $('tbody tr').length; $(document).ready(function () { $("#addrow").on("click", function () { var newRow = $("<tr>"); var cols = ""; cols += '<td class="col-md-4"><input type="text" class="form-control" asp-for="Sentence.SentenceText" name="sent" /></td>'; cols += '<td class="col-md-2"></td>'; cols += '<td class="col-md-2"><input type="file" class="form-control-file border" name="img"></td>'; cols += '<td class="col-md-2"><input type="file" class="form-control-file border" name="aud" disabled></td>'; cols += '<td class="col-md-2"><input type="button" class="ibtnDel btn btn-md btn-danger" value="delete"></td><hr />'; cols += '<td class="col-md-2"><input type="hidden" name="Id" value="null" />'; newRow.append(cols); $('tbody').append(newRow); counter++; }); }); $("table.order-list").on("click", ".ibtnDel", function (event) { console.log("Delete"); $(this).closest("tr").remove(); counter -= 1 }); $('#myForm').submit(function (e) { e.preventDefault(); var formData = new FormData($('#myForm')[0]); var value1 = formData.getAll("img"); $('input[name="Id"]').each(function (i, elem) { formData.append('SentencesList[' + i + '].Id', $(elem).val() ); }); $('input[name="sent"]').each(function (i, elem) { formData.append('SentencesList[' + i + '].SentenceText', $(elem).val() ); }); $('input[name="img"]').each(function (i, elem) { formData.append('SentencesList[' + i + '].Image.Name', value1[i].name ); }); $.ajax({ type: "POST", url: "/Stuff/PostEdit", async: true, data: formData, cache: false, processData: false, contentType: false, success: function (data) { console.log("Ok") }, error: function (data) { } }); }); </script> }
Controller:
[HttpPost] public IActionResult PostEdit(EditStoryViewModel model) { //Here you can judge whether your id is Edit or Creat //if id=null or 0,did create operation //if id has value,did edit operation return Json("Ok"); }
Best Regards,
Rena
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Monday, August 17, 2020 9:56 AM -
User1185448985 posted
It seems you want to pass the modified item which exsits in the model and new item to the controller.And did different operation for the two types of data.Did I understand correctly?Yes exactly!!! It works perfectly i appreciate your help
But now i'm struggling with another issue in my Edit Action
I'm getting the uploaded files from the user and collect them by :
var files = HttpContext.Request.Form.Files;
and i'm getting a list of IFormFile sorted by its appearance to the user
is it possible to attach the updated sentences Id to this list of IFormFile
foreach(var i in model.SentencesList) { if(i.Id == 0) { //Create new Sentences & attach the corresponding file } else { //edit existing sentences && update the images if updated by user (How can i get the id's of the sentences where the image was updated?) } }
If i have to change the way i'm getting the files i would but i don't know how
Thank you in advance
Tuesday, August 18, 2020 11:49 PM -
User711641945 posted
Hi Amani AI
According to my previous post(you could see the gif result), the id of the sentence can be obtained directly if it exists in database.
Here is my whole model:
Model:
public class Sentence { public int Id { get; set; } public string SentenceText { get; set; } public Image Image { get; set; } public int EditStoryViewModelId { get; set; } public EditStoryViewModel EditStoryViewModel { get; set; } } public class Image { public int Id { get; set; } public string Name { get; set; } public string ImageSelected { get; set; } }
Another way is to get the file name which in request.form and judge if the file name contains in the database then you could get the id:
var files = HttpContext.Request.Form.Files; foreach(var item in files) { var a = item.FileName; //Here you can judge whether your filename exists in the database }
Best Regards,
Rena
Wednesday, August 19, 2020 4:08 AM -
User1185448985 posted
the trick is that i rename the file with the sentence id before saving it, to ensure no name duplication :(
Wednesday, August 19, 2020 1:05 PM