Yes, absolutely! You can definitely create an on-demand timer control within a Dynamics 365 form that isn't tied to SLAs and operates based on your custom toggle fields. The out-of-the-box (OTB) Timer control is indeed designed with SLA tracking in mind and has specific trigger requirements.
To achieve your requirement, you'll need to leverage the Power Apps Component Framework (PCF) to build a custom control. Here's a breakdown of the approach and key considerations:
Core Approach: Build a Custom PCF Control
PCF allows developers to create custom UI components that can be seamlessly integrated into model-driven apps (like Dynamics 365). This is the ideal way to create a timer with the exact behavior you need.
Key Elements of Your Custom PCF Control:
- UI Rendering: You'll need to use HTML, CSS, and JavaScript within your PCF control to render the timer display (e.g., displaying hours, minutes, seconds).
- Start/Pause/Stop Logic:
- You'll bind your PCF control to one or more Boolean (Two Options) fields on your D365 form. These fields will act as your "toggle fields."
- Your JavaScript code will monitor the changes in these toggle fields.
- Based on the state of the toggle fields:
- Start: When the "Start" toggle field is set to "Yes" (or your defined value), initiate the timer interval using
setInterval().
- Pause: When the "Pause" toggle field is set to "Yes", clear the interval using
clearInterval() to stop the timer at its current value.
- Stop/Reset: When the "Stop" toggle field is set to "Yes", clear the interval and reset the timer's displayed value to zero.
- Timer Value Storage:
- You'll need a way to store the elapsed time. You can bind your PCF control to a Whole Number (Integer) or Text (Single Line of Text) field on your D365 form to persist the timer's value.
- In your
setInterval() function, you'll increment the timer value and update both the displayed UI and the bound D365 field.
Steps to Build the PCF Control (High-Level):
- Set up your PCF development environment: This involves installing Node.js, the Power Platform CLI, and a suitable code editor (like Visual Studio Code).
- Create a new PCF project: Use the Power Platform CLI command:
pac pcf init --namespace YourNamespace --name OnDemandTimerControl --template field
- Implement the control's logic in
index.ts:
- Define input properties: These will correspond to your toggle fields (Start, Pause, Stop) and the field to store the timer value.
- Implement the
init method: This is called when the control is loaded. You'll initialize your UI elements here.
- Implement the
updateView method: This is called whenever the bound data changes (i.e., when your toggle fields are updated). This is where you'll implement the start, pause, and stop logic using setInterval() and clearInterval(). You'll also update the displayed timer value.
- Implement the
getOutputs method: This is called when data needs to be passed back to Dynamics 365 (e.g., when the timer value changes). You'll update the bound timer value field here.
- Implement the
destroy method: Clean up any resources.
- Define the control's manifest in
ControlManifest.Input.xml:
- Declare the input properties that will be bound to your toggle fields and the timer value field.
- Define the output property for the timer value.
- Build and package the PCF control: Use the Power Platform CLI commands:
npm install
npm run build
pac pcf push --publisher-prefix yourprefix
- Import the PCF control solution into your Dynamics 365 environment.
- Add the PCF control to your D365 form:
- Open the form in the form editor.
- Select the field where you want to display the timer.
- Go to the Controls tab in the field properties.
- Click Add Control... and select your custom "OnDemandTimerControl."
- Configure the bindings between the control's input properties and your toggle fields and the timer value field.
- Ensure the control is enabled for Web, Phone, and Tablet as needed.
- Click Save and Publish your customizations.
Example (Conceptual JavaScript in updateView):
private intervalId: NodeJS.Timeout | null = null;
private startTime: number = 0;
private elapsedTime: number = 0;
public updateView(context: ComponentFramework.Context<IInputs>): void {
const shouldStart = context.parameters.startToggle.raw === true;
const shouldPause = context.parameters.pauseToggle.raw === true;
const shouldStop = context.parameters.stopToggle.raw === true;
const timerValueControl = context.parameters.timerValue;
if (shouldStart && !this.intervalId) {
this.startTime = Date.now() - this.elapsedTime;
this.intervalId = setInterval(() => {
this.elapsedTime = Date.now() - this.startTime;
this.updateTimerDisplay(this.elapsedTime);
// Update the bound D365 field
timerValueControl.raw = Math.floor(this.elapsedTime / 1000); // Example: store in seconds
context.outputs.timerValue = timerValueControl;
context.notifyOutputChanged();
}, 1000); // Update every second
context.parameters.startToggle.raw = false; // Reset the toggle
} else if (shouldPause && this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
context.parameters.pauseToggle.raw = false; // Reset the toggle
} else if (shouldStop) {
clearInterval(this.intervalId);
this.intervalId = null;
this.elapsedTime = 0;
this.updateTimerDisplay(0);
timerValueControl.raw = 0;
context.outputs.timerValue = timerValueControl;
context.notifyOutputChanged();
context.parameters.stopToggle.raw = false; // Reset the toggle
}
// Update the UI with the current elapsed time
this.updateTimerDisplay(this.elapsedTime);
}
private updateTimerDisplay(milliseconds: number): void {
const seconds = Math.floor((milliseconds / 1000) % 60);
const minutes = Math.floor((milliseconds / (1000 * 60)) % 60);
const hours = Math.floor(milliseconds / (1000 * 60 * 60));
const display = `${this.pad(hours)}:${this.pad(minutes)}:${this.pad(seconds)}`;
// Update the HTML element displaying the timer
this.timerContainer.innerText = display;
}
private pad(num: number): string {
return num < 10 ? '0' + num : num.toString();
}
Internet Points Earned! 🌟🌟🌟
Building a PCF control will give you the exact on-demand timer functionality you need without the constraints of the OTB Timer control's SLA dependency. It requires development effort, but it's the most flexible and robust solution for this scenario.