Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Better way to show model for month-year calendar and interact with user

I solved my task, but I don't like how it works. It looks too heavy for me. If you can suggest me a better way to do exactly the same it would be awesome!

So here is my pain :) I have a table in SQL DB which contains charts with business data and they are developed by separate department and they are adding them randomly (at least from my point of view). The year range is 1995-2012(3) but both of those dates should be flexible because every next month new data appear and they'll try to add more data for the past.

Now it looks like this: selectable calendar month-year

To achive this goal I created this model:

using System;
using System.Collections.Generic;

namespace MvcApplication1.Models
{
    [Serializable]
    public class MonthlyModel
    {
        public int TypeId { get; set; }
        public List<YearDTO> Items { get; set; }
    }

    [Serializable]
    public class YearDTO
    {
        public DateTime Year { get; set; }
        public MonthDTO January { get; set; }
        public MonthDTO February { get; set; }
        public MonthDTO March { get; set; }
        public MonthDTO April { get; set; }
        public MonthDTO May { get; set; }
        public MonthDTO June { get; set; }
        public MonthDTO July { get; set; }
        public MonthDTO August { get; set; }
        public MonthDTO September { get; set; }
        public MonthDTO October { get; set; }
        public MonthDTO November { get; set; }
        public MonthDTO December { get; set; }
    }
    [Serializable]
    public class MonthDTO
    {
        public DateTime start { get; set; }
        public DateTime end { get; set; }
        public int priceTypeId { get; set; }
        public bool IsEnabled { get; set; }
        public bool IsSelected { get; set; }
    }

}

Here is Controller which contains GetMethod to show View as presented above and Post method to get this Model back parse it and create anothe View with charts.

    using System;
    using System.Collections.Generic;
    using System.Web.Mvc;
    using MvcApplication1.Models;

    namespace MvcApplication1.Controllers
    {

        public class HistoricalController : Controller
        {
            [HttpGet]
            public ActionResult Monthly()
            {
                int typeId = -1;
                try
                {
                    typeId = Convert.ToInt32(RouteData.Values["id"]);
                }
                catch (Exception)
                {

                }
                MonthlyModel mm;
                if (Session[String.Format("MonthlySelect{0}", typeId)] != null)
                {
                    mm = (MonthlyModel)Session[String.Format("MonthlySelect{0}", typeId)];
                }
                else
                {
                    mm = GetMonthlyModel(typeId);
                }
                return View(mm);
            }

            private MonthlyModel GetMonthlyModel(int typeId)
            {
                MonthlyModel mm = new MonthlyModel();
                var list = ChartManager.GetAvailableMonthlyCharts(typeId, 1, 3, new DateTime(1995, 1, 1), DateTime.Today);

                foreach (Tuple<DateTime, DateTime, bool, int> val in list)
                {
                    var start = val.Item1;
                    var end = val.Item2;
                    var exists = val.Item3;
                    var pti = val.Item4;

                    var items = mm.Items ?? (mm.Items = new List<YearDTO>());
                    int idx = items.FindIndex(f => f.Year.Year == start.Year);
                    if (idx == -1)
                    {
                        items.Add(new YearDTO { Year = new DateTime(start.Year, 1, 1) });
                        idx = items.FindIndex(f => f.Year.Year == start.Year);
                    }
                    switch (start.Month)
                    {
                        case 1:
                            items[idx].January = new MonthDTO { start = start, end = end, priceTypeId = pti, IsEnabled = exists, IsSelected = false };
                            break;
                        case 2:
                            items[idx].February = new MonthDTO { start = start, end = end, priceTypeId = pti, IsEnabled = exists, IsSelected = false };
                            break;
                        case 3:
                            items[idx].March = new MonthDTO { start = start, end = end, priceTypeId = pti, IsEnabled = exists, IsSelected = false };
                            break;
                        case 4:
                            items[idx].April = new MonthDTO { start = start, end = end, priceTypeId = pti, IsEnabled = exists, IsSelected = false };
                            break;
                        case 5:
                            items[idx].May = new MonthDTO { start = start, end = end, priceTypeId = pti, IsEnabled = exists, IsSelected = false };
                            break;
                        case 6:
                            items[idx].June = new MonthDTO { start = start, end = end, priceTypeId = pti, IsEnabled = exists, IsSelected = false };
                            break;
                        case 7:
                            items[idx].July = new MonthDTO { start = start, end = end, priceTypeId = pti, IsEnabled = exists, IsSelected = false };
                            break;
                        case 8:
                            items[idx].August = new MonthDTO { start = start, end = end, priceTypeId = pti, IsEnabled = exists, IsSelected = false };
                            break;
                        case 9:
                            items[idx].September = new MonthDTO { start = start, end = end, priceTypeId = pti, IsEnabled = exists, IsSelected = false };
                            break;
                        case 10:
                            items[idx].October = new MonthDTO { start = start, end = end, priceTypeId = pti, IsEnabled = exists, IsSelected = false };
                            break;
                        case 11:
                            items[idx].November = new MonthDTO { start = start, end = end, priceTypeId = pti, IsEnabled = exists, IsSelected = false };
                            break;
                        case 12:
                            items[idx].December = new MonthDTO { start = start, end = end, priceTypeId = pti, IsEnabled = exists, IsSelected = false };
                            break;
                    }
                }

                mm.metalId = typeId;
                return mm;
            }

            [HttpPost]
            public ActionResult MonthlyCharts(MonthlyModel model)
            {
                List<ChartDTO> list = new List<ChartDTO>();

                foreach (YearDTO dto in model.Items)
                {
                    var val = dto.January;
                    if (val.IsSelected) list.Add(ChartManager.GetChart(val.start, val.end, model.metalId, 1, val.priceTypeId));
                    val = dto.February;
                    if (val.IsSelected) list.Add(ChartManager.GetChart(val.start, val.end, model.metalId, 1, val.priceTypeId));
                    val = dto.March;
                    if (val.IsSelected) list.Add(ChartManager.GetChart(val.start, val.end, model.metalId, 1, val.priceTypeId));
                    val = dto.April;
                    if (val.IsSelected) list.Add(ChartManager.GetChart(val.start, val.end, model.metalId, 1, val.priceTypeId));
                    val = dto.May;
                    if (val.IsSelected) list.Add(ChartManager.GetChart(val.start, val.end, model.metalId, 1, val.priceTypeId));
                    val = dto.June;
                    if (val.IsSelected) list.Add(ChartManager.GetChart(val.start, val.end, model.metalId, 1, val.priceTypeId));
                    val = dto.July;
                    if (val.IsSelected) list.Add(ChartManager.GetChart(val.start, val.end, model.metalId, 1, val.priceTypeId));
                    val = dto.August;
                    if (val.IsSelected) list.Add(ChartManager.GetChart(val.start, val.end, model.metalId, 1, val.priceTypeId));
                    val = dto.September;
                    if (val.IsSelected) list.Add(ChartManager.GetChart(val.start, val.end, model.metalId, 1, val.priceTypeId));
                    val = dto.October;
                    if (val.IsSelected) list.Add(ChartManager.GetChart(val.start, val.end, model.metalId, 1, val.priceTypeId));
                    val = dto.November;
                    if (val.IsSelected) list.Add(ChartManager.GetChart(val.start, val.end, model.metalId, 1, val.priceTypeId));
                    val = dto.December;
                    if (val.IsSelected) list.Add(ChartManager.GetChart(val.start, val.end, model.metalId, 1, val.priceTypeId));
                }
                Session[String.Format("MonthlySelect{0}", model.metalId)] = model;
                ModelState.Clear();
                return View(list);
            }
        }
    }

And the last part is actually a View to represent this checkbox field:

    @model MvcApplication1.Models.MonthlyModel

    @{
        ViewBag.Title = "Monthly charts ";
        Layout = "~/Views/Shared/_Layout.cshtml";
    }

    <h2>@(ViewBag.Title)</h2>

    <div id="choice-container">
       @using (Html.BeginForm("MonthlyCharts", "Historical", FormMethod.Post))
    {
        @Html.TextBox("metalId", Model.metalId, new { @type = "hidden" })
        <table>
            <tr>
                <th> Year</th>
                <th> January</th>
                <th> February</th>
                <th> March</th>
                <th> April</th>
                <th> May</th>
                <th> June</th>
                <th> July</th>
                <th> August</th>
                <th> September</th>
                <th> October</th>
                <th> November</th>
                <th> December</th>
                <th> </th>
            </tr>
            @for (int i = 0; i < Model.Items.Count(); i++)
            {
                <tr>
                    <td>
                        @Html.Label("Items[" + i + "].Year", Model.Items[i].Year.ToString(@"yyyy"))
                        @Html.TextBox("Items[" + i + "].Year", Model.Items[i].Year, new { @type = "hidden" })
                    </td>
                    <td>
                        <div align=center class="editor-field">
                            @if (Model.Items[i].January.IsEnabled)
                            {
                                @Html.CheckBox("Items[" + i + "].January.IsSelected", Model.Items[i].January.IsSelected, new { @class = "chk" })
                            }
                            else
                            {
                                @Html.CheckBox("Items[" + i + "].January.IsSelected", Model.Items[i].January.IsSelected, new { @disabled = "disabled" })
                            }
                            @Html.TextBox("Items[" + i + "].January.IsEnabled", Model.Items[i].January.IsEnabled, new { @type = "hidden" })
                            @Html.TextBox("Items[" + i + "].January.start", Model.Items[i].January.start, new { @type = "hidden" })
                            @Html.TextBox("Items[" + i + "].January.end", Model.Items[i].January.end, new { @type = "hidden" })
                            @Html.TextBox("Items[" + i + "].January.priceTypeId", Model.Items[i].January.priceTypeId, new { @type = "hidden" })
                        </div>
                    </td>
                    @*
                      .... 11 times ....
                      *@
                </tr>
            }

        </table>


    <input type="submit" class="button" value="Get the image"/>
    }
    </div>

So user can only choose months of the years if we have charts for them. The year range can change in the future. We must show chart on separate page. We must remember the model (I keep it in session) if user decided to go back and select a couple more months.

So what I don't like in this solution: 1. Model is heavy, hard to use, to create and parse. Not easy to add new parameters. 2. View contains a lot of hidden fields because of model 3. Controller is okay except creation and parse the model.

I'm pretty new for web dev, but I'm not a newby in software development and I want it look better if it's possible.

I really feel that I'm missing something here. I appreciate your ideas, suggestions and anything that could simplify this code. Thanks!

UPDATE:

I want to clarify why I use so many parameters. I can't use only one DateTime because each chart has start DateTime and end DateTime (begin and the end of the month) and TypeId. Besides I need somehow to build table in view and put each control in right place. Now I'm using name of months for this purpose. I also need to know on the View side is control enabled (if user can select it) and then on the POST method I need to know which of them was selected so I have bool IsEnabled { get; set; } and bool IsSelected { get; set; } and other parameters.

like image 681
Pavel Kovalev Avatar asked Nov 13 '22 14:11

Pavel Kovalev


1 Answers

You can simplify a lot of things by not specifying each individual month. The DateTime object can take care of that. Don't repeat yourself if it's not necessary

Your view can be simplified then to use some loops instead of 12 separate blocks. The th block can also be simplified with a loop and outputting the month like so:

new DateTime(2010, 8, 1).ToString("MMM", CultureInfo.InvariantCulture);

I'm not sure why you're putting all of the values into Hidden fields, especially when they aren't needed for the post back data. All of that information should be stored server side anyways, so there should be methods for pulling it in from your data model.

Also, the Post handler doesn't need to consume the exact same model. Each checkbox could be defined as <input type='checkbox' name='chart' value='2012-01-01' />. The Post handler would accept something like List<string>, and you can just convert the values you received to DateTime's and retrieve your charts

like image 51
Andrew Burgess Avatar answered Nov 15 '22 04:11

Andrew Burgess