C# ASP.NET MVC - How to retrieve all values from a from that can have unknown input field count

ChrisU 231 Reputation points
2023-06-09T07:49:58.66+00:00

I have a simple form, that allows the user to edit a drop down list that exists within another form. In this the user can view the current drop down list values, edit them, delete them or create more.

User's image

This opens this form in a modal:

User's image

Here you can edit existing values, delete them or add new:

enter image description here

So it can end up having any number of values!

The CSHTML for this:

@using (Html.BeginForm("EditDropDown", "Incidents", FormMethod.Post, new { onsubmit = "validateCustomTolerances()", id = "modal-form" }))
{
  @foreach (var opt in Model.IncRptOptions)
  {
    @if (opt.Type == "Action")
      {
        <div class="IncRpt-opt-modalDisp">
          <input type="text" id="" name="" value="@opt.TypeValue">
          <a class="edit-dropdown delete-existing"><i class="bi bi-trash3-fill"></i></a>
        </div>
      }
   }
   <div id="additional-options-here"></div>
   <a class="btn btn-sm btn-secondary" id="add-option">Add Option</a>
   <br>
   @*------ Hidden form content (required by controller action) ------*@
   <input id="optionType" type="hidden" name="optionType" value="Action" />

   @*------ Form buttons ------*@
   <div class="modal-form-btns">
     <button type="submit" class="btn btn-sm btn-primary modal-save-btn">Save</button>
     <button type="button" class="btn btn-sm btn-secondary">Cancel</button>
   </div>
}

The JS for this:

// Deletes the existing option next to the 'bin' button user clicks it. 
    document.querySelectorAll('.delete-existing').forEach(item => {
        item.addEventListener('click', event => {
            let existingParent = item.parentElement;
            existingParent.remove();
        });
    });

    // Event listeners for the 'add option' button
    let addOption = document.querySelector('#add-option');

    // Creates the form input element for an additional option when button clicked
    addOption.addEventListener('click', function () {
        let parent = document.querySelector('#additional-options-here');
        let html = `
                <input type="text" id="test" name="" value="">
                <a class="edit-dropdown delete-added"><i class="bi bi-trash3-fill"></i></a>
                `;
        let template = document.createElement('div');
        template.setAttribute('class', 'IncRpt-opt-modalDisp')
        template.innerHTML = html;
        let finalHTML = template;
        finalHTML.querySelector('.delete-added').addEventListener('click', deleteAddedElement);
        parent.appendChild(finalHTML);
    });

    // Deletes the added option elements when user clicks on the 'bin' icons
    function deleteAddedElement() {
        let parent = this.parentElement;
        parent.remove();
    }

As a result, I will not know how many values will be returned.

Using Flask I used request.form.getList("Input-name-value"). What is the ASP.NET equivalent way of doing this in the Controller method?

.NET
.NET
Microsoft Technologies based on the .NET software framework.
3,372 questions
ASP.NET
ASP.NET
A set of technologies in the .NET Framework for building web applications and XML web services.
3,254 questions
0 comments No comments
{count} votes

3 answers

Sort by: Most helpful
  1. AgaveJoe 26,201 Reputation points
    2023-06-09T10:48:27.46+00:00

    What is the ASP.NET equivalent way of doing this in the Controller method?

    I recommend taking advantage of MVC model binding.

    https://learn.microsoft.com/en-us/archive/msdn-magazine/2012/february/asp-net-mvc-the-features-and-foibles-of-asp-net-mvc-model-binding

    https://learn.microsoft.com/en-us/aspnet/core/mvc/models/model-binding?view=aspnetcore-7.0

    The controller action simply defines a C# type that matches the post parameters. In the example below the markup has three inputs named Options.

    <h2>Index</h2>
    <form method="post">
        <input type="hidden" name="Options" value="Closed Door" />
        <input type="hidden" name="Options" value="Power Restored" />
        <input type="hidden" name="Options" value="Support Call Raised" />
        <input type="submit" value="submit" />
    </form>
    

    The browser sends a list of options in the HTTP body

    Options=Closed+Door&Options=Power+Restored&Options=Support+Call+Raised
    

    The controller action just needs a parameter name that matches the input name which is "Options" and the type is an array or a collection.

            // GET: ModelBindingEx
            [HttpGet]
            public ActionResult Index()
            {
                return View();
            }
            [HttpPost]
            public ActionResult Index(List<string> Options)
            {
                return Json(Options);
            }
    

    You could also have a complex type where the post payload is an array and anther value. In this case you wrap the properties in a class.

    <form method="post">
        <input type="hidden" name="Id" value="1" />
        <input type="hidden" name="Options" value="Closed Door" />
        <input type="hidden" name="Options" value="Power Restored" />
        <input type="hidden" name="Options" value="Support Call Raised" />
        <input type="submit" value="submit" />
    </form>
    
            public class MyViewModel
            {
                public int Id { get; set; }
                public List<string> Options { get; set; }
            }
    
            [HttpGet]
            public ActionResult Index()
            {
                return View();
            }
            [HttpPost]
            public ActionResult Index(MyViewModel model)
            {
                return Json(model);
            }
    

    Lastly, you can also access the parameters using the Request collection.

            [HttpPost]
            public ActionResult Index(MyViewModel model)
            {
                string[] items = ((string)Request["Options"]).Split(',');
                return Json(items);
            }
    
    0 comments No comments

  2. QiYou-MSFT 4,306 Reputation points Microsoft Vendor
    2023-06-12T08:12:14.7566667+00:00

    Hi @ChrisU

    We usually use the Dropdownlist control in HtmlHelper to implement in ASP.NET MVC. For example:

    Code:

     public List<Person> Create()
            {
                List<Person> list = new List<Person>();
                Person p1 = new Person() { id = 1, name = "Name1" };
                Person p2 = new Person() { id = 2, name = "Name2" };
                Person p3 = new Person() { id = 3, name = "Name3" };
                Person p4 = new Person() { id = 4, name = "Name4" };
                list.Add(p1);
                list.Add(p2);
                list.Add(p3);
                list.Add(p4);
                return list;
            }
            // GET: Test
            public ActionResult Index()
            {
                List<Person> list = Create();
                SelectList selList = new SelectList(list, "Id", "Name", 1);
                ViewBag.aaa = selList;
                return View();
            }
    
    
    
    <div>
        @Html.DropDownList("pid", (SelectList)ViewBag.aaa)
        
    </div>
    

    Output:

    DropDownListTest1

    But this is not conducive to the storage of data, so we can store the data in the database.

    We can use the Sqlcommand method to convert the read data from the dataset to the list, and finally use the above method to form a DropDownList.

    public IList<T> GetList<T>(string connStr, string SqlStr)
            {
                using (SqlConnection conn = new SqlConnection(connStr))
                {
                   
                    using (SqlDataAdapter SDA = new SqlDataAdapter(SqlStr, conn))
                    {
                        DataSet ds = new DataSet();
                        SDA.Fill(ds);
                        return DataSetConvertToList<T>(ds, 0);
                    }
                }
            }
            public IList<T> DataSetConvertToList<T>(DataSet dataSet, int tableIndex)
            {
                //Verify that the parameter is valid
                if (dataSet == null || dataSet.Tables.Count <= 0 || tableIndex < 0)
                    return null;
    
                DataTable dt = dataSet.Tables[tableIndex];
    
                IList<T> list = new List<T>();
    
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    //Create a generic object
                    T _t = Activator.CreateInstance<T>();
                    //Gets all properties of the object
                    PropertyInfo[] propertyInfo = _t.GetType().GetProperties();
                    for (int j = 0; j < dt.Columns.Count; j++)
                    {
                        foreach (PropertyInfo info in propertyInfo)
                        {
                            //Assign a value when the attribute name and column name are the same
                            if (dt.Columns[j].ColumnName.ToUpper().Equals(info.Name.ToUpper()))
                            {
                                if (dt.Rows[i][j] != DBNull.Value)
                                {
                                    info.SetValue(_t, dt.Rows[i][j], null);
                                }
                                else
                                {
                                    info.SetValue(_t, null, null);
                                }
                                break;
                            }
                        }
                    }
                    list.Add(_t);
                }
                return list;
            }
    
    
    

    Next, we can modify the data of the database through the operation of adding, deleting, modifying, and checking the data in the database, so that the Item under the DropDownList can modify or add and delete operations.

    Read the data from the database and display it in the GridView, and then perform the corresponding operation.

    Best Regards

    Qi You


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments

  3. ChrisU 231 Reputation points
    2023-06-12T09:02:01.5433333+00:00

    Thanks for your responses. I only really wanted to get the values to update the database and did not want to add another model or update an existing.

    I found that I could use the IFormCollection Interface and then use the the TryGetValue Method as in the below code. Thanks for your help.

    [HttpPost]
    public ActionResult EditDropDownList(IFormCollection collection, int ID)
    {
       if ((collection.TryGetValue("optionType", out StringValues LogTypes)) &&     (collection.TryGetValue("optionValue", out StringValues TypeValues)))
          {
             string logTypeText = string.Empty;
             string typeValueText = string.Empty;
             for (int i = 1; i <= TypeValues.Count; i++)
                {
                   logTypeText += LogTypes[i - 1] + ",";
                   typeValueText += TypeValues[i - 1] + ",";
                }
             }
    
       return RedirectToAction("RptPage", new RouteValueDictionary(new { Controller = "Home", Action = "Rpt", IncID = ID }));
    }
    
    0 comments No comments