Home > Blockchain >  Set mvc dropdownlist value bound to object array
Set mvc dropdownlist value bound to object array

Time:10-05

I have a razorview in MVC looping over an array of objects from my model and generating corresponding html controls.

My html elements are properly bound, except my drop down lists who can't seem to select the value provided to them by the model.

My view: (in the hereby case, I'm simply displaying a list of countries)

@for (var i = 0; i < Model.answers.Count(); i  )
{
            <div >

                ...

                    @switch (Model.answers[i].Statement.QuestionType)
                    {
                        ...
                        
                        case ExternalEnums.QuestionTypeEnum.country:

                            @Html.DropDownListFor(
                                 Model => Model.answers[i].Value,
                                 new SelectList(Model.Pays, "Value", "Text")
                             )

                            break;
                        
                    }

                ...
                
            </div>
}

My viewcontroller, generating the country list items and retrieving the existing model entries:


    public class HomeIndexViewModel
    {
        private QuestionsModelContainer dbContext;
        private AdmcommonEntities admCommonContext;

        ...

        public List<Answer> answers { get; private set; }

        private IEnumerable<SelectListItem> _countries;

        public IEnumerable<SelectListItem> Pays
        {
            get
            {
                if (_countries == null)
                    SetCountries();

                return _countries;
            }
        }

        public HomeIndexViewModel()
        {
            Init(-1, null);
        }

        public HomeIndexViewModel(int page, string _pageWideError = null)
        {
            Init(page, _pageWideError);
        }

        private void Init(int page, string _pageWideError = null)
        {
            dbContext = new QuestionsModelContainer();
            
            PageNum = page;
            pageWideError = _pageWideError;
            answers = GetAnswers();

            ...
        }

        private void SetCountries() 
        {
            using (admCommonContext = new AdmcommonEntities())
            {
                var localEntities = admCommonContext.Pays.ToList();
                var localList = new List<SelectListItem>();
                localList.Add(new SelectListItem());

                foreach (var item in localEntities)
                {
                    var newItemList = new SelectListItem();
                    newItemList.Text = item.Libelle;
                    newItemList.Value = item.Libelle;
                    localList.Add(newItemList);
                }

                _countries = localList;
            }            
        }


        public List<Statement> GetStatements()
        {
            var statements = dbContext.StatementSet.Where(w => w.Page == PageNum).OrderBy(w => w.Order).ToList();
            return statements;
        }

        public List<Answer> GetAnswers()
        {
            var statements = GetStatements();
            var ExistingAnswers = new List<Answer>();

            if (AdminPermissionManager.IsUserAuthenticated()) //Loading existing entries.
                ExistingAnswers = Answer.GetExistingAnswers(statements, dbContext);

            var answers = new List<Answer>();
            foreach (var item in statements)
            {
                var answer = ExistingAnswers.Where(w => w.StatementId == item.Id).FirstOrDefault();

                if (answer == null)
                {
                    answer = new Answer();
                    answer.StatementId = item.Id;
                    answer.Statement = item;
                }

                answers.Add(answer);
            }

            return answers;
        }
    }

My model class, simply containing the value i'm trying to display:


    [MetadataType(typeof(AnswerMetaData))]
    public partial class Answer
    {
        ...

        public static List<Answer> GetExistingAnswers(List<int> statementIds, QuestionsModelContainer dbContext)
        {
            List<Answer> ExistingAnswers;
            var usercode = AdminPermissionManager.GetUserCode();
            ExistingAnswers = dbContext.AnswerSet.Where(w => statementIds.Contains(w.StatementId) && w.ChildCode == usercode).ToList();
            return ExistingAnswers;
        }

        public static List<Answer> GetExistingAnswers(List<Statement> statements, QuestionsModelContainer dbContext)
        {
            var statementIds = statements.Select(w => w.Id).ToList();
            return GetExistingAnswers(statementIds, dbContext);
        }
    }

    public class AnswerMetaData
    {

        [InternalValidation]
        public string Value { get; set; }

        private class InternalValidationAttribute : ValidationAttribute
        {
            ...
        }
    }

I'm sure there's something very obvious that I'm missing, but can't figure out what exactly :/...

CodePudding user response:

You're nearly there actually, this part in the View:

 @Html.DropDownListFor(
     Model => Model.answers[i].Value,
     new SelectList(Model.Pays, "Value", "Text")
 )

You create a new selectlist - each time, but you already have a IEnumerable<SelectListItem> created, so you don't have to recreate that list. The only thing you might be missing (most likely) is the "Selected" item option.

If you already have a value selected (and it isn't the first one) it will not be selected dropdown option - also because you pass the value of the selected option as the "ID" of the field (not the actual value) - DropDownListFor is kinda weird in that regard.

So you want to change your @Html.DropDownListFor to something like this:

 @Html.DropDownListFor(
     Model => Model.answers[i].Name,
     Pays(Model.answers[i].Value)
 )

When that being done you should change your property "Pays" in the ViewModel to a method that accepts a value (idk what you're using, but let's assume it's string) - to something along the lines of this:

 public IEnumerable<SelectListItem> Pays(string selectedValue)
 {
    if (_countries == null) SetCountries();
    var value = new List<SelectListItem>();
    foreach(var item in _countries)
    {
        item.Selected = (item.Value == selectedValue);
        value.Add(item);
    }
    return value;
 }

This above is a bit pseudocoded since I'm typing this from memory, but it should get you into the correct direction. Also remember to check with the inspect element in the browser if the dropdown HTML element really has the correct name attribute.

  • Related