asp.net-mvcasp.net-core.net-core

How to create object that contains a list of object in a single form?


public class Basket
{
    public int Id { get; set; }
    public string Sharp { get; set; }
    public string Material { get; set; }
    public List<Fruit> Fruits { get; set; }
}


public class Fruit
{
    public int Id { get; set; }
    public string Color { get; set; }
    public string Taste { get; set; }
}

With the above example, how could I create both Basket and Fruit in the same asp-form without using any JavaScript?

<form method="post" asp-controller="Basket" asp-action="Create">
    <input asp-for="Material" />
    <input asp-for="Sharp" />

    @*I would like to also create custom amounts of new Fruit in this form.*@

    <input type="submit" value="Submit" />
</form>

If my razor form is defined as the above example, how could I create custom amounts of Fruit and create Basket at the same form? It is possible to avoid using JavaScript in this case?


Solution

  • It is possible to avoid using JavaScript in this case?

    Based on your scenario and current architecture what you need to do is, there should be a table where you would be adding your fruit object as it's a List<Fruit> Fruit kind of. As per your given code, your output should be as below:

    enter image description here

    So, I would say Javascript would make it easier. If you would like to avoid Javascript, it wouldn't be impossible but would be costly and complex.

    how could I create custom amounts of Fruit and create Basket at the same form?

    You could follow the steps shown here to achieve what you are trying to implement.

    View:

    @model DotNet6MVCWebApp.Models.Basket
    
    <form method="post" asp-controller="Yonny" asp-action="Create">
        <div class="form-group">
            <label asp-for="Material" class="col-md-2 form-label"></label>
            <input asp-for="Material" class="col-md-6 form-control" />
            <span asp-validation-for="Material" class="form-span-error"></span>
        </div>
    
        <div class="form-group" style="padding-bottom:20px">
            <label asp-for="Sharp" class="col-md-2 form-label"></label>
            <input asp-for="Sharp" class="col-md-6 form-control" />
            <span asp-validation-for="Sharp" class="form-span-error"></span>
        </div>
        @*I would like to also create custom amounts of new Fruit in this form.*@
        <div style="padding-bottom:20px">
             <button type="button" class="btn btn-primary" onclick="AddRow()">Add Fruit</button>
        </div>
       
        <div id="dataTable">
            <table>
                <thead>
                    <tr>
                        <th>Id</th>
                        <th>Color</th>
                        <th>Taste</th>
                    </tr>
                </thead>
                <tbody id="FruitList" data-count="0">
                  
                </tbody>
            </table>
        </div>
        <input type="submit" class="btn btn-success" value="Submit" />
    </form>
    
    @section Scripts {
    <script>
        /*
             . Hidding table on load
        */
          document.getElementById('dataTable').style.display ='none';
    
          function AddRow()
          {
              var countVal = parseInt($('#FruitList').attr('data-count'));
              var html = '';
              html += '<tr>';
              html += '<td><input type="text" name="Fruits[' + countVal + '].Id" class="form-control"/></td>';
              html += '<td><input type="text" name="Fruits[' + countVal + '].Color" class="form-control"/></td>';
               html += '<td><input type="text" name="Fruits[' + countVal + '].Taste" class="form-control"/></td>';
              html += '</tr>';
    
              $('#FruitList').append(html);
              countVal += 1;
              $('#FruitList').attr('data-count', countVal);
          /*
             . Showing table when adding item into 
          */
               document.getElementById('dataTable').style.display ='block';
           
          }
    </script>
    }
    

    Controller:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create(
        [Bind("Id,Material,Sharp,Fruits")] DotNet6MVCWebApp.Models.Basket basket)
    {
        if (ModelState.IsValid)
        {
            // Save Basket
            _context.Add(basket);
            await _context.SaveChangesAsync();
    
            // Add Fruits List
            foreach (var item in basket.Fruits)
            {
                _context.Add(item);
                await _context.SaveChangesAsync();
            }
    
            return RedirectToAction(nameof(Create));
        }
    
        return View(basket);
    }
    

    Note: if you somehow got null data while sending request to controller, make sure your binding property that is Bind("Id,Material,Sharp,Fruits") are same as name="Fruits[' + countVal + '].Id" inside the Javascript function.

    Output

    enter image description here