Skip to content
This repository has been archived by the owner on Nov 29, 2022. It is now read-only.

Commit

Permalink
[frontend-typescript] simple working example of forms
Browse files Browse the repository at this point in the history
  • Loading branch information
jackinf committed Nov 21, 2017
1 parent dfd26a8 commit 7354f01
Show file tree
Hide file tree
Showing 11 changed files with 311 additions and 5 deletions.
4 changes: 4 additions & 0 deletions idontknow.web.ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@types/react-dom-factories": "^1.0.0",
"@types/redux-form": "^7.0.9",
"antd": "^2.13.9",
"axios": "^0.17.1",
"history": "^4.7.2",
"node-sass-chokidar": "^0.0.3",
"npm-run-all": "^4.1.2",
"react": "^16.0.0",
"react-dom": "^16.0.0",
"react-dom-factories": "^1.0.2",
"react-loadable": "^5.3.1",
"react-redux": "^5.0.6",
"react-router": "^4.2.0",
Expand All @@ -18,6 +21,7 @@
"react-scripts-ts": "2.8.0",
"redux": "^3.7.2",
"redux-devtools": "^3.4.0",
"redux-form": "^7.1.2",
"redux-thunk": "^2.2.0"
},
"scripts": {
Expand Down
5 changes: 4 additions & 1 deletion idontknow.web.ts/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import HomeRoute from './routes/Home';
import {LoginRoute} from './routes/Auth';
import BloggingRoute from './routes/Blogging';
import CounterRoute from './routes/Counter';
import DemoFormRoute from './routes/DemoForm';
import asyncComponent from './components/asyncComponent';

const { Header, Footer, Content } = Layout;
Expand All @@ -38,7 +39,8 @@ class AppComponent extends React.Component {
<Menu.Item key="1"><Link to="/">Home</Link></Menu.Item>
<Menu.Item key="2"><Link to="/blogging">Blogging</Link></Menu.Item>
<Menu.Item key="3"><Link to="/counter">Counter</Link></Menu.Item>
<Menu.Item key="4"><Link to="/login">Login</Link></Menu.Item>
<Menu.Item key="4"><Link to="/demo-form">Demo Form</Link></Menu.Item>
<Menu.Item key="5"><Link to="/login">Login</Link></Menu.Item>
</Menu>
</Header>
<br/>
Expand All @@ -47,6 +49,7 @@ class AppComponent extends React.Component {
<Route exact={true} path="/" component={HomeRoute}/>
<Route path="/blogging" component={asyncComponent(() => BloggingRoute(store))}/>
<Route path="/counter" component={asyncComponent(() => CounterRoute(store))}/>
<Route path="/demo-form" component={asyncComponent(() => DemoFormRoute(store))}/>
<Route path="/login" component={LoginRoute}/>
</div>
</Content>
Expand Down
6 changes: 4 additions & 2 deletions idontknow.web.ts/src/config/reducers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { combineReducers } from 'redux';
import {combineReducers, Reducer} from 'redux';
import {reducer as formReducer} from "redux-form";

export default function createReducer(asyncReducers: any) { // TODO: fix any
export default function createReducer(asyncReducers: Reducer<any>) {
return combineReducers({
form: formReducer,
...asyncReducers
});
}
45 changes: 45 additions & 0 deletions idontknow.web.ts/src/routes/DemoForm/DemoForm.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import * as React from "react";
import {reduxForm, Field, InjectedFormProps} from "redux-form";
import {Button} from "antd";
// import {initialize} from "redux-form";

interface SimpleDemoFormProps {
foo: string;
test: string;
}

const SimpleDemoFormName: string = 'simpleDemoForm';
class SimpleDemoForm extends React.Component<InjectedFormProps<SimpleDemoFormProps>> {
resetForm = () => {
this.props.initialize({test: "test123"});
// initialize(SimpleDemoFormName, {test: "test123"}); // this is alternative way
};

render() {
const {} = this.props;

return (
<div>
Simple demo form

<Button onClick={this.resetForm}>
Reset form
</Button>

<Field
name='foo'
component='input'
placeholder='Foo bar'
/>
<Field
name='test'
component='input'
placeholder='Foo bar'
/>

</div>
)
}
}

export default reduxForm({form: SimpleDemoFormName })(SimpleDemoForm);
13 changes: 13 additions & 0 deletions idontknow.web.ts/src/routes/DemoForm/DemoForm.container.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import {connect} from 'react-redux';
import DemoFormComponent from './DemoForm.component';

const mapDispatchToProps = {
onIncrement: () => (dispatch: any) => dispatch({ type: 'INCREMENT' }),
onDecrement: () => (dispatch: any) => dispatch({ type: 'DECREMENT' }),
};

const mapStateToProps = (state: any) => ({

});

export default connect(mapStateToProps, mapDispatchToProps)(DemoFormComponent)
10 changes: 10 additions & 0 deletions idontknow.web.ts/src/routes/DemoForm/DemoForm.reducer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
interface DemoFormReducerAction {
type: string;
}

export default (state = {}, action: DemoFormReducerAction) => {
switch (action.type) {
default:
return state;
}
}
188 changes: 188 additions & 0 deletions idontknow.web.ts/src/routes/DemoForm/Examples.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
import * as React from 'react';
import {Component, MouseEventHandler} from 'react';
// import { Action } from 'redux';
import {
Field, GenericField, reduxForm,
// WrappedFieldProps,
BaseFieldProps, FormProps, FormAction, actionTypes, reducer,
// ConfigProps,
InjectedFormProps
} from "redux-form";
import { input } from 'react-dom-factories';

// TODO: tests fail in TypeScript@next when strictFunctionTypes=true

interface CustomComponentProps {
customProp: string;
meta: { touched: boolean }
}

class CustomComponent extends Component<BaseFieldProps & CustomComponentProps> {
render() {
const {
// input,
meta : { touched },
customProp
} = this.props;

return (
<div>
<span>{customProp}</span>
<p>Field: {touched ? 'touched' : 'pristine'}</p>
<input {...input} />
</div>
);
}
}

class CustomField extends Component<BaseFieldProps & CustomComponentProps> {
render() {
const { customProp, name, meta } = this.props;
const F = Field as new () => GenericField<CustomComponentProps>;
return <F
component={CustomComponent}
customProp={customProp}
name={name}
meta={meta}
/>;
}
}

export interface FormData {
foo: string;
custom: string;
}

// const config1: ConfigProps<FormData, {}> = {
// form: 'myForm'
// };
// @reduxForm<FormData, {}>(config1)
class MyForm extends Component<InjectedFormProps<any, any>> {
render() {
return (
<div>
<Field
name='foo'
component='input'
placeholder='Foo bar'
/>
<CustomField
name='custom'
customProp='Hello'
meta={{touched: false}}
/>
</div>
);
}
}
export const MyFormWrapped = reduxForm({form: "myForm"})(MyForm);

const MyStatelessFunctionalComponent: React.SFC<any> = () => <div/>;

reduxForm({
form: 'mySFCForm'
})(MyStatelessFunctionalComponent);

class MyReusableForm extends Component<InjectedFormProps<{}, {}>> {
render() {
return (
<div>
<Field
name='foo'
component='input'
placeholder='Foo bar'
/>
</div>
);
}
}
export const MyReusableFormWrapper = reduxForm({form: "myForm"})(MyReusableForm);

reduxForm({
form: 'forceUnregisterOnMountForm',
forceUnregisterOnUnmount: true
});

// adapted from: http://redux-form.com/6.0.0-alpha.4/examples/initializeFromState/


export interface DataShape {
firstName: string;
}

// interface Props extends FormProps<DataShape, {}, {}> {}

interface TestProps {
reset: MouseEventHandler<HTMLButtonElement>;
submitting: boolean;
handleSubmit: MouseEventHandler<HTMLFormElement>;
pristine: boolean;
}
export let InitializeFromStateFormFunction = (props: FormProps & TestProps) => {
const { handleSubmit, pristine, reset, submitting } = props;
return (
<form onSubmit={handleSubmit}>
<div>
<label>First Name</label>
<div>
<Field name="firstName" component={input} type="text" placeholder="First Name"/>
</div>
</div>
<div>
<button type="submit" disabled={pristine || submitting}>Submit</button>
<button type="button" disabled={pristine || submitting} onClick={reset}>Undo Changes</button>
</div>
</form>
);
};

// // Decorate with reduxForm(). It will read the initialValues prop provided by connect()
// const DecoratedInitializeFromStateFormFunction = reduxForm({
// form: 'initializeFromState' // a unique identifier for this form
// })(InitializeFromStateFormFunction);

// // You have to connect() to any reducers that you wish to connect to yourself
// const ConnectedDecoratedInitializeFromStateFormFunction = connect(
// state => ({
// initialValues: state.account.data // pull initial values from account reducer
// }),
// )(DecoratedInitializeFromStateFormFunction);
//
// // React ComponentClass instead of StatelessComponent
//
// class InitializeFromStateFormClass extends React.Component<FormProps & TestProps & DispatchProp<any>> {
// render() {
// return InitializeFromStateFormFunction(this.props);
// }
// }
//
// // Decorate with reduxForm(). It will read the initialValues prop provided by connect()
// const DecoratedInitializeFromStateFormClass = reduxForm<DataShape, {}>({
// form: 'initializeFromState' // a unique identifier for this form
// })(InitializeFromStateFormClass);
//
// // You have to connect() to any reducers that you wish to connect to yourself
// const mapStateToProps = (state: any) => ({
// initialValues: { firstName: state.account.data.firstName } // pull initial values from account reducer
// } as {initialValues?: Partial<DataShape>});
// const ConnectedDecoratedInitializeFromStateFormClass = connect(mapStateToProps)(DecoratedInitializeFromStateFormClass);

reducer({}, {
type: 'ACTION'
});

reducer.plugin({
myform: (state: any, action: FormAction) => {
if (action.type === actionTypes.CHANGE && action.meta.form === 'securitySettings') {
return {
...state,
values: {
...state.values,
downloadLinkAutoPassword: true,
},
};
} else {
return state;
}
}
});
Empty file.
Empty file.
7 changes: 7 additions & 0 deletions idontknow.web.ts/src/routes/DemoForm/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {injectAsyncReducer} from '../../config/store';
import CounterReducer from './DemoForm.reducer';

export default (store: any): any => import('./DemoForm.container').then((component) => {
injectAsyncReducer(store, 'counter', CounterReducer);
return component;
});
Loading

0 comments on commit 7354f01

Please sign in to comment.