In this sample we will add a link in the Employees page that will navigate to a "new Employee page". This new page will display a form where you have to enter the avatar url, login and id of a new Employee (just supossing we can edit that info).
We will take a startup point sample 06 AJAX Call.
Summary steps:
- Update
About
component content. - Install
toastr
and typings. - Create dummy
Employee Page
. - Add new route to
Employee Page
. - Add link for navigation.
- Create common
form components
. - Create
EmployeeForm component
. - Update
Employee Page
. - Create
Employee Page container
. - Add save method in
Employee API
.
Install Node.js and npm (v6.6.0) if they are not already installed on your computer.
Verify that you are running at least node v6.x.x and npm 3.x.x by running
node -v
andnpm -v
in a terminal/console window. Older versions may produce errors.
-
Copy the content of the
06 AJAX Call
folder to an empty folder for the sample. -
Install the npm packages described in the
package.json
and verify that it works:
$ npm install
-
We update
About
content to show sample07 Form
highlights. You can see updates in./src/components/about.tsx
. -
Install
toastr
and typings to show toast when save form changes:
npm install toastr --save
npm install @types/toastr --save-dev
...
import * as React from 'react';
interface Props {
label: string;
className: string;
onClick: () => void;
}
export const Button: React.StatelessComponent<Props> = (props) => {
return (
<button type="button"
className={props.className}
onClick={props.onClick}
>
{props.label}
</button>
);
};
- Create its
index.ts
file:
export * from './input';
export * from './button';
- Create
EmployeeForm component
:
import * as React from 'react';
import { EmployeeEntity } from '../../model';
import { Input, Button } from '../../common/components/form';
interface Props {
Employee: EmployeeEntity;
onChange: (fieldName: string, value: string) => void;
onSave: () => void;
}
export const EmployeeForm: React.StatelessComponent<Props> = (props) => {
return (
<form>
<h1>Manage Employee</h1>
<Input
name="login"
label="Login"
value={props.Employee.login}
onChange={props.onChange}
/>
<Input
name="avatar_url"
label="Avatar Url"
value={props.Employee.avatar_url}
onChange={props.onChange}
/>
<Button
label="Save"
className="btn btn-default"
onClick={props.onSave}
/>
</form>
);
};
- Update
Employee Page
:
import * as React from 'react';
+ import { EmployeeEntity } from '../../model';
+ import { EmployeeForm } from './EmployeeForm';
+ interface Props {
+ Employee: EmployeeEntity;
+ onChange: (fieldName: string, value: string) => void;
+ onSave: () => void;
+ }
- export const EmployeePage: React.StatelessComponent<{}> = () => {
+ export const EmployeePage: React.StatelessComponent<Props> = (props) => {
return (
- <div className="row">
- <h2>Employee Page</h2>
- </div>
+ <EmployeeForm
+ Employee={props.Employee}
+ onChange={props.onChange}
+ onSave={props.onSave}
+ />
);
}
- Create
Employee Page container
:
import * as React from 'react';
import { EmployeeEntity } from '../../model';
import { EmployeePage } from './page';
interface State {
Employee: EmployeeEntity;
}
export class EmployeePageContainer extends React.Component<{}, State> {
constructor(props) {
super(props);
this.state = {
Employee: {
id: -1,
login: '',
avatar_url: '',
}
};
this.onFieldValueChange = this.onFieldValueChange.bind(this);
}
private onFieldValueChange(fieldName: string, value: string) {
const nextState = {
...this.state,
Employee: {
...this.state.Employee,
[fieldName]: value,
}
};
this.setState(nextState);
}
private onSave() {
console.log('save');
}
render() {
return (
<EmployeePage
Employee={this.state.Employee}
onChange={this.onFieldValueChange}
onSave={this.onSave}
/>
);
}
}
- Update its
index.ts
file:
- export * from './page';
+ export * from './pageContainer';
- And router:
import * as React from 'react';
import { Route, Switch, HashRouter } from 'react-router-dom';
import { App } from './app';
- import { About, EmployeesPage, EmployeePage } from './components';
+ import { About, EmployeesPage, EmployeePageContainer } from './components';
export const AppRouter: React.StatelessComponent<{}> = () => {
return (
<HashRouter>
<div className="container-fluid">
<Route component={App} />
<Switch>
<Route exact path="/" component={About} />
<Route path="/about" component={About} />
<Route path="/Employees" component={EmployeesPage} />
- <Route path="/Employee" component={EmployeePage} />
+ <Route path="/Employee" component={EmployeePageContainer} />
</Switch>
</div>
</HashRouter>
);
}
- Add save method in
Employee API
:
import { EmployeeEntity } from '../../model';
import { Employees } from './mockData';
const baseURL = 'https://api.github.com/orgs/lemoncode';
+ let mockEmployees = Employees;
const fetchEmployees = (): Promise<EmployeeEntity[]> => {
- return Promise.resolve(Employees);
+ return Promise.resolve(mockEmployees);
};
...
+ const saveEmployee = (Employee: EmployeeEntity): Promise<boolean> => {
+ const index = mockEmployees.findIndex(m => m.id === Employee.id);
+ index >= 0 ?
+ updateEmployee(Employee, index) :
+ insertEmployee(Employee);
+ return Promise.resolve(true);
+ };
+ const updateEmployee = (Employee: EmployeeEntity, index: number) => {
+ mockEmployees = [
+ ...mockEmployees.slice(0, index),
+ Employee,
+ ...mockEmployees.slice(index + 1),
+ ];
+ };
+ const insertEmployee = (Employee: EmployeeEntity) => {
+ Employee.id = mockEmployees.length;
+ mockEmployees = [
+ ...mockEmployees,
+ Employee,
+ ];
+ };
export const EmployeeAPI = {
fetchEmployees,
fetchEmployeesAsync,
+ saveEmployee,
};
- Use again
fetchEmployees
:
...
public componentDidMount() {
- EmployeeAPI.fetchEmployeesAsync()
+ EmployeeAPI.fetchEmployees()
.then((Employees) => {
this.setState({ Employees });
});
}
...
};
- Update
Employee page
container:
import * as React from 'react';
+ import * as toastr from 'toastr';
+ import { EmployeeAPI } from '../../api/Employee';
+ import { History } from 'history';
import { EmployeeEntity } from '../../model';
import { EmployeePage } from './page';
...
+ interface Props {
+ history: History;
+ }
- export class EmployeePageContainer extends React.Component<{}, State> {
+ export class EmployeePageContainer extends React.Component<Props, State> {
+ private onSave = () => {
- console.log('save');
+ EmployeeAPI.saveEmployee(this.state.Employee)
+ .then(() => {
+ toastr.success('Employee saved.');
+ this.props.history.goBack();
+ });
}
...
render() {
return (
<EmployeePage
Employee={this.state.Employee}
onChange={this.onFieldValueChange}
onSave={this.onSave}
/>
);
}
}
- Execute the example:
$ npm start
We are a team of long-term experienced freelance developers, established as a group in 2010. We specialize in Front End technologies and .NET. Click here to get more info about us.