Hi guys,
Trying to build an optionset control. Fired up the debug harness, and it's stuck on "Loading control harness...".
Using the following Manifest.
<?xml version="1.0" encoding="utf-8" ?> <manifest> <control namespace="ControlsAndrewLy" constructor="ColorOptionsets" version="0.0.1" display-name-key="ColorOptionsets_Display_Key" description-key="ColorOptionsets_Desc_Key" control-type="standard"> <!-- property node identifies a specific, configurable piece of data that the control expects from CDS --> <property name="inputOptionSet" display-name-key="Option Set" description-key="Option Set from CDS" of-type="OptionSet" usage="bound" required="true" /> <property name="inputColorHexString" display-name-key="Color Hex Codes" description-key="Provide a list of color hex codes separated by a comma. e.g. #8B0000,#FF6347,#8B0000" of-type="SingleLine.Text" required="true" /> <resources> <code path="index.ts" order="1"/> <!-- <css path="css/ColorOptionsets.css" order="1" />--> </resources> <!-- UNCOMMENT TO ENABLE THE SPECIFIED API <feature-usage> <uses-feature name="Device.captureAudio" required="true" /> <uses-feature name="Device.captureImage" required="true" /> <uses-feature name="Device.captureVideo" required="true" /> <uses-feature name="Device.getBarcodeValue" required="true" /> <uses-feature name="Device.getCurrentPosition" required="true" /> <uses-feature name="Device.pickFile" required="true" /> <uses-feature name="Utility" required="true" /> <uses-feature name="WebAPI" required="true" /> </feature-usage> --> </control> </manifest>
And the following index.ts file
import {IInputs, IOutputs} from "./generated/ManifestTypes"; export class ColorOptionsets implements ComponentFramework.StandardControl<IInputs, IOutputs> { // Value of the field is stored and used inside the control private _value: number; // string with hex codes private _colorhexcodes: "#FF0000,#800000,#FF6347"; private _colorhexcodesarray : string[]; // PowerApps component framework framework delegate which will be assigned to this object which would be called whenever an update happens. private _notifyOutputChanged: () => void; // label element created as part of this control private label: HTMLInputElement; // Hold field options of bounded optionset field private _fieldOptions: Array<ComponentFramework.PropertyHelper.OptionMetadata>; // Reference to the control container HTMLDivElement // This element contains all elements of our custom control example private _container: HTMLDivElement; // Reference to ComponentFramework Context object private _context: ComponentFramework.Context<IInputs>; private _dropdownSelect: HTMLSelectElement; /** * Empty constructor. */ 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='starndard', it will receive an empty div element within which it can render its content. */ public init(context: ComponentFramework.Context<IInputs>, notifyOutputChanged: () => void, state: ComponentFramework.Dictionary, container:HTMLDivElement) { this._context = context; // vectorise hex colour codes this._colorhexcodesarray = this._colorhexcodes.split(","); /* // set the optionsetfield options if (this._context.parameters.inputOptionSet.attributes) { this._fieldOptions = this._context.parameters.inputOptionSet.attributes.Options; this._dropdownSelect = document.createElement("select"); // add each individual option for(let i=0; i<this._fieldOptions.length; i++){ var selectOption = document.createElement("option"); selectOption.value = this._fieldOptions[i].Value.toLocaleString(); selectOption.text = this._fieldOptions[i].Label; this._dropdownSelect.appendChild( selectOption ); } }*/ this._notifyOutputChanged = notifyOutputChanged; // Adding the label and button created to the container DIV. this._container = document.createElement("div"); this._container.appendChild(this._dropdownSelect); container.appendChild(this._container); } /** * 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<IInputs>): void { // This method would render the control with the updated values after we call NotifyOutputChanged //set the value of the field control to the raw value from the configured field this._value = context.parameters.inputOptionSet.raw; this.label.value = this._value != null ? this._value.toString(): ""; if(context.parameters.inputOptionSet.error) { this.label.innerHTML = this._value.toString(); this.label.style.backgroundColor = this._colorhexcodesarray[0]; //this.label.classList.add("SimpleIncrement_Input_Error_Style"); } else { this.label.innerHTML = this._value.toString(); this.label.style.backgroundColor = this._colorhexcodesarray[0]; //this.label.classList.remove("SimpleIncrement_Input_Error_Style"); } } /** * 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 { return {}; } /** * 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 } }
Thanks again guys.
Thank you jolake, I thought it was me 🙂 Being unblocked in future when i run into this would be terrific.
Hi Andrew,
The issue is that your property inputColorHexString has no defined usage attribute. Adding a usage value to this property node should unblock you. I've filed a bug internally to make sure future similar issues are caught by the control build process.
WarrenBelz
87
Most Valuable Professional
mmbr1606
71
Super User 2025 Season 1
Michael E. Gernaey
65
Super User 2025 Season 1