Hello Community,
thanks to Andrews tutorials ( https://www.youtube.com/watch?v=YJ9hrKxAhTU ) and his help in a previous thread I thought I had successfully created a working PCF control that could replace the ootb DateAndTime.DateAndTime control, but then Internet Explorer happened (well, and the D365 plugin in Outlook - since that's using IE exclusively and apparently there are no plans to move to Edge), and now I have to make the control work with IE, too.
Instead of showing the control, I get an "Error loading control": Error occured during initialization of control: kuc.TimePicker;Message: Ungültiges Argument. (translation: Invalid Argument)
and the full errorDetails are:
Error: Ungültiges Argument.
at TimePicker.prototype.init (eval code:23:5)
at CustomControlHostRoot.prototype._initializeControl (https://kucdev.crm4.dynamics.com/uclient/scripts/es5/editformpage.js?v=1.3.228-1912.2:593:21909)
at Anonymous function (https://kucdev.crm4.dynamics.com/uclient/scripts/es5/editformpage.js?v=1.3.228-1912.2:593:9462)
at _ (https://kucdev.crm4.dynamics.com/uclient/scripts/es5/app.js?v=1.3.228-1912.2:2684:8745)
at e.prototype.scheduleControlUpdate (https://kucdev.crm4.dynamics.com/uclient/scripts/es5/app.js?v=1.3.228-1912.2:2904:1647)
at n (https://kucdev.crm4.dynamics.com/uclient/scripts/es5/editformpage.js?v=1.3.228-1912.2:593:9321)
at CustomControlHostRoot.prototype._initializeData (https://kucdev.crm4.dynamics.com/uclient/scripts/es5/editformpage.js?v=1.3.228-1912.2:593:9502)
at CustomControlHostRoot.prototype.componentDidMount (https://kucdev.crm4.dynamics.com/uclient/scripts/es5/editformpage.js?v=1.3.228-1912.2:593:36362)
at nj (https://kucdev.crm4.dynamics.com/uclient/scripts/es5/vendor.js?v=1.3.228-1912.2:451:172)
at t.unstable_runWithPriority (https://kucdev.crm4.dynamics.com/uclient/scripts/es5/app.js?v=1.3.228-1912.2:2450:3871)
Aktivitäts-ID: 5457e6b6-2cfd-4a88-b78a-76e56f6bf746
at first I thought this was down to using the blur event I was using to catch inputs once the user leaves the field, but commenting that part out entirely didn't help at all. So I assume this is down to init not being called properly, but I have no idea where to go from here. I didn't see anything come up in the browser console, and the message itself isn't all that helpful either.
The control works fine in Edge (Chromium), Firefox, Chrome and so on, it's just IE that's having issues here.
import {IInputs, IOutputs} from "./generated/ManifestTypes";
import * as $ from "jquery";
import { Component } from "react";
export class TimePicker implements ComponentFramework.StandardControl {
private date: HTMLInputElement;
private time: HTMLInputElement;
private notifyOutputChanged: () => void;
constructor()
{
}
/**
* Used to initialize the control instance. Controls can kick off remote server calls and other initialization actions here.
* Data-set values are not initialized here, use updateView.
* @param context The entire property bag available to control via Context Object; It contains values as set up by the customizer mapped to property names defined in the manifest, as well as utility functions.
* @param notifyOutputChanged A callback method to alert the framework that the control has new outputs ready to be retrieved asynchronously.
* @param state A piece of data that persists in one session for a single user. Can be set at any point in a controls life cycle by calling 'setControlState' in the Mode interface.
* @param container If a control is marked control-type='standard', it will receive an empty div element within which it can render its content.
*/
public init( context: ComponentFramework.Context,
notifyOutputChanged: () => void,
state: ComponentFramework.Dictionary,
container: HTMLDivElement)
{
this.date = document.createElement("input");
this.date.type = "date";
this.date.className = "date";
var current = new Date();
this.date.max = this.padLeft(current.getFullYear(), 4) "-" this.padLeft(current.getMonth() 1, 2) "-" this.padLeft(current.getDate(), 2);
this.time = document.createElement("input");
this.time.type = "time";
this.time.className = "time";
var dateTime = context.parameters.dateTime.raw;
if (dateTime != null) {
var offset = dateTime.getTimezoneOffset();
var dateOnly = this.padLeft(dateTime.getFullYear(), 4) "-" this.padLeft(dateTime.getMonth() 1, 2) "-" this.padLeft(dateTime.getDate(), 2);
var timeOnly = this.padLeft(dateTime.getHours(), 2) ":" this.padLeft(dateTime.getMinutes(), 2);
this.date.value = dateOnly;
this.time.value = timeOnly;
}
this.notifyOutputChanged = notifyOutputChanged;
// register onChange events and forward them to CDS
this.date.addEventListener("blur", () => { // 19
this.notifyOutputChanged();
});
this.time.addEventListener("blur", () => {
this.notifyOutputChanged();
});
// add fields to container (div)
container.appendChild(this.date);
container.appendChild(this.time);
}
/**
* Called when any value in the property bag has changed. This includes field values, data-sets, global values such as container height and width, offline status, control metadata values such as label, visible, etc.
* @param context The entire property bag available to control via Context Object; It contains values as set up by the customizer mapped to names defined in the manifest, as well as utility functions
*/
public updateView(context: ComponentFramework.Context): void
{
var dateTime = context.parameters.dateTime.raw;
if (dateTime != null) {
var offset = dateTime.getTimezoneOffset();
//dateTime.setTime(dateTime.getTime() offset*60000);
var dateOnly = this.padLeft(dateTime.getFullYear(), 4) "-" this.padLeft(dateTime.getMonth() 1, 2) "-" this.padLeft(dateTime.getDate(), 2);
var timeOnly = this.padLeft(dateTime.getHours(), 2) ":" this.padLeft(dateTime.getMinutes(), 2);
this.date.value = dateOnly;
this.time.value = timeOnly;
}
}
/**
* It is called by the framework prior to a control receiving new data.
* @returns an object based on nomenclature defined in manifest, expecting object[s] for property marked as “bound” or “output”
*/
public getOutputs(): IOutputs
{
if (this.date.valueAsDate != null && this.time.valueAsDate != null) {
//offset = this.date.valueAsDate.getTimezoneOffset();
var offset = this.time.valueAsDate.getTimezoneOffset();
var dateTime = new Date(this.date.valueAsNumber this.time.valueAsNumber /* (offset * 60000)*/);
dateTime.setTime(dateTime.getTime() (dateTime.getTimezoneOffset()*60000))
return {
dateTime: dateTime
};
} else {
return { dateTime: undefined }
}
}
/**
* Called when the control is to be removed from the DOM tree. Controls should use this call for cleanup.
* i.e. cancelling any pending remote calls, removing listeners, etc.
*/
public destroy(): void
{
// Add code to cleanup control if necessary
}
/**
* Helper function to pad strings
*
*/
public padLeft(input: Number, length: Number): String
{
var result = input.toString();
var c = '0';
while (result.length < length) result = c result;
return result;
}
}