Search code examples
asp.net-mvchtml.dropdownlistfor

DropDownListFor - need help defining "SelectedValue" property


I need help understanding how to set the SelectedValue property in HTML.DropDownListFor.

Here's what I have so far: In another part of the model, MA is an int that is stored on the database.

In the Model:

public IList<SelectListItem> SelectListMA(int MA)
    {
        
        IList < SelectListItem > List = new List<SelectListItem>();
        SelectListItem Item;
        for(int i = 1; i <= 9; i++)
        {
            Item = new SelectListItem
            {
                Value = i.ToString(),
                Text = i.ToString(),
                Selected = i == MA
            };
            List.Add(Item);
        }
        return List;
    }

In the controller:

ViewBag.MA = _Repository.SelectListMA(5);

And finally, in the View:

@Html.DropDownListFor(model => model.MA, new SelectList(ViewBag.MA, dataValueField: "Value", dataTextField: "Text"))

In the View the dropdown displays fine, however the default value is not being set and I am using the model to pass the original model for editing to View hence using ViewBag

Edit: Further details Requested - this is the full Controller that this belongs to.

    private readonly IRacesRepos _RaceRepository;

    public BaseTeamsController(IRacesRepos _Repository)
    {
        _RaceRepository = _Repository;


    }
    //sets the Model to the repository
    public BaseTeamsController() : this(new ModelRaces()) { }
        

    public ActionResult BEditPlayer(int ID)
        {
    
            Races_Players SelectedPlayer = _RaceRepository.GetPlayerBase(ID);
    
    
            ViewBag.MA = _RaceRepository.SelectListMA(SelectedPlayer.MA);
    
            ViewBag.ST = _RaceRepository.SelectListST(SelectedPlayer.ST);
            ViewBag.AG = _RaceRepository.SelectListAG(SelectedPlayer.AG);
            ViewBag.PA = _RaceRepository.SelectListPA((int)SelectedPlayer.PA);
            ViewBag.AV = _RaceRepository.SelectListAV(SelectedPlayer.AV);
            ViewBag.Race = _RaceRepository.GetRaceBase(SelectedPlayer.RaceID);
            return View(SelectedPlayer);
        }

And I am using MVC version 5, and ModelRaces is the name of the model that contains the code, MA is an int in the model from the database.

Full View

@model BB2020MVC.Models.Races_Players

@{
    ViewBag.Title = "Add Player to " + ViewBag.RaceName;
}



@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()
    
<div class="form-horizontal">
    <h4>Add Player to @ViewBag.RaceName</h4>
    <hr />
    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
    @Html.HiddenFor(model => model.PlayerID)
    @Html.HiddenFor(model => model.RaceID)

    <div class="form-group">
        @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10 focus">
            @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.MA, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.DropDownListFor(model => model.MA, new SelectList(ViewBag.MA, dataTextField: "Text", dataValueField:"Value") , new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.MA, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.ST, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.DropDownListFor(model => model.ST, new SelectList(ViewBag.ST, dataTextField: "Text", dataValueField: "Value"), new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.ST, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.AG, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.DropDownListFor(model => model.AG, new SelectList(ViewBag.AG, dataTextField: "Text", dataValueField: "Value"), new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.AG, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.PA, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.DropDownListFor(model => model.PA, new SelectList(ViewBag.PA, dataTextField: "Text", dataValueField: "Value") ,new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.PA, "", new { @class = "text-danger" })
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(model => model.AV, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.DropDownListFor(model => model.AV, new SelectList(ViewBag.AV, dataTextField: "Text", dataValueField: "Value") ,new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.AV, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.Cost, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.Cost, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.Cost, "", new { @class = "text-danger" })
        </div>
    </div>




    <div class="form-group">
        @Html.LabelFor(model => model.MaxQTY, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.MaxQTY, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.MaxQTY, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Create" class="btn btn-default" />
        </div>
    </div>
</div>
}

<div>
    @Html.ActionLink("Cancel", "ViewRace", new { ID = Model.RaceID })
</div>

Edit: Been doing a bit of testing and reading, issue seems to be that the view is not selecting the selected value of model => model.MA yet the value is not null on editing so any value that has been selected by SelectListItem or SelectList is ignored. Also passing any value into selectedValue other than a number or word (eg "1" or "Word", not a variable of type int or string) causes the item to not be selected. Doesn't fix the issue but an interesting point.


Solution

  • The answer to this one lies between the keyboard and the screen.

    Let me explain:

    In the additional testing I had erroneously changed _RaceRepository.GetPlayerBase(ID) to another function that generates a new base for the record. (an impromptu Mutation Test!)

    This meant every time I was trying to edit the player, I was passing the default value of "1 to the view and upon submission edited a model that never existed in the first place.

    Upon setting the correct function, I was getting the correct values and thus the setting of the selected value sorted itself out.

    I will however thank Sergey for having a look and trying to assist, and providing a better way of providing a SelectList (A better version would be to use a ViewModel, that will have to be used for another part).

    So for those that are interested, here is the code that solves this issue:

    From the Model:

    public SelectList SelectListMA()
        {
            IList<SelectListItem> List = new List<SelectListItem>();
            SelectListItem Item;
            for(int i = 1; i <=9; i++)
            {
                Item = new SelectListItem()
                {
                    Value = i.ToString(),
                    Text = i.ToString()
                };
                List.Add(Item);
            }
            
            return new SelectList(List,"Value","Text");
        }
    

    From the Controller:

        public ActionResult BEditPlayer(int ID)
        {
            Races_Players SelectedPlayer = _RaceRepository.GetPlayerBase(ID);
    
            ViewBag.MASelect = _RaceRepository.SelectListMA();
            ViewBag.STSelect = _RaceRepository.SelectListST();
            ViewBag.AGSelect = _RaceRepository.SelectListAG();
            ViewBag.PASelect = _RaceRepository.SelectListPA();
            ViewBag.AVSelect = _RaceRepository.SelectListAV();
    
    
    
            return View(SelectedPlayer);
        }
    

    From the View: - as SelectList is to stop errors happening as the code is built

    @Html.DropDownListFor(model => model.MA, ViewBag.MASelect as SelectList, "Select One") 
    

    Also, for any new programmers as per the research and testing, SelectList and SelectListItem have SelectedValue and Selected respectively for selecting Default values.

    SelectedValue can be any object that identifies the primary key of the list or a new default value of the list (eg integer for a value already in the list, or a string for a default value of null).
    Selected, however, is a boolean (ie true or false) that selects the value of the list. You only need to use one or the other.

    Remember - if the value is passed from the controller to the view as the value in model => model.[Variable] then the value will be set to the value passed, not to the value set by SelectedValue or Selected.