Juan Stoppa
Software Engineer - Wealth Dynamix
@juanstoppa
Building
Forms
@juanstoppa
@juanstoppa
Ngrx
FormQL
Reactive forms
Dynamic component loader
GraphQL
@juanstoppa
@juanstoppa
Component
Component
Section
Page
Page
Layout
Section
Form Metadata
Form Metadata
@juanstoppa
Component
Component
Section
Page
Page
Layout
Section
FormControl
FormControl
FormGroup
FormGroup
FormGroup
FormGroup
FormGroup
Ngrx
Component
Form Metadata
RF FormGroup
Store dictates validation rules with new state
FormGroup applies validation rules from new state
@juanstoppa
{
formStore: {
form: {
layoutComponentName: 'FormLayoutDefaultComponent',
pages: [
{
sections: [
{
components: [
{
schema: 'contact.firstName',
key: 'firstName',
label: 'First name',
componentName: 'TextboxReactiveComponent',
type: 'textbox',
order: 1,
position: {
column: '4.1',
order: 0
},
componentId: 'f3ba55e9-20b3-db67-2099-22a9108bcd47',
value: 'Joe'
},
{
schema: 'contact.firstName',
key: 'lastName',
label: 'Last Name',
componentName: 'TextboxReactiveComponent',
type: 'textbox',
order: 1,
position: {
column: '4.2',
order: 0
},
componentId: '0af1e87f-09fe-e6e0-80ca-f1d512b889ec',
value: 'Joe'
}
],
structure: '4-4-4',
position: {
column: '12.1',
order: 0
},
sectionId: '5d3fcbe3-a029-ca5e-4791-9666155fff0f',
headerStyle: {
'font-size': '1.2rem',
'padding-bottom': '.5rem',
'border-bottom': '2px solid #000',
'margin-bottom': '10px'
},
sectionName: 'Header 1'
},
{
components: [
{
schema: 'contact.lastName',
key: 'lastName',
label: 'Last Name',
componentName: 'TextboxReactiveComponent',
type: 'textbox',
order: 1,
position: {
column: '12',
order: 0
},
componentId: 'b31ce3ce-a329-fc4b-15e9-208eeece91be',
value: 'Black'
}
],
structure: '12',
position: {
column: '6.1',
order: 0
},
sectionId: '098ba7f6-94e3-00ee-23c3-ff803cb68400',
headerStyle: {
'font-size': '1.2rem',
'padding-bottom': '.5rem',
'border-bottom': '2px solid #000',
'margin-bottom': '10px'
},
sectionName: 'Header 2'
},
{
components: [
{
schema: 'contact.mobile',
key: 'firstName',
label: 'Mobile',
componentName: 'TextboxReactiveComponent',
type: 'textbox',
order: 1,
position: {
column: '3.1',
order: 0
},
componentId: 'bb22abb9-0fd0-fa7b-ff0a-50e2c2031970',
value: '076666666666',
conditions: {}
},
{
schema: 'contact.email',
key: 'firstName',
label: 'Email2',
componentName: 'TextboxReactiveComponent',
type: 'textbox',
order: 1,
position: {
column: '6',
order: 0
},
componentId: '776bd62b-b83a-9b67-43b9-03cf7daa2dcb',
value: 'joe.back@nomyemail.com'
}
],
structure: '6-3-3',
position: {
column: '6.2',
order: 0
},
sectionId: '81e907b9-b6e5-fe27-d9fe-aaec2de37541',
headerStyle: {
'font-size': '1.2rem',
'padding-bottom': '.5rem',
'border-bottom': '2px solid #000',
'margin-bottom': '10px'
},
sectionName: 'Header 3'
},
{
components: [
{
schema: 'contact.firstName',
key: 'lastName',
label: 'First Name',
componentName: 'TextboxReactiveComponent',
type: 'textbox',
order: 1,
position: {
column: '12',
order: 0
},
componentId: '9ae93aff-abb9-ca20-c907-73302e92f94b',
conditions: {},
value: 'Joe'
}
],
structure: '12',
position: {
column: '12.2',
order: 0
},
sectionId: '8d1156fe-484d-7cce-4c38-8c97e022d3e2',
headerStyle: {
'font-size': '1.2rem',
'padding-bottom': '.5rem',
'border-bottom': '2px solid #000',
'margin-bottom': '10px'
},
sectionName: 'Header 4'
}
],
structure: '12/6-6/12',
pageId: 'f83c2ca3-1259-aa95-e817-61321a04713d'
}
]
}
}
How can we easily change the form definition?
FormQL has a Form Editor!
@juanstoppa
Ngrx store
Data
Form
2
Form
Groups
Components
3
4
Initial state is loaded in the store using side effects
Form Groups recalculated with new state
Components
GraphQL Server
1
Dispatch [form] load action
FormQL
@juanstoppa
Ngrx store
Data
Form
1
2
3
Keystroke detected
dispatch component update action
Form, Data & Components
state is recalculated
Form Groups
recalculated with new state
Components
Form
Groups
Components
4
FormQL
@juanstoppa
View Mode
Edit Mode
Live Edit Mode
Editing Data
Editing Form Metadata
Editing Data
& Form Metadata
@juanstoppa
FormQL
Angular App
Layouts
Sections
Pages
Components
Validators
NGRX Store
GraphQL Service
Custom components
Custom layouts
Custom components
Custom Validators
Loaded using dynamic component loader
@juanstoppa
@juanstoppa
export class MyCustomComponent implements ControlValueAccessor {
static componentName = 'MyCustomComponent';
static validators = [
<ComponentValidator> {
name: "CustomValidator",
validator: CustomValidator,
key: "customValidator"
}
];
@Input() field: FormComponent<any>;
@Input() reactiveFormGroup: FormGroup;
Validators to apply
to this field
Component Name to support prod builds
@juanstoppa
Single store (Apollo Client)
Feedback
Angular Material CDK
RESTful api support
@juanstoppa
Use what works best for you and your team!
Ngrx as one source of truth
Reactive forms FTW
Dynamic component loader for extending
GraphQL to cherry pick your data
@juanstoppa
@formql_io