1

I need to select Quarter and Year then on submit those two values should be passed to my stored proc "SummaryProc" and after executing it will pass the rows for ID..... Please guide me if the code i have written is fine. I am missing out on the link as I am unable to understand how to link all these. The working app will be "Enter Quarter & Year in _Summary.cshtml -> Pass values to Controller -> Execution in Repository code -> rows returned from stored proc to be displayed in SummaryTable.cshtml"

_Summary.cshtml

                     <div class="form-group">
                    <label class="control-label col-lg-4">Period:</label>
                    <div class="col-lg-8">
                        @Html.DropDownList("Quarter", new SelectListItem[] { (new SelectListItem() { Text = "Q1", Value = "1" }), (new SelectListItem() { Text = "Q2", Value = "2" }), (new SelectListItem() { Text = "Q3", Value = "3" }), (new SelectListItem() { Text = "Q4", Value = "4" }) }, "--Select Quarter--", new { @class = "form-control", id = "Quarter" })
                        <br />
                        @Html.DropDownList("Year", new SelectListItem[] { (new SelectListItem() { Text = "2016", Value = "2016" }), (new SelectListItem() { Text = "2017", Value = "2017" }) }, "--Select Year--", new { @class = "form-control", id = "Year" })
                    </div>
                </div>

                    <div class="row">
                        <div class="col-lg-offset-4" style="padding: 10px 0px 0px 0px;">
                            <input type="submit" id="submit" value="Submit" class="btn btn-lg btn-success" />
                        </div>
                    </div>

Controller code:

  [ActionName("_Summary")]
            [HttpPost]

            public ActionResult _Summary(FloorPlanViewModel model, FormCollection form)
            {

                SummaryConfiguration sumConfig = new SummaryConfiguration();
            sumConfig.Quarter = Convert.ToInt32(form["Quarter"]);
            sumConfig.Year = Convert.ToInt32(form["Year"]);
            var details = floorService.SummaryProc(sumConfig.Quarter, sumConfig.Year);
            return PartialView("SummaryTable", details);

            }

Code to execute stored procedure:

 public IEnumerable<SummaryConfiguration> SummaryProc(int Quarter, int Year)
          {
              var model = new List<SummaryConfiguration>();


              using (var dbCmd = defaultDB.GetStoredProcCommand("dbo.SummaryProc"))
              {
                  defaultDB.AddInParameter(dbCmd, "Quarter", System.Data.DbType.Int32, Quarter);
                  defaultDB.AddInParameter(dbCmd, "Year", System.Data.DbType.Int32, Year);
                  var varCmd = defaultDB.ExecuteReader(dbCmd);

                  while (varCmd.Read())
                  {
                      // add items in the list
                      model.Add(new SummaryConfiguration()
                      {
                          ID = Convert.ToString(varCmd["ID"]),
                        //rest of the code
                      });
                  }
              }
              return model;
          }
beginner
  • 303
  • 1
  • 10
  • 31
  • You need to specify the view name if you want to return a different view. But why in the world are you not binding to your model instead of using code like `Convert.ToInt32(form["Quarter"]`. And you will get better performance if you were to use ajax to post the option values and update the existing view with a partial view of the table. –  Aug 01 '17 at 03:04
  • And your `SummaryProc` method returns `IEnumerable` so the `@foreach (var item in Model.sumConfig)` makes no sense (`IEnumerable` does not contain any properties) and your code would just throw [this exception](https://stackoverflow.com/questions/40373595/the-model-item-passed-into-the-dictionary-is-of-type-but-this-dictionary-requ) –  Aug 01 '17 at 03:09
  • @StephenMuecke so can i just use '@foreach (var item in Model)' ? – beginner Aug 01 '17 at 03:37
  • Yes you could (but then you not displaying the selected options in the new view which does not make for a good UI) –  Aug 01 '17 at 03:42
  • in the next view i need to display lineid, project etc in the table. I have made some changes to the code..let me update the question – beginner Aug 01 '17 at 03:45
  • @StephenMuecke I have made some changes to the code. Now I am getting a page where I need to enter Quarter & year. but on submit nothing is happening. Its even not hitting the breakpoiubts in the controller – beginner Aug 01 '17 at 03:53
  • Yes I know, but you will also want to display (say) 'Results for Quarter 1, 2017' so the user knows what they are looking at :) And `_Summary.cshtml` has nothing to do with `@model IList`, and it needs a different model (one with properties for `Quarter` and `Year`) –  Aug 01 '17 at 03:54
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/150673/discussion-between-stephen-muecke-and-beginner). –  Aug 01 '17 at 03:54

1 Answers1

1

The typical way to handle this without using ajax is to have a single GET method and view that posts back to the method.

Start by creating a view model to represent your view

public class SummaryConfigurationVM
{
    public int Quarter { get; set; }
    public int Year { get; set; }
    public IEnumerable<SummaryConfiguration> Configurations { get; set; }
    public IEnuemrable<SelectListItem> QuarterList { get; set; }
    public IEnuemrable<SelectListItem> YearListList { get; set; }
}

and add any validation attributes that may be applicable to Quarter and Year (for example a [Range] attribute)

and the your controller method will be

public ActionResult Summary(int? quarter, int? year)
{
    IEnumerable<SummaryConfiguration> configurations = new List<SummaryConfiguration>();
    if (quarter.HasValue && year.HasValue)
    {
        configurations = floorService.SummaryProc(quarter.Value, year.Value);
    }
    SummaryConfigurationVM model = new SummaryConfigurationVM()
    {
        Quarter = quarter,
        Year = year,
        Configurations = configurations,
        QuarterList = new List<SelectListItem>()
        {
            new SelectListItem(){ Text = "Q1", Value = "1" },
            ....
        },
        YearList = new List<SelectListItem>()
        {
            ....
        }
    };
    return View(model);
}

Note that you also need to consider validating that the values of quarter and year fall in the expected range.

Your view will then be

@model SummaryConfigurationVM
....
@using (Html.BeginForm("Summary", "yourControllerName", FormMethod.Get))
{
    @Html.LabelFor(m => m.Quarter)
    @Html.DropDownListFor(m => m.Quarter, Model.QuarterList, "--Select Quarter--")
    @Html.ValidationMessageFor(m => m.Quarter)

    .... // ditto for Year

    <input type="submit" value="Submit" />
}

<table>
    <thead>
        <tr>
            <th>@Html.DisplayNameFor(m => m.Configurations.FirstOrDefault().LineID)</th>
            ....
        </tr>
    </thead>
    <tbody>
        @foreach( var item in Model.Configurations)
        {
            <tr>
                <td>@Html.DisplayFor(modelItem => item.LineID)</td>
                .... // other properties of SummaryConfiguration
            </tr>
        }
    </tbody>
</table>

You might also consider rendering the <table> in side a @if (Model.Configuraton.Any()) { block (and if false the display a message noting that no results were found.

  • I made changes according to your answer. But when i run the app Its not opening the page where i need to enter Quarter and year.. throws an exception " [ArgumentException: The parameters dictionary contains a null entry for parameter 'quarter' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ActionResult SummaryTable(Int32, Int32)' in 'USTGlobal.WorkBench.UI.Controllers.FloorPlanController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter. Parameter name: parameters]" – beginner Aug 01 '17 at 05:54
  • 1
    If your want to be able to navigate to the page and not pass any parameters, then just make the parameters `nullable` - i.e. `public ActionResult Summary(int? quarter, int? year)` but then you will definitely need to validate that they are not `null` before running your query –  Aug 01 '17 at 05:56
  • 1
    For example if either are `null` then you would set your `Configurations` to an empty list (and not call the `SummaryProc()` method. Give me 10 min and I'll update the answer with a typical example, but you may need to modify it based on your logic –  Aug 01 '17 at 05:58
  • i made the changes . that particular exception is gone now. But I am getting another exception at SummaryProc about the casting "Object cannot be cast from DBNull to other types." – beginner Aug 01 '17 at 06:14
  • Did you use `quarter.Value, year.Value` when calling the method? –  Aug 01 '17 at 06:14
  • In my question you can see "Code to execute stored procedure: LineID = Convert.ToString(varCmd["LineID"]),...." – beginner Aug 01 '17 at 06:15
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/150684/discussion-between-stephen-muecke-and-beginner). –  Aug 01 '17 at 06:15