jdtcn / BlazorDateRangePicker

A Blazor component for choosing date ranges and dates
MIT License
186 stars 34 forks source link

synced calendars #39

Closed DanPFW closed 4 years ago

DanPFW commented 4 years ago

I'd like to use the left calendar for my start range and the right calendar for my end range. I set the start/end dates to the 1st and last day of a month. Both dates highlight on the same calendar.

jdtcn commented 4 years ago

Hi,

you can use <DateRangePicker LinkedCalendars="true" /> to achieve that behavior.

DanPFW commented 4 years ago

the calendars always display current & next/prior month. How do I get both calendars to display the same month? ie. I want the left calendar to display 10/1/20 and the right calendar to display 10/15/20.

AlwaysShowCalendars="true" AutoAdjustCalendars="false" LinkedCalendars="true" ShowOnlyOneCalendar="false" SingleDatePicker="false"

jdtcn commented 4 years ago

Ok, I got it now. So, to achieve that behavior, you'll need to:

  1. Change calendar month when other month is changed,
  2. Modify css to meet your requirements,
  3. Modify day click handler.

Something like that:

<style>
    .daterangepicker td.in-range {
        background-color: transparent;
    }

    .left td.end-date,
    .right td.start-date {
        background-color: transparent;
        color: black;
    }

    .start-date.end-date,
    .left td.start-date,
    .right td.end-date {
        background-color: #357ebd !important;
        color: white !important;
    }

    .left .end-date.active:hover,
    .right .start-date.active:hover {
        background-color: transparent;
        color: black;
    }
</style>

<DateRangePicker @ref="Picker" AutoAdjustCalendars="false" OnMonthChanged="MonthChanged" />

@code {
    DateRangePicker Picker { get; set; }
    DateTimeOffset? LeftMonth { get; set; }
    DateTimeOffset? RightMonth { get; set; }

    private void MonthChanged()
    {
        if (LeftMonth != Picker.LeftCalendar.Month)
        {
            var rightMonth = Picker.RightCalendar.GetType().GetProperty("Month");
            rightMonth.SetValue(Picker.RightCalendar, Picker.LeftCalendar.Month);
        }
        else if (RightMonth != Picker.RightCalendar.Month)
        {
            var leftMonth = Picker.LeftCalendar.GetType().GetProperty("Month");
            leftMonth.SetValue(Picker.LeftCalendar, Picker.RightCalendar.Month);
        }

        UpdateClickHandlers(Picker.RightCalendar, SideType.Right);
        UpdateClickHandlers(Picker.LeftCalendar, SideType.Left);

        LeftMonth = Picker.LeftCalendar.Month;
        RightMonth = Picker.RightCalendar.Month;
    }

    private void UpdateClickHandlers(CalendarType calendarType, SideType side)
    {
        var calendar = calendarType.GetType()
            .GetProperty("Calendar",
                System.Reflection.BindingFlags.NonPublic
                | System.Reflection.BindingFlags.Instance)
            .GetValue(calendarType);

        foreach (var row in (List<List<CalendarItem>>)calendar)
        {
            foreach (var day in row)
            {
                var dayClick = day.Click;
                day.Click = () =>
                {
                    if (side == SideType.Right && !Picker.TEndDate.HasValue)
                    {
                        if (day.Day > Picker.TStartDate) dayClick.Invoke();
                    }
                    else if (side == SideType.Left)
                    {
                        Picker.TStartDate = null;
                        Picker.TEndDate = null;
                        dayClick.Invoke();
                    }
                };
            }
        }
    }
}
DanPFW commented 4 years ago

this is looking really good. It looks like the 2 calendars are still linked in a way? the month selection/arrow controls both calendars/month drop downs. in addition to defaulting the left calendar to 1 date in a month, and the right calendar to another date in the same month, I'd also like the ability to cross months. can this component support that kind of functionality? thanks for all your input on this. really appreciate it.

jdtcn commented 4 years ago

Yes, the calendars is linked by this code:

DateTimeOffset? LeftMonth { get; set; }
DateTimeOffset? RightMonth { get; set; }

private void MonthChanged()
{
    if (LeftMonth != Picker.LeftCalendar.Month)
    {
        var rightMonth = Picker.RightCalendar.GetType().GetProperty("Month");

        // Here we set the right month when the left is changed
        rightMonth.SetValue(Picker.RightCalendar, Picker.LeftCalendar.Month);
    }
    else if (RightMonth != Picker.RightCalendar.Month)
    {
        var leftMonth = Picker.LeftCalendar.GetType().GetProperty("Month");

        // Here we set the left month when the right is changed
        leftMonth.SetValue(Picker.LeftCalendar, Picker.RightCalendar.Month);
    }

    LeftMonth = Picker.LeftCalendar.Month;
    RightMonth = Picker.RightCalendar.Month;
}

Just remove this code and the calendars will not be linked in any way.

DanPFW commented 4 years ago

I've tried that, however, once removed, both calendars won't display the same month at the same time.

jdtcn commented 4 years ago

Did you try it with AutoAdjustCalendars="false" or AutoAdjustCalendars="true"?

jdtcn commented 4 years ago

And you can set initially selected months in the MonthChanged method like that:

DateTimeOffset? Month { get; set; }

private void MonthChanged()
{
    if (!Month.HasValue)
    {
        Month = DateTimeOffset.Now.AddDays(-100);

        var rightMonth = Picker.RightCalendar.GetType().GetProperty("Month");
        rightMonth.SetValue(Picker.RightCalendar, Month.Value);

        var leftMonth = Picker.LeftCalendar.GetType().GetProperty("Month");
        leftMonth.SetValue(Picker.LeftCalendar, Month.Value);
    }
}
DanPFW commented 4 years ago

I think I finally found a combination of settings I needed.

AlwaysShowCalendars="true" AutoAdjustCalendars="true" LinkedCalendars="false" ShowOnlyOneCalendar="false" SingleDatePicker="false" StartDate="ReportStartingDate" EndDate="ReportEndingDate"

thanks for all of your input. Now I need to figure out if your component can be used to select month (Jan-Dec) and quarters (1-4).

jdtcn commented 4 years ago

Now I need to figure out if your component can be used to select month (Jan-Dec) and quarters (1-4).

No, it's not, sorry. But there is other components with this functionality.