Search code examples
c#asp.net-mvcpostgresqlasp.net-core

Multi-selected values can't be passed to the controller


I am trying to select multiple values with Multiselect functionality and pass them to db, but to no avail.

Models' M-M relations


        public class Cluster : IEntityBase<string>
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public string Id { get; set; }
        [Required]
        public string Name { get; set; }
        public IEnumerable<Sensor> Sensors { get; set; }


    }
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public string Id { get; set; }
        public string Name { get; set; }
        public IEnumerable<Cluster> Clusters { get; set; } 
        [ForeignKey("SensorType")]
        public string SensorTypeId { get; set; }
        public SensorType SensorType { get; set; }

Repository Pattern

private readonly ApplicationDbContext _db; 
public SensorRepository(ApplicationDbContext db) {
 _db = db; 
}

public void Add(SensorVM entity)
        {       
            
            Sensor mappedSensor = new Sensor()
            {
                Id = entity.Id,
                Name = entity.Name,
                Clusters = entity.Clusters,
                SensorTypeId = entity.SensorTypeId,
                SensorType = entity.SensorType,
                APIUrl = entity.APIUrl,
                X = entity.X,
                Y = entity.Y,
                Configuration = entity.Configuration,
                ConfigurationSchema = schema.ToJson(),
                SerialNumber = entity.SerialNumber,
                Interval = entity.Interval,
                IsActive = entity.IsActive
            };                        
            _db.Sensors.Add(mappedSensor);
            _db.SaveChanges();                        
        }

Controller code

        [HttpGet]
        public IActionResult Add()
        {                        
            IEnumerable<Cluster> getClusters = _clusterRepository.GetAll().ToList();
            ViewData["Clusters"] = new MultiSelectList(getClusters, "Id", "Name");
    ...
            return View();
        }

        [HttpPost]
        public IActionResult Add(SensorVM obj)
        {
            if (ModelState.IsValid)
            {                
                _sensorRepository.Add(obj);
                return RedirectToAction("Index");
            }
            return View(obj);
        }

View code

<div class="form-floating py-2 col-12">
            <select asp-for="Clusters" asp-items="(MultiSelectList)@ViewData["Clusters"]" multiselect-search="true" multiple placeholder="-Select Clusters-">
            <span asp-validation-for="Clusters" class="text-danger"></span>
            </select>
 </div>

It shows Clusters = null.

I suspect I am missing some sort of Id manipulation - collecting them in a list. Using the M-m relationship, a ClusterSensor table was created in db consisting of SensorId and ClusterId.

The other thing is that I am missing a way to populate the 'selectedValues' parameter of MultiSelectList.

public MultiSelectList(IEnumerable items, string dataValueField, string dataTextField, IEnumerable selectedValues);

Solution

  • If you want to get a multi selection of values ,like ClusterIds,we can add a property ClusterIds in SensorVM model like:

    public IEnumerable<Cluster> Clusters { get; set; }
    
    public string[] ClusterIds { get; set; }
    

    Then in the view:

    <div class="form-floating py-2 col-12">
        <select asp-for="ClusterIds" asp-items="(MultiSelectList)@ViewData["Clusters"]" multiselect-search="true" multiple placeholder="-Select Clusters-">
            <span asp-validation-for="ClusterIds" class="text-danger"></span>
        </select>
    </div>
    

    result:

    enter image description here

    Then set the Clusters by the select ClusterId, like:

    [HttpPost]
    public IActionResult Add(SensorVM obj)
            {  
            IEnumerable<Cluster> getClusters = _clusterRepository.GetAll().ToList();
    
            var list = new List<Cluster>();
            foreach (var x in obj.ClusterIds)
            {
               var item = getClusters.FirstOrDefault(s => s.Id == x);
               list.Add(item);
             }
               obj.Clusters = list;
    
                ModelState.Remove("Clusters");
                if (ModelState.IsValid)
                {                
                    _sensorRepository.Add(obj);
                    return RedirectToAction("Index");
                }
                return View(obj);
            }
    

    result:

    enter image description here

    Update:

    @model SensorVM
    
    <form method="post">
        <div class="form-floating py-2 col-12">
            <select asp-for="ClusterIds" asp-items="(MultiSelectList)@ViewData["Clusters"]" multiselect-search="true" multiple placeholder="-Select Clusters-">
                <span asp-validation-for="ClusterIds" class="text-danger"></span>
            </select>
        </div> 
        <button type="submit">submit</button>
    </form>