Skip to content

Commit 9bae54a

Browse files
Merge pull request #57 from SimplrJS/feature/controlled-mechanism
Controlled mechanism implemented and onChange types for Field and Form updated.
2 parents c6d1a66 + 2ba1e8c commit 9bae54a

File tree

16 files changed

+367
-255
lines changed

16 files changed

+367
-255
lines changed

packages/simplr-forms-dom/package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "simplr-forms-dom",
3-
"version": "4.0.1-alpha.2",
3+
"version": "4.0.1-alpha.3",
44
"description": "DOM components for simplr-forms.",
55
"repository": "SimplrJS/simplr-forms",
66
"homepage": "https://github.com/SimplrJS/simplr-forms",
@@ -47,6 +47,7 @@
4747
"mz": "^2.6.0",
4848
"simplr-mvdir": "0.0.1-beta.7",
4949
"sinon": "^2.2.0",
50+
"source-map-loader": "^0.2.1",
5051
"ts-jest": "^20.0.4",
5152
"ts-loader": "^2.1.0",
5253
"tslint": "^5.2.0",
@@ -57,11 +58,12 @@
5758
"@types/react": "^15.0.24",
5859
"@types/prop-types": "^15.5.1",
5960
"immutable": "^3.8.1",
60-
"simplr-forms": "^4.0.1-alpha.2",
61+
"simplr-forms": "^4.0.1-alpha.3",
6162
"typed-immutable-record": "0.0.6",
6263
"react": "^15.5.4",
6364
"react-dom": "^15.5.4",
64-
"prop-types": "^15.5.8"
65+
"prop-types": "^15.5.8",
66+
"tslib": "^1.7.1"
6567
},
6668
"jest": {
6769
"setupTestFrameworkScriptFile": "./node_modules/jest-enzyme/lib/index.js",

packages/simplr-forms-dom/src/components/text.tsx

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,28 @@ import * as React from "react";
22
import { FieldValue } from "simplr-forms/contracts";
33
import { DomFieldProps } from "../contracts/field";
44

5-
import { BaseDomField, BaseDomFieldState } from "../abstractions/base-dom-field";
6-
import { FieldOnChangeCallback } from "../contracts/field";
5+
import {
6+
BaseDomField,
7+
BaseDomFieldState
8+
} from "../abstractions/base-dom-field";
9+
import {
10+
FieldOnChangeCallback,
11+
FieldOnChangeInternalCallback
12+
} from "../contracts/field";
13+
import {
14+
FormProps
15+
} from "../contracts/form";
16+
17+
export type TextOnChangeCallback = FieldOnChangeCallback<HTMLInputElement>;
718

819
/**
920
* Override the differences between extended interfaces.
10-
*
11-
* @export
12-
* @interface Props
13-
* @extends {CoreContracts.FieldProps}
14-
* @extends {React.HTMLProps<HTMLInputElement>}
1521
*/
1622
export interface TextProps extends DomFieldProps, React.HTMLProps<HTMLInputElement> {
1723
name: string;
1824
onFocus?: React.EventHandler<React.FocusEvent<HTMLInputElement>>;
1925
onBlur?: React.EventHandler<React.FocusEvent<HTMLInputElement>>;
20-
onChange?: FieldOnChangeCallback<HTMLInputElement>;
26+
onChange?: TextOnChangeCallback & FieldOnChangeInternalCallback;
2127
ref?: any;
2228

2329
defaultValue?: FieldValue;
@@ -30,15 +36,25 @@ export class Text extends BaseDomField<TextProps, BaseDomFieldState> {
3036
}
3137

3238
protected OnChangeHandler: React.FormEventHandler<HTMLInputElement> = (event) => {
33-
this.OnValueChange(this.GetValueFromEvent(event));
39+
event.persist();
3440

35-
const newValue = this.FormStore.GetField(this.FieldId).Value;
41+
let newValue: string | undefined;
42+
if (!this.IsControlled) {
43+
this.OnValueChange(this.GetValueFromEvent(event));
44+
newValue = this.FormStore.GetField(this.FieldId).Value;
45+
} else {
46+
newValue = this.GetValueFromEvent(event);
47+
}
3648

3749
if (this.props.onChange != null) {
3850
this.props.onChange(event, newValue, this.FieldId, this.FormId);
3951
}
4052

41-
// TODO: FormProps.OnFieldChange
53+
const formStoreState = this.FormStore.GetState();
54+
const formProps = formStoreState.Form.Props as FormProps;
55+
if (formProps.onChange != null) {
56+
formProps.onChange(event, newValue, this.FieldId, this.FormId);
57+
}
4258
}
4359

4460
protected get RawDefaultValue() {

packages/simplr-forms-dom/src/contracts/field.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@ import {
66
} from "simplr-forms/contracts";
77
import { FormStore } from "simplr-forms/stores";
88

9-
export interface FieldOnChangeCallback<TElement> extends React.EventHandler<React.FormEvent<TElement>> {
10-
(event: React.FormEvent<TElement> | undefined, newValue: FieldValue, fieldId: string, formId: string): void;
9+
export interface FieldOnChangeInternalCallback {
10+
(event: React.FormEvent<any>, ...parameters: any[]): void;
11+
}
12+
13+
export interface FieldOnChangeCallback<TElement> {
14+
(event: React.FormEvent<TElement>, newValue: FieldValue, fieldId: string, formId: string): void;
1115
}
1216

1317
export interface DomFieldProps extends FieldProps {

packages/simplr-forms-dom/src/contracts/form.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,21 @@ import { FormProps as CoreFormProps } from "simplr-forms/contracts";
44
import { FormStore } from "simplr-forms/stores";
55
import {
66
FieldOnChangeCallback,
7+
FieldOnChangeInternalCallback,
78
DomFieldTemplateCallback
89
} from "../contracts/field";
910

10-
export interface FormOnSubmitCallback extends React.FormEventHandler<HTMLFormElement> {
11+
export interface FormOnSubmitInternalCallback {
12+
(event: React.FormEvent<HTMLFormElement>, ...parameters: any[]): void | Promise<never> | FormError | string;
13+
}
14+
15+
export interface FormOnSubmitCallback {
1116
(event: React.FormEvent<HTMLFormElement>, store: FormStore): void | Promise<never> | FormError | string;
1217
}
1318

1419
export interface FormProps extends CoreFormProps, React.HTMLProps<HTMLFormElement> {
15-
onSubmit?: FormOnSubmitCallback;
16-
onChange?: FieldOnChangeCallback<any>;
20+
onSubmit?: FormOnSubmitCallback & FormOnSubmitInternalCallback;
21+
onChange?: FieldOnChangeCallback<any> & FieldOnChangeInternalCallback;
1722
preventSubmitDefaultAndPropagation?: boolean;
1823
template?: DomFieldTemplateCallback;
1924
// tslint:disable-next-line:max-line-length

packages/simplr-forms-dom/tools/webpack.config.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,16 @@ module.exports = {
6262
},
6363
module: {
6464
rules: [
65+
{
66+
enforce: "pre",
67+
test: /\.js$/,
68+
loader: "source-map-loader"
69+
},
70+
{
71+
enforce: "pre",
72+
test: /\.tsx?$/,
73+
use: "source-map-loader"
74+
},
6575
{
6676
test: /\.tsx?$/,
6777
loader: "ts-loader",
@@ -73,5 +83,6 @@ module.exports = {
7383
resolve: {
7484
extensions: [".ts", ".tsx"]
7585
},
76-
externals: externalsResolver
86+
externals: externalsResolver,
87+
devtool: "inline-source-map"
7788
};

packages/simplr-forms-dom/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66
"outDir": "dist",
77
"rootDir": "src",
88
"jsx": "react",
9-
"sourceMap": false,
9+
"sourceMap": true,
1010
"skipDefaultLibCheck": true,
1111
"declaration": true,
1212
"pretty": true,
1313
"strict": true,
14+
"noEmitHelpers": true,
1415
"lib": [
1516
"dom",
1617
"dom.iterable",

packages/simplr-forms-dom/webpack.config.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,16 @@ module.exports = {
5252
},
5353
module: {
5454
rules: [
55+
{
56+
enforce: "pre",
57+
test: /\.js$/,
58+
loader: "source-map-loader"
59+
},
60+
{
61+
enforce: "pre",
62+
test: /\.tsx?$/,
63+
use: "source-map-loader"
64+
},
5565
{
5666
test: /\.tsx?$/,
5767
loader: "ts-loader",
@@ -62,5 +72,6 @@ module.exports = {
6272
resolve: {
6373
extensions: [".ts", ".tsx"]
6474
},
65-
externals: externalsResolver
75+
externals: externalsResolver,
76+
devtool: "inline-source-map"
6677
};

packages/simplr-forms/package.json

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "simplr-forms",
3-
"version": "4.0.1-alpha.2",
3+
"version": "4.0.1-alpha.3",
44
"description": "Shared simplr-forms logic.",
55
"repository": "SimplrJS/simplr-forms",
66
"homepage": "https://github.com/SimplrJS/simplr-forms",
@@ -45,6 +45,7 @@
4545
"react-test-renderer": "^15.5.4",
4646
"simplr-mvdir": "0.0.1-beta.7",
4747
"sinon": "^2.2.0",
48+
"source-map-loader": "^0.2.1",
4849
"ts-jest": "^20.0.4",
4950
"ts-loader": "^2.1.0",
5051
"tslint": "^5.2.0",
@@ -53,18 +54,19 @@
5354
"webpack": "^2.5.1"
5455
},
5556
"dependencies": {
57+
"@types/fbemitter": "^2.0.32",
58+
"@types/flux": "^3.0.1",
59+
"@types/prop-types": "^15.5.1",
60+
"@types/react": "^15.0.22",
61+
"@types/react-dom": "^15.5.0",
5662
"action-emitter": "^0.2.1",
5763
"fbemitter": "^2.1.1",
5864
"immutable": "^3.8.1",
59-
"typed-immutable-record": "^0.0.6",
65+
"prop-types": "^15.5.8",
6066
"react": "15.5.4",
6167
"react-dom": "^15.5.4",
62-
"prop-types": "^15.5.8",
63-
"@types/fbemitter": "^2.0.32",
64-
"@types/flux": "^3.0.1",
65-
"@types/prop-types": "^15.5.1",
66-
"@types/react": "^15.0.22",
67-
"@types/react-dom": "^15.5.0"
68+
"tslib": "^1.7.1",
69+
"typed-immutable-record": "^0.0.6"
6870
},
6971
"jest": {
7072
"setupTestFrameworkScriptFile": "./node_modules/jest-enzyme/lib/index.js",

packages/simplr-forms/src/abstractions/base-field.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,15 @@ export interface BaseFieldState extends CoreFieldState {
99
}
1010

1111
export abstract class BaseField<TProps extends FieldProps, TState extends BaseFieldState> extends CoreField<TProps, TState> {
12+
componentWillReceiveProps(nextProps: FieldProps): void {
13+
super.componentWillReceiveProps(nextProps);
14+
15+
if (this.IsControlled) {
16+
const newValue = this.ProcessValueBeforeStore(this.props.value);
17+
this.FormStore.UpdateFieldValue(this.FieldId, newValue);
18+
}
19+
}
20+
1221
protected abstract get RawDefaultValue(): FieldValue;
1322

1423
protected get RawInitialValue(): FieldValue {
@@ -19,6 +28,29 @@ export abstract class BaseField<TProps extends FieldProps, TState extends BaseFi
1928
return this.props.value;
2029
}
2130

31+
protected get IsControlled(): boolean {
32+
return this.props.value !== undefined;
33+
}
34+
35+
protected get ControlledValue(): FieldValue {
36+
return this.props.value;
37+
}
38+
39+
protected get Value(): FieldValue {
40+
if (this.IsControlled) {
41+
return this.ControlledValue;
42+
}
43+
44+
// If state is defined
45+
if (this.state != null && this.state.Value != null) {
46+
// Return its value
47+
return this.state.Value;
48+
}
49+
50+
// Return default value
51+
return this.RawDefaultValue;
52+
}
53+
2254
protected get Disabled(): boolean | undefined {
2355
// FormStore can only enforce disabling
2456
if (this.FormStore.GetState().Disabled === true) {

packages/simplr-forms/src/abstractions/core-field.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,15 +115,13 @@ export abstract class CoreField<TProps extends CoreFieldProps, TState extends Co
115115
/**
116116
* Is field currently controlled.
117117
*/
118-
protected get IsControlled(): boolean {
119-
return false;
120-
}
118+
protected abstract get IsControlled(): boolean;
121119

122120
/**
123121
* Current or default field value.
124122
*/
125123
protected get Value(): FieldValue {
126-
// If field is defined
124+
// If state is defined
127125
if (this.state != null && this.state.Value != null) {
128126
// Return its value
129127
return this.state.Value;
@@ -133,6 +131,8 @@ export abstract class CoreField<TProps extends CoreFieldProps, TState extends Co
133131
return this.RawDefaultValue;
134132
}
135133

134+
protected abstract get ControlledValue(): FieldValue;
135+
136136
protected ProcessValueBeforeStore(value: FieldValue): FieldValue {
137137
// Parse and normalize value
138138
if (value != null) {

0 commit comments

Comments
 (0)