locked
Post table data with fixed length in ASP Core MVC RRS feed

  • Question

  • User-1741097413 posted

    I have a create parent action, in the view there is a table, and every row is of type Child. The number of rows is fixed, but user might save the table without filling all the data, it requires days to fill every row. Let me show the view models first before explaining any further.

    public class CreateEditParentViewModel
    {
        public int Id { get; set; }
        public IList<ChildViewModel> ChildrenList { get; set; }
    }
    
    public class ChildViewModel
    {
        public int Id { get; set; }
        public string Day { get; set; }
        public DateTime Date { get; set; }
        //public DateTime Time { get; set; }
        //other properties
    }

    as you can see, every row will have fields for date and time and since I'll be having so many rows I decided to use partial view for the row. Will be something like this:

    @model TestApplication.Models.ViewModels.ChildViewModel
    <td>
    <input type="hidden" asp-for="Id" />
    </td>
    <td>
        <input asp-for="Date" class="form-control" name="dob" />
        <span asp-validation-for="Date" class="text-danger"></span>
    </td>
    <td>
        time
    </td>

    The create view:

     @model TestApplication.Models.ViewModels.CreateEditParentViewModel
     <form method="post" asp-action="create">
        <table>
            <thead>
                <tr>
                    <th>Day</th>
                    <th>Date</th>
                    <th>Time</th>
                </tr>
            </thead>
            <tbody>
                @for (int i = 0; i < Model.ChildrenList.Count; i++)
                {
                    <partial name="_ChildPartial" for="@Model.ChildrenList[i]" />
                }
            </tbody>
        </table>
     </form>

    The get action:

           [HttpGet]
            public async Task<IActionResult> Create( int? id) 
            {
                var childrenFixed = new[] { //craeted a fixed list
                        new Child { DayNumber = 1 },
                        new Child { DayNumber = 2 },
                        new Child { DayNumber = 3 },
                };
                List<ChildSessionViewModel> childListVM = new List<ChildViewModel>();
                foreach (Child item in childrenFixed) //saved in ChildViewModel object
                {
                    var childVM= new childViewModel
                    {
                        Day = item.DayNumber,
                    };
                    childListVM.Add(childVM);
                }
                CreateEditParentViewModel modelVM = new CreateEditParentViewModel()
                {
                    ChildrenlistList = childListVM, //populated the view with empty fixed rows
                };
                return View(modelVM);
            }

    My first concern is am I doing it the right way? Is this how I should deal with table data? The other thing, how to avoid nulls in this case? the user should fill all the cells eventually, but of course there will be so many tables with so many nulls forever. Can I not create child object (row) until its used?

    Sunday, August 30, 2020 11:19 AM

Answers

  • User-17257777 posted

    Hi rosaud,

    My first concern is am I doing it the right way? Is this how I should deal with table data?

    I think it is OK.

    how to avoid nulls in this case? the user should fill all the cells eventually

    You can use [Required] Attribute to force user to fill all the data like below:

    Model:

    public class CreateEditParentViewModel
    {
        public int Id { get; set; }
        public IList<ChildViewModel> ChildrenList { get; set; }
    }
    
    public class ChildViewModel
    {
        public int Id { get; set; }
        public string Day { get; set; }
        [Required]
        public string Date { get; set; }
        
    }

    Note that the Date should be string type.

    The create view:

    @model WebApplication3.ViewModels.CreateEditParentViewModel
    <form method="post" asp-action="create">
        <table>
            <thead>
                <tr>
                    <th>Day</th>
                    <th>Date</th>
                </tr>
            </thead>
            <tbody>
                @for (int i = 0; i < Model.ChildrenList.Count; i++)
                {
                    <partial name="_ChildPartial" for="@Model.ChildrenList[i]" />
                }
            </tbody>
            </table>
        <input type="submit" value="submit" class="btn btn-danger" />
    </form>

    Partial view:

    @model WebApplication3.ViewModels.ChildViewModel
    <tr>
        <td>
            <input type="hidden" asp-for="Id" />
        </td>
        <td>
            <input asp-for="Date" class="form-control" type="date" />
            <span asp-validation-for="Date" class="text-danger"></span>
        </td>
    </tr>

    Controller:

    [HttpGet]
    public IActionResult Create(int? id)
    {
        var childrenFixed = new[] { //craeted a fixed list
                new Child { DayNumber = "1" },
                new Child { DayNumber = "2" },
                new Child { DayNumber = "3" },
        };
        List<ChildViewModel> childListVM = new List<ChildViewModel>();
        foreach (Child item in childrenFixed) //saved in ChildViewModel object
        {
            var childVM = new ChildViewModel
            {
                Day = item.DayNumber,
            };
            childListVM.Add(childVM);
        }
        CreateEditParentViewModel modelVM = new CreateEditParentViewModel()
        {
            ChildrenList = childListVM, //populated the view with empty fixed rows
        };
        return View(modelVM);
    }
    
    [HttpPost]
    public IActionResult Create(CreateEditParentViewModel createEditParentViewModel)
    {
        if (ModelState.IsValid)
        {
            //some logic
        }
        return View(createEditParentViewModel);
    }

    If user didn't fill the date, ModelState.IsVaild will be false.

    Result:

    Best Regards,

    Jiadong Meng

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, August 31, 2020 7:26 AM

All replies

  • User-17257777 posted

    Hi rosaud,

    My first concern is am I doing it the right way? Is this how I should deal with table data?

    I think it is OK.

    how to avoid nulls in this case? the user should fill all the cells eventually

    You can use [Required] Attribute to force user to fill all the data like below:

    Model:

    public class CreateEditParentViewModel
    {
        public int Id { get; set; }
        public IList<ChildViewModel> ChildrenList { get; set; }
    }
    
    public class ChildViewModel
    {
        public int Id { get; set; }
        public string Day { get; set; }
        [Required]
        public string Date { get; set; }
        
    }

    Note that the Date should be string type.

    The create view:

    @model WebApplication3.ViewModels.CreateEditParentViewModel
    <form method="post" asp-action="create">
        <table>
            <thead>
                <tr>
                    <th>Day</th>
                    <th>Date</th>
                </tr>
            </thead>
            <tbody>
                @for (int i = 0; i < Model.ChildrenList.Count; i++)
                {
                    <partial name="_ChildPartial" for="@Model.ChildrenList[i]" />
                }
            </tbody>
            </table>
        <input type="submit" value="submit" class="btn btn-danger" />
    </form>

    Partial view:

    @model WebApplication3.ViewModels.ChildViewModel
    <tr>
        <td>
            <input type="hidden" asp-for="Id" />
        </td>
        <td>
            <input asp-for="Date" class="form-control" type="date" />
            <span asp-validation-for="Date" class="text-danger"></span>
        </td>
    </tr>

    Controller:

    [HttpGet]
    public IActionResult Create(int? id)
    {
        var childrenFixed = new[] { //craeted a fixed list
                new Child { DayNumber = "1" },
                new Child { DayNumber = "2" },
                new Child { DayNumber = "3" },
        };
        List<ChildViewModel> childListVM = new List<ChildViewModel>();
        foreach (Child item in childrenFixed) //saved in ChildViewModel object
        {
            var childVM = new ChildViewModel
            {
                Day = item.DayNumber,
            };
            childListVM.Add(childVM);
        }
        CreateEditParentViewModel modelVM = new CreateEditParentViewModel()
        {
            ChildrenList = childListVM, //populated the view with empty fixed rows
        };
        return View(modelVM);
    }
    
    [HttpPost]
    public IActionResult Create(CreateEditParentViewModel createEditParentViewModel)
    {
        if (ModelState.IsValid)
        {
            //some logic
        }
        return View(createEditParentViewModel);
    }

    If user didn't fill the date, ModelState.IsVaild will be false.

    Result:

    Best Regards,

    Jiadong Meng

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Monday, August 31, 2020 7:26 AM
  • User-1741097413 posted

    Thank you so much for the reply!
    For the required validation,  actually its up to the user to fill the cells in the creation time or later.
    The user has two option either saves it as draft (uncompleted) or publish it (all cells should be filled).

    May I ask why the Date should be string? I already modified it, I just want to learn why to avoid using DateTime in other situations. 

    Regards.

    Monday, August 31, 2020 11:07 AM
  • User-17257777 posted

    Hi rosaud,

    May I ask why the Date should be string?

    DateTime has the default value 01/01/0001 00:00:00, so, if we didn't fill the date, it will still pass the model validation.

    Best Regards,

    Jiadong Meng

    Tuesday, September 1, 2020 5:07 AM
  • User-1741097413 posted

    Oh I see! Thank you very much!

    Tuesday, September 1, 2020 9:03 AM