Search code examples
c#asp.netasp.net-mvcasp.net-coreasp.net-core-tag-helpers

Getting a date from form input (with tag helpers) and displaying events in that week in asp.net core mvc


I want a system where:

  1. Upon first visiting the page, a user sees a list of events for the current week;
  2. The user selects a week from the dropdown weekpicker, and the start date of that week is displayed in the text input field;
  3. The user presses 'go' and then the page refreshes (or not if I want to be fancy) and displays the list of events for the given week.

So far, parts 1 and 2 work fine.

So, what am I missing from this code so that the model updates with a new given date (the start of the week) and the page refreshes to show the items from said week? As I understand it, model binding happens automatically so I don't need to put anything explicit in the IndexNewDate method to update the model with the inputted date, correct?

My model:

 public class PlannerViewModel
    {
        public List<PlannerLib.Models.EventModel> Events { get; set; }
        public DateTime startDate { get; set; }
    } 

My View (the relevant part):

<div class="weekSelector">
        <form method="post" asp-controller="HomeController" asp-action="chooseWeek" autocomplete="off">
            <input type="text" asp-for="IndexNewDate" name="startDate" id="weekPicker" autocomplete="off"/>
            <input type="submit" value="Go" class="submit" />
        </form>
</div>

My Controller:

public class HomeController : Controller
    {
        public IActionResult Index()
        {
            DateTime weekStart = new DateTime(2020, 10, 1);
            PlannerViewModel model = new PlannerViewModel();
            model.Events = new List<PlannerLib.Models.EventModel>();
            model.Events = PlannerController.AcquireWeekData(weekStart).ToList();

            return View(model);
        }

        [HttpPost]
        public IActionResult IndexNewDate(PlannerViewModel model) { 

            DateTime weekStart = model.startDate;
            model.Event = new List<PlannerLib.Models.EventModel>();
            model.Event = PlannerController.AcquireWeekData(weekStart).ToList();

            return View(model);
        }
    }

And for context, the JS weekpicker:

$(function () {
    var startDate;
    var endDate;
    $('#weekPicker').datepicker({
        firstDay: 1,
        dateFormat: 'dd-mm-yy',
        changeMonth: true,
        changeYear: true,
        showButtonPanel: true,
        onSelect: function (dateText, inst) {
            var date = $(this).datepicker('getDate');
            startDate = new Date(date.getFullYear(), date.getMonth(), date.getDate() - date.getDay() + 1);
            endDate = new Date(date.getFullYear(), date.getMonth(), date.getDate() - date.getDay() + 6);
            var dateFormat = inst.settings.dateFormat || $.datepicker.dateFormat;
            $('#startDate').text($.datepicker.formatDate(dateFormat, startDate, inst.settings));
            $('#endDate').text($.datepicker.formatDate(dateFormat, endDate, inst.settings));
            $(this).val($.datepicker.formatDate(dateFormat, startDate, inst.settings));
        }
    });
});

Solution

  • So there were a few things I was getting wrong.

    Firstly, I hadn't included *@addTagHelper , Microsoft.AspNetCore.Mvc.TagHelpers at the top of my view file.

    This allowed me to see that my tag helpers were wrong. The asp-for tag should refer to the variable within the model that it's for, not the action in the controller. Secondly, due to some shuffling around I'd left an old action (which would have been incorrect anyway) in the asp-action. I now have updated that to refer to the correct action in the controller.

    <div class="weekSelector">
        <form method="post" asp-action="**Index**" autocomplete="off">
            <input type="text" asp-for="**startDate**" name="startDate" id="weekPicker" autocomplete="off" />
            <input type="submit" value="Go" class="submit" />
        </form>
    </div>
    

    I also removed the reference to asp-controller, because that was affecting the post request.

    In fact, in the controller there is no need for a different action name.

    [HttpGet]
    public IActionResult Index()
    {
            DateTime weekStart = new DateTime(2020, 10, 1);
            PlannerViewModel model = new PlannerViewModel();
            model.Events = new List<PlannerLib.Models.EventModel>();
            model.Events = PlannerController.AcquireWeekData(weekStart).ToList();
            model.startDate = weekStart;
    
            return View(model);
    }
    
    [Route("/")]
    [HttpPost]
    public IActionResult Index(PlannerViewModel model) { 
    
            DateTime weekStart = model.startDate;
            model.Events = new List<PlannerLib.Models.EventModel>();
            model.Events = PlannerController.AcquireWeekData(weekStart).ToList();
    
            return View(model);
    }
    

    Now there are two Index() actions, differentiated by HttpPost and and HttpGet and also whether or not they take in the model as a parameter.