Back to Blogs

A user-friendly PowerApps DateTime selector

I recently had to build a Power Apps form for a SharePoint list tracking company events. For the most part, this was fairly straight forward as PowerApps auto-generates the form based on the schema of your list. However, the same did not go for end users selecting an event's Start and End date: The default values were often irrelevant and updating the Start date did not update the End date. It wasn't long until we ended up with events that 'ended' before they 'started', couldn't be rendered in our calendar, and left colleagues wondering what the heck was going on.

As this was my first attempt at PowerApps, figuring out a better DateTime selector took a bit of time but we did get there in the end.

Requirements

  1. The form needs to handle Events with a Start and End DateTime, and non-Events without dates.
  2. The End DateTime should always be after the Start DateTime.
  3. A record that's already been created should display the saved value, not the default value. (I may have needed to add this requirement myself after the first attempt..)

Step 1: Initialize the right Start and End DateTime values.

The form used a drop-down to differentiated between Events and non-Events. We can use its onChange property to (re-)initialize Start and End DateTimes. If the record is of type Event, use either the already-set Start Date or the current timestamp. If it's a non-Event, initialize the Date to an empty value. Finally, set this value to be available as the Default of the actual Date DataCard. We can then repeat the same for the End DateTime.

UpdateContext({
  StartDT: If(
    DataCardValue1.Selected.Value in ["Event"],
    Coalesce(ThisItem.Start, Now() - Minute(Now()) / 60 / 24),
    Blank(),
  ),
});
Start_DataCard1.Default = StartDT;

Step 2: Update the default values of Date DataCards.

From here, we can set the Default of our Start DataCard to StartDT, and the Default of our End DataCard to EndDT. This effectively handles requirements 1 and 3.

Step 3: Update the End Date based on changes to the Start Date.

For this, we need to update the OnChange properties of the Date, Hour, and Minute Values of our Start DataCard. First, we need to sync the value selected by the user with our StartDT. Then we check whether the Start DateTime is after the End DateTime and update the latter if necessary.

UpdateContext(
    {StartDT: DateTimeValue(
        Text(DateValue1.SelectedDate, "yyy-mm-dd") &
        " " &
        Text(HourValue1.Selected.Value, "[$-en-GB]hh") &
        ":" &
        Text(MinuteValue1.Selected.Value, "[$-en-GB]nn")
        )
    }
);
If(
    DateValue(EndDT) < DateValue(StartDT),
    UpdateContext(
        {EndDT: DateAdd(
            StartDT,
            1,
            TimeUnit.Hours
            )
        }
    ),
    EndDT = EndDT;
)

The above makes for a fairly intuitive user experience. Every an event is set to Start after it Ends, the End is automatically updated to be one hour after the selected Start. Great!