Search code examples
asp.net-mvcparametershtml.dropdownlistforactionresult

MVC/Razor: Call action method with parameter from dropdownlist onchange event and parameter from an actionlink button value


I've inherited an ASP.NET MVC project (dude left) that needs changes and so trying to understand how the project works and how to fix it.

It's an application for recording and editing timesheets Timesheet snippet

When the user selects a month, the display changes and shows data for that month. The trouble is, the previous guy didn't allow for there being more than one year, so clicking 8 (for instance), displays August's data for this and previous years. I've added the year button so the user can select the year.

Controller is:

        public ActionResult MyTimesheets(int? month, int? year)
    {
        if(year == null)
        {
            year = DateTime.Now.Year;
        }

        if(month == null)
        {
            month = DateTime.Now.Month;
        }

        ViewBag.UserName = GetCurrentUserName();

        //  Get list of years in data for drop-down box
        var yearList = new SelectList(contextdb.TimeSheetsDb.Select(y => y.TimeSheetDate.Year).Distinct().OrderByDescending(y => y.ToString()).ToList());
        ViewData["YearList"] = yearList;

        var myTimeSheets = contextdb.TimeSheetsDb.Include(x => x.UserTS).Where(x => x.UserTS.UPN == User.Identity.Name && x.TimeSheetDate.Month == month.Value && x.TimeSheetDate.Year == year.Value).ToList();
        return View(myTimeSheets);
    }

I added the year aparemeter and altered the query to filter on year as well as month.

He's used a loop to create the buttons for each month:

        @for (int i = 1; i <= 12; i++)
    {
        if (Model.First().TimeSheetDate.Month == i)
        {
            @Html.ActionLink(i.ToString(), "MyTimesheets", new { month = i }, new { @class = "btn btn-success", style = "margin-left: 3px" });
        }
    else
        {
        @Html.ActionLink(i.ToString(), "MyTimesheets", new { month = i }, new { @class = "btn btn-default", style = "margin-left: 3px" });
        }
    }

I've added the drop-down list based on the view data in the controller:

        <td>@Html.DropDownList("YearList", (IEnumerable<SelectListItem>)ViewData["YearList"], new { @onchange = "CallChangefunc(this.value)" })</td>

This has an onchange event, so when the user selects a different year, the action event is called with the new parameter value for the year:

<script>
    function CallChangefunc(val) {
        var url;

        url = "/TimeSheets/MyTimeSheets/?year=" + val;

        window.location.href = url;
    }

This works and it's taken me a long time to get here.

What I am now floundering with is if the user clicks a button for a different month, how to pass the new month value AND the currently selected year to the action method as the year parameter.

And conversely, if changing the year, passing with the onchange event the currently clicked month.


Solution

  • If you need to do the same javascript code like you did for onchange event Just Add onClick for the buttons when you create it Eg:

    @Html.ActionLink(i.ToString(), "MyTimesheets", new { month = i }, new { @class = "btn btn-success", style = "margin-left: 3px", @onclick = "CallClickfunc("+i+")" });
    

    Pass the i value on that function Now Javascript function for that would be

    function CallClickfunc(val){
        //Here get the selected value of Year drop down and pass it to URL
        var year = $('#YearList').val();
        $('#hdnMonth').val(val);
        var url;
    
        url = "/TimeSheets/MyTimeSheets/?year=" + year +"&month="+val;
    
        window.location.href = url;
    }
    

    This would work for the button click and along with year.

    ********************For Year drop down along with button******************** Simply you can create a hidden value to store the month value which we would be changing in the above function which we created And you can add

        @for (int i = 1; i <= 12; i++)
        {
            if (Model.First().TimeSheetDate.Month == i)
            {
                 @Html.ActionLink(i.ToString(), "MyTimesheets", new { month = i }, new { @class = "btn btn-success", style = "margin-left: 3px", @onclick = "CallClickfunc("+i+")" });
    <input type="hidden" name="hdnMonth" id="hdnMonth" value=""+i+"">
            }
        else
            {
             @Html.ActionLink(i.ToString(), "MyTimesheets", new { month = i }, new { @class = "btn btn-default", style = "margin-left: 3px", @onclick = "CallClickfunc("+i+")" });
    <input type="hidden" name="hdnMonth" id="hdnMonth" value=""+i+"">
            }
        }
    

    After this your onchange function would change to get the value from hidden and append with URL

    function CallChangefunc(val) {
            var month = $('#hdnMonth').val();
            var url;
    
            url = "/TimeSheets/MyTimeSheets/?year=" + val+"&month="+month;
    
            window.location.href = url;
        }
    

    This code would work for both the functionality you said.

    Yes, we have a better option to do this but to continue with the code as you have done to make it easier for you, I continued the same.