Blog

Custom Controls Framework - Context

– 5 Minutes

As mentioned a previous post, the Custom Controls Framework has a context object which gets passed around that contains a gold-mine of information.  This post will explore some of the properties of the context object that jumped out at me, and provide a type definition file that can be used in your TypeScript development to get IntelliSense.

Properties

It should go without saying that everything below is subject to change.  I did notice that there are some functions in these properties that aren't fully functional yet (e.g. utils.clearNotification).  I think this may be part of the reason Microsoft hasn't released details of the CCF to a wider audience -- they're still finalizing the details!

With that said, here are the properties that jumped out at me.

device

This property contains methods for capturing audio, video, and pictures.  The best part?  You don't have to worry what type/brand of device the user is using!  The implementation details are abstracted away.

device: {
    isGetBarcodeValueOperationAvailable(): boolean;
    getBarcodeValue();
    isCaptureAudioOperationAvailable(): boolean;
    captureAudio();
    isCaptureVideoOperationAvailable(): boolean;
    captureVideo();
    isTakePictureOperationAvailable(): boolean;
    captureImage(options: any);
    getCurrentPosition();
    pickFile(options: any);
};

formatting

Contains functions that can be used to format dates/times, numbers, and currency using the user's culture preferences.  No need to worry about figuring out the users locale/preferences -- these functions take care of it all for you.

formatting: {
    formatDateLong(date: Date): string;
    formatDateLongAbbreviated(date: Date): string;
    formatDateShort(date: Date, includeTime?: boolean): string;
    formatDateYearMonth(date: Date): string;
    formatDateAsFilterStringInUTC(date: Date, includeTime?: boolean): string;
    formatTime(date: Date, timezone?: TimeZone): string;
    formatCurrency(value: number, precision?: number, symbol?: string): string;
    formatDecimal(value: number, precision?: number): string;
    formatInteger(value: number): string;
    formatLanguage(lcid: number): string;
    getWeekOfYear(date: Date): number;
};

Contains function used to create popups and navigate to other areas.  Some of the really cool options are being able to initiate a global search with a specified term, and opening a Task Flow

navigation: {
    openAlertDialog(alertStrings: any, alertOptions?: any);
    openErrorDialog(alertStrings: any, alertOptions?: any);
    openConfirmDialog(alertStrings: any, alertOptions?: any);
    openSearch(term: string);
    openCreateForm(p1: any, p2: any, p3: any);
    openEditForm(p1: any, p2: any, p3: any, p4: any, p5: any);
    openDashboard(dashboard: string);
    openFile(file: any, options: any);
    openForm(p1: any, p2: any);
    openGrid(p1: any, p2: any, p3: any, p4: any, p5: any, p6: any);
    openMap(p1: any);
    openMaps(p1: any);
    openPhoneNumber(p1: any);
    openTaskFlow(name: string, options: any, data?: any);
    openUrl(p1: any, p2: any);
    openUrlWithProtocol(p1: any, p2: any);
    openWebResource(name: string, options: DialogOptions, data?: any);
}

Note: I'm still trying to sort out some of the parameters for these functions.

utils

Contains two function to set and clear notifications (i.e. errors) on your control.

utils: {
    setNotification(message: string, id: string): void;
    clearNotification(id: string): void;
}

parameters

And finally, the most important one, parameters.  So far we've only focused on raw and formatted, but there are a few other properties worth mentioning.  For example, attributes.  If the parameter is bound to a field, attributes will contain data about how the user has configured the field in their environment.  For example, on a number field, you will have access to the min/max values.  Another is security -- this contains information related to security roles/field security profiles.  

parameters: {
    [name: string]: {
        type: string,
        error: boolean;
        errorMessage?: string;
        raw: any;
        formatted?: string;
        security?: {
            editable: boolean,
            readable: boolean,
            secured: boolean
        },
        attributes?: {
            Behavior?: string;
            DefaultValue?: string;
            Description?: string;
            DisplayName?: string;
            EntityLogicalName?: string;
            Format?: string;
            ImeMode?: number;
            IsSecured?: boolean;
            LogicalName?: string;
            MaxLength?: number;
            MaxValue?: number;
            MinValue?: number;
            Options?: any;
            Precision?: number;
            RequiredLevel?: number;
            SourceType?: number;
            Targets?: any;
            Type?: string;
        },
        notifications?: Array;
    }
};

Type Definition

Up to this point, we have been creating our TypeScript file with all of the types implicitly set to any.  While this works, it defeats the purpose of using TypeScript!  To fix this, we can define a type definition file (.d.ts) which includes the definitions of every property on the context variable.  If you reference the type definition file in your control file, you will get IntelliSense which should make it much easier to develop a custom control!

You just need to add the following to the top of the file...

/// <reference path="./types/FieldControls.d.ts" />

...and then you can compile the TypeScript file with the -noImplicitAny switch without any warnings/errors.

tsc -noImplicitAny PercentageControl.ts

You can find an updated Percentage Control solution which includes the type definition file here: CustomControls_1_0_0_5.zip.  The definition file is a work in progress.  I'll be improving it over the coming weeks as I explore some more.

Comments

Javed Maner

Hi Bob,

Thanks for sharing this custom control example. I imported this solution. It works fine in google chrome but it does not work in IE11. Can you please suggest any solution for this?