From e9813ca978ee82c9fa0b77e658707439c632f9fb Mon Sep 17 00:00:00 2001 From: Jack Franklin Date: Mon, 4 Apr 2016 16:18:55 +0100 Subject: [PATCH 1/4] Get the server side form submission working This form can be submitted & validated entirely without JS on the client :) --- client-render.js | 2 - components/about.js | 13 ++++++ components/email-form.js | 68 +++++++++++++++++++++++++++++++ components/validate-email-form.js | 20 +++++++++ package.json | 2 + server.js | 22 +++++++++- 6 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 components/email-form.js create mode 100644 components/validate-email-form.js diff --git a/client-render.js b/client-render.js index def88ba..23af70e 100644 --- a/client-render.js +++ b/client-render.js @@ -4,8 +4,6 @@ import { Router, browserHistory } from 'react-router'; import { routes } from './routes'; -// import createBrowserHistory from 'history/lib/createBrowserHistory'; - ReactDOM.render( , document.getElementById('app') diff --git a/components/about.js b/components/about.js index 2601496..659336f 100644 --- a/components/about.js +++ b/components/about.js @@ -1,10 +1,23 @@ import React from 'react'; +import EmailForm from './email-form'; export default class AboutComponent extends React.Component { + constructor(props) { + super(props); + const { success, errors, value } = this.props.location.query; + if (success) { + this.emailFormProps = { + success: success === "true", + errors: errors && errors.split(',') || [], + value + } + } + } render() { return (

A little bit about me.

+
); } diff --git a/components/email-form.js b/components/email-form.js new file mode 100644 index 0000000..0024948 --- /dev/null +++ b/components/email-form.js @@ -0,0 +1,68 @@ +import React from 'react'; + +export default class EmailForm extends React.Component { + constructor(props) { + super(props); + const { success, errors, value } = props; + this.state = { + success, + errors, + value + }; + } + + formSubmittedSuccessfully() { + return this.state.success === true; + } + + renderErrors() { + return this.state.errors.map((err) => { + return ( +
  • +

    {err}

    +
  • + ); + }); + } + + renderForm() { + return ( +
    + +
    + + +
    + +
    + ); + } + + renderSuccess() { + return ( +
    +

    Thanks, {this.state.value} has been added to our totally cool list.

    +
    + ) + } + + render() { + return ( +
    + { this.state.errors && this.state.errors.length > 0 && +
    +
    There were errors submitting this form.
    +
      {this.renderErrors()}
    +
    + } + { !this.formSubmittedSuccessfully() && this.renderForm() } + { this.formSubmittedSuccessfully() && this.renderSuccess() } +
    + ) + } +} + +EmailForm.propTypes = { + success: React.PropTypes.bool, + errors: React.PropTypes.arrayOf(React.PropTypes.string) +}; diff --git a/components/validate-email-form.js b/components/validate-email-form.js new file mode 100644 index 0000000..7e07027 --- /dev/null +++ b/components/validate-email-form.js @@ -0,0 +1,20 @@ +// write any logic for your form in one file that can be used on both the client and the server + +export default function(email) { + // IRL you probably want a better check! + if (email.indexOf('@') > -1) { + return { + valid: true, + email, + errors: [] + } + } else { + return { + valid: false, + email, + errors: [ + `Email address ${email} is not valid` + ] + } + } +} diff --git a/package.json b/package.json index fd26237..522a700 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "author": "", "license": "ISC", "dependencies": { + "body-parser": "^1.15.0", "ejs": "^2.3.4", "express": "^4.13.3", "history": "^1.13.1", @@ -34,6 +35,7 @@ "babel-loader": "^6.2.0", "babel-preset-es2015": "^6.1.18", "babel-preset-react": "^6.1.18", + "nodemon": "^1.9.1", "webpack": "^1.12.9" } } diff --git a/server.js b/server.js index ac66620..9fcc026 100644 --- a/server.js +++ b/server.js @@ -3,12 +3,17 @@ import express from 'express'; import React from 'react'; import { renderToString } from 'react-dom/server'; import { match, RouterContext } from 'react-router'; +import bodyParser from 'body-parser'; import { routes } from './routes'; +import validateEmailForm from './components/validate-email-form'; + const app = express(); app.use(express.static('public')); +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: true })); app.set('view engine', 'ejs'); @@ -36,7 +41,22 @@ app.get('*', (req, res) => { } }); }); -app.listen(3003, 'localhost', function(err) { + +app.post('/submit-email-form', (req, res) => { + const { email } = req.body; + const result = validateEmailForm(email); + + if (result.valid === true) { + // here you would save this to a database, or whatever you want + // db.addEmail(email) + + res.redirect(`/about?success=true&value=${email}`); + } else { + res.redirect(`/about?errors=${result.errors.join(',')}&success=false&value=${email}`); + } +}); + +app.listen(3003, 'localhost', (err) => { if (err) { console.log(err); return; From 10210c0cda7b125e25d94b54aad114c0e89d6977 Mon Sep 17 00:00:00 2001 From: Jack Franklin Date: Mon, 4 Apr 2016 16:23:06 +0100 Subject: [PATCH 2/4] Some refactoring before building the JS version --- components/email-form.js | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/components/email-form.js b/components/email-form.js index 0024948..9d7577d 100644 --- a/components/email-form.js +++ b/components/email-form.js @@ -15,7 +15,7 @@ export default class EmailForm extends React.Component { return this.state.success === true; } - renderErrors() { + renderErrorsList() { return this.state.errors.map((err) => { return (
  • @@ -46,17 +46,24 @@ export default class EmailForm extends React.Component { ) } + renderErrors() { + if (this.state.errors && this.state.errors.length > 0) { + return ( +
    +
    There were errors submitting this form.
    +
      {this.renderErrorsList()}
    +
    + ); + } else { + return null; + } + } + render() { return (
    - { this.state.errors && this.state.errors.length > 0 && -
    -
    There were errors submitting this form.
    -
      {this.renderErrors()}
    -
    - } - { !this.formSubmittedSuccessfully() && this.renderForm() } - { this.formSubmittedSuccessfully() && this.renderSuccess() } + { this.renderErrors() } + { this.formSubmittedSuccessfully() ? this.renderSuccess() : this.renderForm() }
    ) } From 6c04e4f673a7d4f3d12b3ec33a39fd6eb8612f12 Mon Sep 17 00:00:00 2001 From: Jack Franklin Date: Mon, 4 Apr 2016 16:33:58 +0100 Subject: [PATCH 3/4] Make email-form work with JS too --- components/email-form.js | 44 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/components/email-form.js b/components/email-form.js index 9d7577d..4be855d 100644 --- a/components/email-form.js +++ b/components/email-form.js @@ -1,4 +1,6 @@ import React from 'react'; +import { Link } from 'react-router'; +import validateEmailForm from './validate-email-form'; export default class EmailForm extends React.Component { constructor(props) { @@ -7,14 +9,43 @@ export default class EmailForm extends React.Component { this.state = { success, errors, - value + value: value || '' }; + this.formSubmit = this.formSubmit.bind(this); + this.inputChange = this.inputChange.bind(this); + this.resetForm = this.resetForm.bind(this); } formSubmittedSuccessfully() { return this.state.success === true; } + inputChange(e) { + this.setState({ + value: e.target.value + }); + } + + resetForm(e) { + e.preventDefault(); + this.setState({ + success: undefined, + errors: [], + value: '' + }); + } + + formSubmit(e) { + e.preventDefault(); + const emailValue = this.state.value; + // note how this is the same validator we ran on the server! + const result = validateEmailForm(emailValue); + this.setState({ + errors: result.errors, + success: result.valid + }); + } + renderErrorsList() { return this.state.errors.map((err) => { return ( @@ -27,11 +58,17 @@ export default class EmailForm extends React.Component { renderForm() { return ( -
    +
    - +
    @@ -42,6 +79,7 @@ export default class EmailForm extends React.Component { return (

    Thanks, {this.state.value} has been added to our totally cool list.

    + Reset page
    ) } From 16a527b13c3b5cbc131cf8cbd95a647d8590fff6 Mon Sep 17 00:00:00 2001 From: Jack Franklin Date: Fri, 13 May 2016 12:27:56 +0100 Subject: [PATCH 4/4] Add comment --- components/email-form.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/email-form.js b/components/email-form.js index 4be855d..77085da 100644 --- a/components/email-form.js +++ b/components/email-form.js @@ -40,6 +40,8 @@ export default class EmailForm extends React.Component { const emailValue = this.state.value; // note how this is the same validator we ran on the server! const result = validateEmailForm(emailValue); + // at this point you could POST to an endpoint to save + // this to the database, or do whatever you need to this.setState({ errors: result.errors, success: result.valid