fcmlib v1.0.99
��# FCM
This library allows you to build flow custom components which target both the default and default-legacy players simultaneously.
It works on the concept that there is a base abstract class definition called FCMCore that defines all the methods & properties.
There are then 2 extension classes to this (FCMLegacy & FCMNew) which handle the interactions with the flow player API's
FCMLegacy converts the legacy manywho javascript library into the FCMCore model.
FCMNew converts the new default player library to the FCMCore model.
To make this all work we implement our actual component in a single TSX file exposing a React.Component<any,any>.
We implement our flow component in 2 files for Core & Legacy.
I use ESBuild to transpile, host and package.
e.g.
'''
package.json File
An example of a package.json file
{
"name": "mycomp",
"version": "1.0.0",
"description": "My Component",
"scripts": {
"start": "esbuild ./src/MyClassNew.tsx --outfile=./build/myclass_ng.js --sourcemap=both --serve=8080 --servedir=build --bundle --format=esm --watch",
"build": "esbuild ./src/MyClassNew.tsx --outfile=./build/myclass_ng.js --minify --bundle --format=esm --target=chrome58,firefox57,safari11,edge16",
"startLegacy": "esbuild ./src/MyClassNewLegacy.tsx --outfile=./build/myclass_leg.js --sourcemap=both --serve=8080 --servedir=build --bundle --format=esm --watch",
"buildLegacy": "esbuild ./src/MyClassNewLegacy.tsx --outfile=./build/myclass_leg.js --minify --bundle --format=esm --target=chrome58,firefox57,safari11,edge16",
"buildAll": "npm run build & npm run buildLegacy"
},
"author": "Boomi",
"license": "MIT",
"dependencies": {
"fcmlib": "^1.0.38",
"react": "18.2.0"
},
"devDependencies": {
"@types/react": "^18.2.28",
"esbuild": "0.19.4"
}
}
tsconfig.json
An example of a package.json file
{
"compilerOptions": {
"outDir": "./build",
"sourceMap": true,
"noImplicitAny": true,
"module": "commonjs",
"target": "es5",
"jsx": "react",
"downlevelIteration": true,
"lib": [
"es2015",
"dom"
],
"skipLibCheck": false,
"esModuleInterop": true
},
"include": [
"./src/**/*"
]
}
Legacy Component Definition (MyClassLegacy.tsx)
import { FCMLegacy } from "fcmlib/lib/FCMLegacy";
import * as React from 'react';
import { _MyClass } from "./MyClass";
declare const manywho: any;
class MyClass extends FCMLegacy {
//FCMCore will trigger this if we should update
redraw() {
// call something on the real component to trigger a redraw
this.childComponent.buildCoreTable();
}
render() {
return(
<_MyClass
parent={this}
ref={(element: any) => {this.childComponent = element}} // here we are giving FCMCore a ref to our component
/>
);
}
}
manywho.component.register('MyClass', MyClass);
New Component Definition (MyClassNew.tsx)
import { FCMNew } from "fcmlib/lib/FCMNew";
import * as React from 'react';
import { _MyClass } from "./MyClass";
export default class CascadingCombos extends FCMNew {
//FCMCore will trigger this if we should update
redraw() {
// call something on the real component to trigger a redraw
this.childComponent.buildCoreTable();
}
render() {
return(
<_MyClass
parent={this}
ref={(element: any) => {this.childComponent = element}} // here we are giving FCMCore a ref to our component
/>
);
}
}
Actual component implementation (MyClass.tsx)
export class _MyClass extends React.Component<any,any> {
component: FCMCore;
constructor(props.any) {
super(props);
this.component = props.props.parent;
}
render() {
let classes: string = 'myclass ' + this.component.getAttribute('classes', '');
const style: CSSProperties = {};
style.width = 'fit-content';
style.height = 'fit-content';
if (this.component.isVisible === false) {
style.display = 'none';
}
if (this.component.getAttribute("width")) {
style.width = this.component.getAttribute("width");
}
if (this.component.getAttribute("height")) {
style.height = this.component.getAttribute("height");
}
return (
<div
className={classes}
style={style}
>
"Hello World"
</div>
);
}
}
Interface
We now have the ability, in the actual component file (MyClass.tsx) to use this.component.xxx to interact with the data delivered to us by Flow and the Flow server side state directly.
Core Properties
id
The component's guid as created by Flow.
label
The component's label string.
contentType
An eContentType enumeration of the state's content type.
contentValue
The component's string state value if the state is a simple type (string, number, dateTime, boolean etc.).
objectData
The component's dataSource as an objectDataArray if the model is an objectData or objectDataArray.
getOriginalStateValue() : string | boolean | number | Date | FlowObjectData | FlowObjectDataArray | undefined
Gets the component's initial state vale as a real converted type.
setStateValue(value: string | boolean | number | Date | FlowObjectData | FlowObjectDataArray)
Sets the component's state value.
stateValue : string | boolean | number | Date | FlowObjectData | FlowObjectDataArray
Gets the current value of the component's state.
The one you last set with setStateValue().
outcomes : Object
An object with each outcome attached to the component keyed on its developer name.
e.g.
let oc: FlowOutcome = this.component.outcomes["OutcomeName"]
or
Object.keys(this.component.outcomes).forEach((key: string) => {
let oc: FlowOutcome = this.component.outcomes[key]
});
async triggerOutcome(outcomeName: string) : Promise
This will trigger the outcome specified by its developerName.
It is await-able.
async getValue(name: string) : Promise
This will make an await-able call to directly get any named value from the current Flow's state.
It directly calls the Flow REST api.
If the value (Named on it's developerName) is not in the state it will throw a silent console error and return a null.
If successful it will return a FlowValue object.
async setValue(FlowValue | FlowValue[])
This will make an await-able call to directly update the FlowValue into the current Flow's state.
It directly calls the Flow REST api.
e.g.
let val: FlowValue = await this.component.getValue("MyValue");
if(val) {
val.value = "Hello World";
//or
val.value = someObjectDataOrArray;
await this.component.setValue(val);
}
async inflateValue(value: string) : Promise
This awaitable function will attempt to extract a part of a Flow value.
We pass it {{MyValue}} or {{MyValue->Property}} or {{MyValue->Property->property}} etc.
It will retrieve the FlowValue "MyValue" if not previously retrieved then iterate down through it's properies to get the indicated one.
Great if you want to pass a complex value in an attribute.
getAttribute(AttributeName, defaultValue) : string;
This will get the value of the named attribute from the component.
If it is not defined then the defaultValue will be returned or null if no default is specified.
e.g.
let myBool: boolean = this.component.getAttribute("myBool","false") === "true";
Others
There are various other component configuration attributes exposed like visibility, developerName, authenticationToken, currentMapElementId and more.
Other Classes
Various other classes are exposed as helpers and Enums.
FlowObjectData
FlowObjectDataArray
FlowDisplayColumn
FlowOutcome
FlowAttribute
FlowValue
eContentType
4 months ago
4 months ago
5 months ago
5 months ago
5 months ago
5 months ago
6 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
8 months ago
8 months ago
9 months ago
9 months ago
11 months ago
11 months ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago