0
votes

I am trying to create a filter drop down list to pass as parameter back to my controller. I cannot seem to get the drop down list to render.

Below is my model:

using System;

namespace ShiftPatternConfigurator.Models
{
    public class ShiftModel
    {
        public int ShiftNo;
        public string ShiftName;
        public DateTime StartTime;
        public DateTime FinishTime;
        public string Team;
        public int Week;
        public int CycleWeek = 0;
        public string StartDay;
        public DateTime StartDate;
    }

    public enum Month
    {
        January = 1,
        February = 2,
        March = 3,
        April = 4,
        May = 5,
        June = 6,
        July = 7,
        August = 8,
        September = 9,
        October = 10,
        November = 11,
        December = 12
    }
}

Here's my Controller:

using Oracle.ManagedDataAccess.Client;
using ShiftPatternConfigurator.Models;
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.Mvc;

namespace ShiftPatternConfigurator.Controllers
{
    public class HomeController : Controller
    {
        // list to hold the shift data
        List<ShiftModel> shiftData = new List<ShiftModel>();
        // GET: Index
        public ActionResult Index()
        {
            ViewBag.Title = "Shift Pattern Configurator";
            // create the select list to help pick which months shifts to look at
            ViewBag.Month = new SelectList(Enum.GetValues(typeof(Month)),"Month", "Month", DateTime.Now.ToString("MMMM"));
            // create the shift data to display in the page          
            return View(GetShiftData(shiftData, ViewBag.Month));
        }

        [HttpPost]
        public ActionResult SelectMonth(SelectList Month)
        {
            ViewBag.Title = "Shift Pattern Configurator";          
            ViewBag.Month = Month;
            return View(GetShiftData(shiftData, Month));
        }

        private List<ShiftModel> GetShiftData(List<ShiftModel> shiftData, SelectList monthIn)
        {
            // get the month enum from our selected value
            Month month = (Month)Enum.Parse(typeof(Month), monthIn.SelectedValue.ToString());
            DateTime start;
            DateTime finish;
            // if its the end of the year (December) 
            if ((int)month == 12)
            {
                // then show december and january
                start = new DateTime(DateTime.Today.Year, (int)month, 1, 0, 0, 0);
                finish = new DateTime(DateTime.Today.Year + 1, 2, 1, 0, 0, 0);
            }
            else
            {
                start = new DateTime(DateTime.Today.Year, (int)month, 1, 0, 0, 0);
                finish = new DateTime(DateTime.Today.Year, (int)month + 1, 1, 0, 0, 0);
            }

            // build the query (Get shift records that are greater than or equal to today and 2 weeks worth)
            StringBuilder oracleQuery = new StringBuilder("SELECT SHIFT_NO, SHIFT_NAME, START_TIME, FINISH_TIME, TEAM, WEEK, CYCLE_WEEK, START_DAY, START_DATE ");
            oracleQuery.Append("FROM PROD_KPI.NEW_SHIFTS ");
            oracleQuery.Append("WHERE START_DATE BETWEEN :pSTART_DATE AND :pEND_DATE ");
            oracleQuery.Append("ORDER BY START_DATE DESC ");

            // connection to oracle
            string connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["IFSOracleConnection"].ConnectionString;
            OracleConnection conn = new OracleConnection(connectionString);
            conn.Open();

            // oracle command object and parameters
            OracleCommand cmd = new OracleCommand(oracleQuery.ToString(), conn);
            cmd.Parameters.Add(new OracleParameter("pSTART_DATE", OracleDbType.Date));
            cmd.Parameters[0].Value = start;
            cmd.Parameters.Add(new OracleParameter("pEND_DATE", OracleDbType.Date));
            cmd.Parameters[1].Value = finish;

            // execute the query
            OracleDataReader reader = cmd.ExecuteReader();
            while (reader.Read())
            {
                //object o = reader.IsDBNull(0) ? null : reader.GetValue(0);
                ShiftModel shiftRecord = new ShiftModel
                {
                    ShiftNo = reader.GetInt32(reader.GetOrdinal("SHIFT_NO")),
                    ShiftName = reader.IsDBNull(reader.GetOrdinal("SHIFT_NAME")) ? null : reader.GetString(reader.GetOrdinal("SHIFT_NAME")),
                    StartTime = reader.GetDateTime(reader.GetOrdinal("START_TIME")),
                    FinishTime = reader.GetDateTime(reader.GetOrdinal("FINISH_TIME")),
                    Team = reader.IsDBNull(reader.GetOrdinal("TEAM")) ? null : reader.GetString(reader.GetOrdinal("TEAM")),
                    Week = reader.GetInt32(reader.GetOrdinal("WEEK")),
                    CycleWeek = reader.GetInt32(reader.GetOrdinal("CYCLE_WEEK")),
                    StartDay = reader.IsDBNull(reader.GetOrdinal("START_DAY")) ? null : reader.GetString(reader.GetOrdinal("START_DAY")),
                    StartDate = reader.GetDateTime(reader.GetOrdinal("START_DATE"))
                };
                shiftData.Add(shiftRecord);
            }

            reader.Close();

            return shiftData;
        }
    }
}

Here's my Razor view:

@using ShiftPatternConfigurator.Models
@model IEnumerable<ShiftPatternConfigurator.Models.ShiftModel>

<h2>@ViewBag.Title</h2>

@using (Html.BeginForm("SelectMonth", "HomeController", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    @Html.DropDownList("Month", (SelectList)ViewBag.Month)
    <input type="submit" value="SelectMonth" />
}


<table class="table">
    <tr>
        <th>Shift No</th>
        <th>Shift Name</th>
        <th>Start Time</th>
        <th>Finish Time</th>
        <th>Team</th>
        <th>Week</th>
        <th>Start Day</th>
        <th>Start Date</th>
        <th></th>
    </tr>

    @if (Model.Count() > 0)
    {
        foreach (var item in Model)
        {
            <tr>
                <td>@item.ShiftNo</td>
                <td>@item.ShiftName</td>
                <td>@item.StartTime</td>
                <td>@item.FinishTime</td>
                <td>@item.Team</td>
                <td>@item.Week</td>
                <td>@item.StartDay</td>
                <td>@item.StartDate.ToShortDateString()</td>
                <td>
                    @Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
                    @Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
                    @Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
                </td>
            </tr>
        }
    }
    else
    {
        <tr>
            <td colspan="10" align="center"><h2>No Data</h2></td>
        </tr>
    }

</table>

Can someone suggest how to create the DropDownList object so that when the form is submitted it passes the Month parameter back to my select month ActionResult in the HomeController.

When I run my code and break just prior to creating the DropDownList, if I inspect my ViewBag.Month I can see a populated SelectList with the Selected Value set to the current month.

Advice please.

EDIT: The Error I am receiving is the following:

System.Web.HttpException: 'DataBinding: 'ShiftPatternConfigurator.Models.Month' does not contain a property with the name 'Month'.'

2

2 Answers

1
votes

You can manually build the select list as your answer shows or you can use the built in Html helper Html.EnumDropDownListFor which will achieve what I believe you're looking for with much less code. Example usage as follows:

public class MyViewModel
{
    //Month is an enum here
    public Month Month { get; set; }
}

and your view (MonthExample.cshtml) would look like :

@model MyProject.MyViewModel
...
@using(Html.BeginForm("MonthExample", "ControllerName", FormMethod.Post))
{
    @Html.EnumDropDownListFor(x => x.Month)
    <button type="submit">Save</button>
}

...

the framework will see that Month is an enum and automatically build the options for the dropdown list as opposed to you doing that manually.

If you'd like to see a simple example of the controller get/post, they could look like the following:

public ActionResult MonthExample()
{
    return View(new MyViewModel());
}

[HttpPost]
public ActionResult MonthExample(MyViewModel model)
{
    //here model.Month will have the selected month from the dropdown list
}
0
votes

So after really stopping to think about the error I have fixed my issue. Well actually there was two which I will explain.

The Error I was receiving was:

System.Web.HttpException: 'DataBinding: 'ShiftPatternConfigurator.Models.Month' does not contain a property with the name 'Month'.'

This led me to think about the fact that my enum has no dataValueField or dataTypeField as it's an enum.

So I looked at my code where I am creating the SelectList:

ViewBag.Month = new SelectList(Enum.GetValues(typeof(Month)), "Month", "Month", DateTime.Now.ToString("MMMM"));

I looked more closely at the overloaded methods and found one that does not require the dataValueField or dataTypeField, so I modified my code to the following:

ViewBag.Month = new SelectList(Enum.GetValues(typeof(Month)), DateTime.Now.ToString("MMMM"));

This then allowed the DropDownList to be rendered. However I was still experiencing an issue where the Selected value was not being set. After a quick google I found that you can't set a ViewBags dynamic field the same as the models property.

So I modified my controller code like so:

ViewBag.MonthFilter = new SelectList(Enum.GetValues(typeof(Month)), DateTime.Now.ToString("MMMM"));

and my view code like so:

@using (Html.BeginForm("SelectMonth", "HomeController", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    @Html.DropDownList("Month", (SelectList)ViewBag.MonthFilter)
    <input type="submit" value="SelectMonth" />
}

EDIT: Here is my new updated code after using the answer provided by @GregH

Model:

using System;
using System.Collections.Generic;

namespace ShiftPatternConfigurator.Models
{
    // view model
    public class ShiftViewModel
    {
        public IEnumerable<ShiftModel> Shifts { get; set; }
        public Month Month { get; set; }
    }

    // shift model
    public class ShiftModel
    {
        public int ShiftNo;
        public string ShiftName;
        public DateTime StartTime;
        public DateTime FinishTime;
        public string Team;
        public int Week;
        public int CycleWeek = 0;
        public string StartDay;
        public DateTime StartDate;
    }

    // month enum
    public enum Month
    {
        January = 1,
        February = 2,
        March = 3,
        April = 4,
        May = 5,
        June = 6,
        July = 7,
        August = 8,
        September = 9,
        October = 10,
        November = 11,
        December = 12
    }
}

Controller:

using Oracle.ManagedDataAccess.Client;
using ShiftPatternConfigurator.Models;
using System;
using System.Collections.Generic;
using System.Text;
using System.Web.Mvc;

namespace ShiftPatternConfigurator.Controllers
{
    public class HomeController : Controller
    {
        // GET: Index
        public ActionResult Index()
        {
            ViewBag.Title = "Shift Pattern Configurator Test";
            ShiftViewModel view = new ShiftViewModel
            {
                Month = new Month()
            };
            view.Month = (Month)DateTime.Now.Month;
            view.Shifts = GetShiftData(view.Month);       
            return View(view);
        }

        [HttpPost]
        public ActionResult Index(ShiftViewModel view)
        {
            ViewBag.Title = "Shift Pattern Configurator";
            view.Shifts = GetShiftData(view.Month);
            return View(view);
        }

        private List<ShiftModel> GetShiftData(Month month)...
    }
}

View:

@model ShiftPatternConfigurator.Models.ShiftViewModel

<h2>@ViewBag.Title</h2>

@using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    @Html.EnumDropDownListFor(x => x.Month)
    <input type="submit" value="SelectMonth" />
}
<table class="table">
    <tr>
        <th>Shift No</th>
        <th>Shift Name</th>
        <th>Start Time</th>
        <th>Finish Time</th>
        <th>Team</th>
        <th>Week</th>
        <th>Start Day</th>
        <th>Start Date</th>
        <th></th>
    </tr>

    @if (Model.Shifts.Count() > 0)
    {
        foreach (var item in Model.Shifts)
        {
            <tr>
                <td>@item.ShiftNo</td>
                <td>@item.ShiftName</td>
                <td>@item.StartTime</td>
                <td>@item.FinishTime</td>
                <td>@item.Team</td>
                <td>@item.Week</td>
                <td>@item.StartDay</td>
                <td>@item.StartDate.ToShortDateString()</td>
                <td>
                    @Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
                    @Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
                    @Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
                </td>
            </tr>
        }
    }
    else
    {
        <tr>
            <td colspan="10" align="center"><h2>No Data</h2></td>
        </tr>
    }

</table>