Formbird Component Development
Using the github codespace functionality we can now create and edit components through Github and Visual Studio Code Online. Component development can now be performed from within the browser with component updates only a refresh away. Makes it much easier for setup of accounts, key and environment management for new users.
Create Codespace
Open Formbird formbird-sc-components github here:
Navigate to the desired branches: either angular-starter or react-starter
Create the codespace environment
Click the green Code
Select the codespaces tab
Click the dropdown on right of Create codespace on angular
Select Configure and create codespace
Change machine type from 2-core to 4-core
Click Create codespace
Allow codespace to open. Once the page is loaded
Once the page is loaded open terminal by...
Ctrl `
Set up Environments
Now we want to set up the enironment as you would a local one.
To set up the dependencies.
yarnIf you have any issues try
yarn cache clean
Next time you want to use the environment you can simply navigate to the codespaces dropdown in formbird-sc-components and select from your codespaces
Running the environment
This is if you want to locally host the component. The main issue with this is you cannot select one component and this process runs only items packaged in sc-components. Some components are starting to be removed.
Once the environment is set up should just be able to run the following:
yarn serve
Navigate to PORTS
next to TERMINAL
. Either open the local address in another window or browser alltogether.
I use another browser altogether as to allow for easy cache deletes.
This url will be similar to below which can then be provided to component template in formbird. The only downside to this is uses a local url so the component cannot be shared with others.
eg. https://formbird-formbird-sc-components-...-4200.githubpreview.dev/...
Note you may have to change the port visibility to Private to Organisation or Public
To do this navigate to terminal in codespace.
In the TERMINAL window, click on PORTS tab.
Right click and select port visibility.
Change to desired setting
Setting up cdn-deployer in Codespaces
In order to have your component hosted 24/7 and so others can see/use it we can use the formbird cdn server.
We want to copy the directory
/workspaces/codespace-components/dist/...
into the cdn. We do this by running...
cdn-deployer -p projectName -s 'suffix' /path-to-dist/
eg. cdn-deployer -p sc-signature-new -s 0.0.1 ./dist/sc-signature/
To save new changes to the CDN we need to compile the distribution using
npx ng build sc-signature
You can add to the end the --watch
command to enable constant build updates for the distribution.
To verify your changes visit https://cdn.formbird.com/components/
Creating a new component
Two things need to be created, a hosted angular component and a component document.
Angular component creation
We will be using codespace-components for the following...
Angular component creation under formbird sc-components
Open Formbird formbird-sc-components github here:
And create a codespaces using the steps from above.
Here we will create an angular component sc-time
Create branch in formbird-sc-components and create new component dir in projects.
cd projects
mkdir sc-time
cd sc-time
npx ng g application sc-time
Use all the defaults when generating. Remove the unnecessary documents in /src/app/ except app.module.ts
Next, generate the sc-time module and component (tend to omit the sc-)
cd src/app/
npx ng g module time --module=./app.module.ts
npx ng g component time --module=./time/time.module.ts
Again use the suggested defaults. Only major choice should be whether to use css or scss. Chose whatever styling format you are more comfortable with. You should now have following files in app/time/...
Open app.module.ts and delete AppComponent. For layout I have used sc-signature. app.module.ts is shown below for sc-time.
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import {CommonModule} from '@angular/common';
import { TimeModule } from './time/time.module';
@NgModule({
declarations: [
],
imports: [
CommonModule,
BrowserModule,
TimeModule
],
providers: [],
})
export class AppModule {
constructor() {}
// ngDoBootstrap needs to do nothing when exporting custom elements so that the normal Angular app bootstrap doesn't take place
ngDoBootstrap() {}
}
Navigate to time.module.ts and setup for basic implementation for a custom element component is as follows. Also check that time.component.ts has been imported in the time.module.ts
import { CUSTOM_ELEMENTS_SCHEMA, Injector, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import {FormbirdScSharedModule} from '../../../../formbird-sc-shared/src/lib/formbird-sc-shared.module';
import {FormbirdServicesModule} from '@formbird/services';
import {CustomElementService} from '../../../../formbird-sc-shared/src/lib/services/custom-element.service';
import {ClientConstants} from '../../../../formbird-services/src/lib/constants/ClientConstants';
import { default as pjson } from '../../../../../package.json';
import { TimeComponent } from './time.component';
@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
declarations: [
TimeComponent
],
imports: [
CommonModule,
FormbirdServicesModule
],
entryComponents: [
TimeComponent
]
})
export class TimeModule {
constructor(private injector: Injector, private customElementService: CustomElementService) {
customElementService.convertToCustomElement(TimeComponent, 'sc-time', this.injector,
ClientConstants.ANGULAR_COMPONENT_SUFFIX, pjson.version);
}
}
Now we are going to leave the ts and html files (time.component.ts and time.component) alone for the moment while we verify the component has been setup correctly. As it is a web component we need to delare webpack in angular.json.
Navigate to angular.json
in the home dir and the section for sc-time should be appended at the bottom of the document. Change the builder section to below under "architect": { ....
...
"architect": {
"build": {
"builder": "@angular-builders/custom-webpack:browser",
"options": {
"customWebpackConfig": {
"path": "projects/sc-time/extra-webpack.config.js",
"mergeStrategies": {
"externals": "replace"
}
},
...
Also change prefix to "sc".
Also in angular.json we need to change the production build config to turn off hashing. Other configs can be left but for simplicity sake, I have added other paramaters. See ng build config file documentation for more info.
...
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"fileReplacements": [
{
"replace": "projects/sc-time/src/environments/environment.ts",
"with": "projects/sc-time/src/environments/environment.prod.ts"
}
],
"outputHashing": "none",
"optimization": true,
"sourceMap": false,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true
},
...
After this we need to create the extra-webpack.config.js file. We can either copy from below or from another project. I just declared using the text below. Make sure it is a unique name in the output. eg. uniqueName: 'wpScTimeComponentJsonp'
module.exports = {
output: {
uniqueName: 'wpScTimeComponentJsonp'
},
externals: {}
};
External libraries that are supported within are included below. Unless you specifically require a package, leave the externals package empty.
const externals = {
'rxjs': 'rxjs',
'rxjs/operators': 'rxjs.operators',
"redux": "Redux",
"jquery": "jQuery",
"jsonpath": "jsonpath",
"dexie": "Dexie",
"uuid": "uuid",
"handlebars": "Handlebars",
"async": "async",
"lodash": "_",
"loadjs": "loadjs",
"socket.io-client": "io",
"notyf": "Notyf",
"immer": "immer",
"rfc6902": "rfc6902",
// "@formbird/types": "formbird.types",
// "@formbird/shared": "formbird.shared",
// "@formbird/services": "formbird.services",
// "zone.js": "zone.js"
};
Out final step is setting up the component.ts file. We need to extend ComponentDefinitions, add in angular encapsulation and changeDetection. See Angular-CLI for more details on this.
eg.
import {
AfterContentChecked,
AfterViewInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component, ElementRef,
Input, OnDestroy,
OnInit, Output, Renderer2, ViewChild,
ViewEncapsulation, EventEmitter
} from '@angular/core';
import {ComponentDefinition, FormComponent, FormDocument, FormTemplate} from '@formbird/types';
import {UtilDocumentIdService} from '../../../../formbird-sc-shared/src/lib/util-document-id.service';
import { ChangedDocumentService, FormbirdInjectorService } from "@formbird/services";
import {
AbstractComponent,
ComponentSetupService
} from "@formbird/angular-shared";
interface TimeComponentDef extends ComponentDefinition {
use24hrTime: boolean;
}
@Component({
selector: 'sc-time',
templateUrl: './time.component.html',
styleUrls: ['./time.component.css'],
encapsulation: ViewEncapsulation.ShadowDom,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class TimeComponent extends AbstractComponent<TimeComponentDef> implements FormComponent, OnInit, AfterViewInit {
notificationService: any;
fileProviderService: any;
constructor(
protected formbirdInjectorService: FormbirdInjectorService,
protected cdRef: ChangeDetectorRef,
private el: ElementRef,
protected changedDocumentService: ChangedDocumentService,
protected componentSetupService: ComponentSetupService,
private utilService: UtilDocumentIdService
) {
super(formbirdInjectorService, changedDocumentService, componentSetupService, cdRef);
this.fileProviderService = this.formbirdInjectorService.get('FileProviderService');
this.notificationService = this.formbirdInjectorService.get('NotificationService');
}
ngOnInit(): void {
this.componentSetupService.setupStandardProperties(this);
}
ngAfterViewInit(): void {
}
}
Next generate the output package. And deploy to cdn.formbird. Try use the /dev path along with the mantis ID for development tracking
cd /workspaces/formbird-sc-components/
npx ng build sc-time
cdn-deployer -p dev -s version1 ./dist/sc-time
You will see in the terminal cdn_url. For me it is cdn_url="https://cdn.formbird.com/components/dev/sc-time/version1" but yours will be slightly different. Take note of this as we will be using it later.
Formbird component document creation
In this section we will be creating a formbird component document with the required information. This section builds on the previous angular component section.
Navigate to the component editor in comp-dev-ng or your chosen environment.
Add in component name. For this example we will be creating sc-time. Add in a version control comment (I use the mantis ID that I'm working off). Now save the component.
Now either click the + symbol on the right of the External Component Library Documents section. This will take you to the External Component Library Reference page. Here we need to define four files which correspond with the build files from an angular component. These are main.js, runtime.js, polyfills.js & styles.css.
Add in a unique library name like scTestDevCDNMain
, V1 for version and other fields. Now in the Relative Library Path
section, add in the URL. If you are serving locally as discussed in the Running the environment section use that url followed by /main.js or others. Otherwise if you are going to use cdn.formbird use a unique cdn_url as per the previous section. You will need to add /componentName/main.js to the end.
eg. https://cdn.formbird.com/components/dev/componentName/V1/componentName/main.js
Repeat this for the runtime.js, polyfills.js & styles.css.
An alternative method is opening the component document with the template editor, and adding in the following object to the document:
"vendorLibrariesRel": [
{
"documentId": "b588d7a0-3f93-11ed-9658-ed22533e38ef",
"name": "CdnFormbirdScPdfRunTime",
"fileName": "https://cdn.formbird.com/components/dev/sc-time/V1/sc-time/runtime.js"
},
{
"documentId": "fb3ee960-3f93-11ed-a487-3918e3084e5e",
"name": "CdnFormbirdScPdfPolyfills",
"fileName": "https://cdn.formbird.com/components/dev/sc-time/V1/sc-time/polyfills.js"
},
{
"documentId": "23d5fe90-3f94-11ed-a487-3918e3084e5e",
"name": "CdnFormbirdScPdfStyles",
"fileName": "https://cdn.formbird.com/components/dev/sc-time/V1/sc-time/styles.css"
},
{
"documentId": "51073550-3f94-11ed-a487-3918e3084e5e",
"name": "CdnFormbirdScPdfMain",
"fileName": "https://cdn.formbird.com/components/dev/sc-time/V1/sc-time/main.js"
}
]
You can see an extra jquery field. Most components at the moment require this so lets just add it in anyways.
Next create a new template with the component you want to make. This will be our component testing document going forward so give it a summary name like sc-time testing document. Save and then add in the component like so...
"components": [
{
"componentName": "sc-time",
"name": "testTime"
}
]
Copy the document URL into the Component Test Document url section so we can easily access it later.
If you havent created the angular component and done everything correctly with a bit of luck we should see the default HTML for sc-time which is...
<p>time works!</p>
You have now successfully created your own formbird angular component.
sc-signature example
Navigate to the component editor.
Fill in required fields. eg. sc-example-comp
Open component document with JSON Editor eg. sc-example-comp in editor
You will need to add in "vendorLibrariesRel" with the link from your codespace.
You can see an extra jquery fie
"vendorLibrariesRel": [
{
"documentId": "e0891af0-11a1-11ea-a2a7-3fcf29a30a67",
"name": "formbirdAngularElementsRunTime",
"fileName": "https://formbird-formbird-sc-components-v6jr44wv6cp4pp-4200.githubpreview.dev/runtime.js"
},
{
"documentId": "0eee3cd0-11ad-11ea-b910-89ec432b92ba",
"name": "formbirdAngularElementsPolyfills",
"fileName": "https://formbird-formbird-sc-components-v6jr44wv6cp4pp-4200.githubpreview.dev/polyfills.js"
},
{
"documentId": "41352dc0-11ad-11ea-b910-89ec432b92ba",
"name": "formbirdAngularElementsStyles",
"fileName": "https://formbird-formbird-sc-components-v6jr44wv6cp4pp-4200.githubpreview.dev/styles.css"
},
{
"documentId": "d51355d0-11ad-11ea-b910-89ec432b92ba",
"name": "formbirdAngularElementsMain",
"fileName": "https://formbird-formbird-sc-components-v6jr44wv6cp4pp-4200.githubpreview.dev/main.js"
}
],
Using Codespace with formbird.com
New angular components can use the simplified component template setup which uses the default page template definition
Start by navigating to the codespace directory
formbird-sc-components/projects
Locate the component that requires development. If you are creating a new one seek Michaels help.
eg. sc-signature
Next find the src app code
sc-signature/src/app/signature
In signature.module.ts under class add a new custom element field which allows the formbird api to reference the application using the name you provide. Note we will be hosting the component as sc-signature-new to avoid conflicts with previous version.
eg. customElementService.convertToCustomElement(SignatureComponent, 'sc-signature-new', this.injector, ClientConstants.ANGULAR_COMPONENT_SUFFIX, pjson.version);
Open comp-dev-ng - Template Editor Add relevant details to template. Note can use component editor to create component.
{
{
**"name": "sc-signature-new",
"componentHtml": "",
"fieldWatchFunction": "",
"componentLoadFunction": "",
"systemHeader": {
"systemType": "component",
"templateId": "5f6000a0-0828-11e6-9b64-1b27992111e1",
"createdWith": "5f6000a0-0828-11e6-9b64-1b27992111e1",
"currentVersion": true,
"summaryName": "sc-signature-new",
"keyIds": [],
"createdDate": "2022-07-28T05:23:51.192Z",
"createdBy": "599f95d0-936a-11ec-b26d-7da72dab73ce",
"documentCreatedDate": "2022-07-27T07:43:41.136Z",
"documentCreatedBy": "540e51dd83fb24502699c93f",
"versionId": "770f9980-0e35-11ed-9977-79b0183037a9",
"serverUpdatedDate": "2022-07-28T05:23:50.778Z",
"serverCreatedDate": "2022-07-28T05:23:50.778Z",
"previousVersionId": "53e05620-0e35-11ed-9977-79b0183037a9"
},
"documentId": "acda2aa0-0d7f-11ed-ab35-db46d5f5bdd1",
"versionInfo": "ANGULAR_COMPONENT_RELEASE",
"appTags": [
"system",
"components",
"componentDefinition"
],
"componentTestUrlLink": "/form/2504aeb0-7448-11e6-949c-9f3b8c69d8b6",
"versionNumber": "7.0",
"componentDescription": "####Configuration Fields\n| Field | Values | Default (if not present) | Details | \n | ---- | ---- | ---- | ---- | \n | name |` values `| not-set | description |\n####Description\nAllows a signature or screen writing to be captured",
"restfulWebServiceFunctions": "",
"serverPreprocessorFunction": "",
"componentCleanupFunction": "",
"vendorLibrariesRel": [
{
"documentId": "ef1dbb2d-2c0e-4f1c-a42d-77c1562be6b2",
"name": "formbirdAngularElementsStylesProdCDN",
**"fileName": "https://formbird-formbird-sc-components-....githubpreview.dev/styles.css"**
},
{
"documentId": "58d8730c-3ff6-4856-9401-0c15f42f4455",
"name": "formbirdAngularElementsRunTimeProdCDN",
**"fileName": "https://formbird-formbird-sc-components-....githubpreview.dev/runtime.js"**
},
{
"documentId": "abaaad2b-90fd-4b7b-b767-792b85dfb93f",
"name": "formbirdAngularElementsPolyfillsProdCDN",
**"fileName": "https://formbird-formbird-sc-components-....githubpreview.dev/polyfills.js"**
},
{
"documentId": "7b431aa0-0173-4cdc-ba74-c6c729f03e91",
"name": "formbirdAngularElementsMainProdCDN",
**"fileName": "https://formbird-formbird-sc-components-....githubpreview.dev/main.js"**
}
],
"compDevTestUrlLink": "/form/2504aeb0-7448-11e6-949c 9f3b8c69d8b6"
}
In the case of sc-signature-new all we have to do now to host the component is ensure the codespace environment is running and we change the 4 filename prefixes to our github url inside the vendorLibrariesRel object.
eg. filename: https://formbird-formbird-sc-components-....githubpreview.dev/
sc-signature-new documents for reference
Signature example template: https://comp-dev-ng.formbird.com/form/2720cf30-0d80-11ed-9b16-af366aef3293
Component template: https://comp-dev-ng.formbird.com/form/acda2aa0-0d7f-11ed-ab35-db46d5f5bdd1/74746c80-8378-11e6-99b1-71ee944cf59f
Useful Notes
- Hosting your component on a formbird template with other components causes load and class errors. There are two ways to get around this. In your codespace under
project/sc-components/src/app/app.module.ts
comment out all components except yours. Alternatively, the error is generated when the core tries to fetch components that are in both your codespace and in the normal component directory. We can get around this by only fetching from ours by adding the four URLs we added to the component template document to the vendour libraries object in our working template.