nwash57
nwash57

Reputation: 37

New to MVC, Populating a DropDownList from a database

I am trying to make a system where, while filling out a webform to add an entry to a database, there are dropdownlists populated from another editable database. So an admin could say, add another name to a list of employees on a payroll and then that name would be populated into the dropdownlist next time it's accessed.

I tried following a lot of other answers to questions like mine on SO, but I haven't been able to get anything to work. This is the one I think i got closest with: MVC 4 Simple Populate DropDown from database model

Using that I created a "Pipeline" object, (Name of the project I'm working on):

[Table("Entries")]
public class pipeline
{
    [Key]
    public int entryID { get; set; }
    public salesStage currentSalesStage { get; set; }
    public string Name { get; set; }

}

A "salesStage" object, (This is what I want an admin to be able to change, so they could theoretically add or delete a sales stage and an employee would see that reflected when they create a new entry into the "pipeline"):

[Table("salesStages")]
public class salesStage
{
    [Key]
    public int salesStageID { get; set; }
    [Display(Name = "Name")]
    public string Name { get; set; }
}

Then I have the ViewModel that the answer from that link outlined:

public class MyViewModel
{
    public pipeline Entry { get; set; }
    public IEnumerable<SelectListItem> salesStages { get; set; }
}

The Database context:

public class PipelineDB : DbContext
{
    public DbSet<pipeline> Entries { get; set; }
}

The ActionResult outlined in the linked answer:

public ActionResult Action(int id)
    {
        var model = new MyViewModel();
        using (var db = new PipelineDB())
        {
            model.salesStages = db.Entries.ToList().Select(x => new SelectListItem
                {
                    Value = x.currentSalesStage.ToString(),
                    Text = x.Name
                });
        }
        return View(model);
    }

And finally where I tried to integrate it into my "Create" View: @Model Pipeline9.Models.MyViewModel

@{
    ViewBag.Title = "Create";
}

<h2>Create</h2>


@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>pipeline</h4>
        <hr />
        @Html.ValidationSummary(true)

        <div class="form-group">
            @Html.LabelFor(model => model.Name, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Name)
                @Html.ValidationMessageFor(model => model.Name)
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.currentSalesStage, new { @class = "control-label col-md-2"})
            <div class="col-md-10">
                @Html.DropDownListFor(x => model.currentSalesStage.salesStageID, Model.salesStages)
            </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("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

I think the create view is where I am going wrong, because it gives me an error on that @Html.DropDownListFor. The Error is:

CS1973: 'System.Web.Mvc.HtmlHelper' has no applicable method named 'DropDownListFor' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax.

Edit: So far everything has worked to a point, but the compiler keeps telling me that "model does not exist in the current context" for @Html.DropDownListFor(x => model.currentSalesStage.salesStageID,...

Upvotes: 1

Views: 3309

Answers (4)

nwash57
nwash57

Reputation: 37

Finally figured it out. used ViewBag to populate the dropdown.

First add the database you need to your controller:

private MyDataBase db = new MyDataBase();

Then set a ViewBag as a new SelectList in the controller:

ViewBag.MyViewBagVariable = new SelectList(db.MyDataBaseModels, "ID", "ID");

And finally, under the View use the DropDownListFor helper with your ViewBag to populate the dropdown list:

@Html.DropDownListFor(model => model.MyDataBaseValue, (SelectList)ViewBag.MyViewBagVariable

Upvotes: 1

Kundan Singh Chouhan
Kundan Singh Chouhan

Reputation: 14282

Try this instead:

@Html.DropDownListFor(x => model.currentSalesStage.salesStageID, 
    new SelectList(Model.salesStages, "Value", "Text"))

Edit

@nwash57 as per your recent comment your currentSalesStage model is null so in order to resolve it assign new instance of your pipeline class into this property in your controller and pass it to your view, e.g.

public ActionResult Action(int id)
{
    var model = new MyViewModel();
    using (var db = new PipelineDB())
    {
        model.salesStages = db.Entries.ToList().Select(x => new SelectListItem
            {
                Value = x.currentSalesStage.ToString(),
                Text = x.Name
            });

        model = new pipeline();
    }
    return View(model);
}

This will fix your issue.

Upvotes: 0

TheNorthWes
TheNorthWes

Reputation: 2739

When you do this: model.salesStages = db.Entries.ToList().Select(x => new SelectListItem { Value = x.currentSalesStage.ToString(), Text = x.Name });

You are setting model.salesStages to an enumerable expression. If you call ToList() after your select it should enumerate your Select(...) into a List of concrete objects.

Code:

 model.salesStages = db.Entries.ToList().Select(x => new SelectListItem
            {
                Value = x.currentSalesStage.ToString(),
                Text = x.Name
            }).ToList();

Upvotes: 0

Lee Englestone
Lee Englestone

Reputation: 4667

Maybe try this?

<div class="col-md-10">
     @Html.DropDownListFor(x => model.currentSalesStage.salesStageID, (SelectList)Model.salesStages)
</div>

Upvotes: 1

Related Questions