From 39f7f1649f433f49a2f2185c8e71c31500b871ff Mon Sep 17 00:00:00 2001 From: SteveSandersonMS Date: Tue, 15 Dec 2015 12:47:52 +0000 Subject: [PATCH] Add example of server and client validation for React --- .../Controllers/PeopleApiController.cs | 30 ++++++++++ .../ReactApp/components/PeopleGrid.jsx | 3 +- .../ReactApp/components/PersonEditor.jsx | 57 +++++++++++++++++++ .../ReactApp/components/ReactApp.jsx | 2 + .../data/{columnMeta.js => columnMeta.jsx} | 16 ++++++ .../react/ReactGrid/Views/Home/Index.cshtml | 2 +- .../ReactGrid/Views/Shared/_Layout.cshtml | 4 +- samples/react/ReactGrid/package.json | 2 + 8 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 samples/react/ReactGrid/Controllers/PeopleApiController.cs create mode 100644 samples/react/ReactGrid/ReactApp/components/PersonEditor.jsx rename samples/react/ReactGrid/ReactApp/data/{columnMeta.js => columnMeta.jsx} (66%) diff --git a/samples/react/ReactGrid/Controllers/PeopleApiController.cs b/samples/react/ReactGrid/Controllers/PeopleApiController.cs new file mode 100644 index 0000000..82e967a --- /dev/null +++ b/samples/react/ReactGrid/Controllers/PeopleApiController.cs @@ -0,0 +1,30 @@ +using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks; +using Microsoft.AspNet.Mvc; + +namespace ReactExample.Controllers +{ + public class PeopleApiController : Controller + { + [HttpPut("api/people/{personId:int}")] + public async Task UpdatePerson([FromBody] PersonDto person) + { + if (!ModelState.IsValid) { + return HttpBadRequest(ModelState); + } else { + return new HttpOkResult(); + } + } + } + + public class PersonDto { + public string name { get; set; } + public string city { get; set; } + public string state { get; set; } + public string country { get; set; } + public string company { get; set; } + + [Range(1, 10)] + public int favoriteNumber { get; set; } + } +} diff --git a/samples/react/ReactGrid/ReactApp/components/PeopleGrid.jsx b/samples/react/ReactGrid/ReactApp/components/PeopleGrid.jsx index c6662fa..a9dbec1 100644 --- a/samples/react/ReactGrid/ReactApp/components/PeopleGrid.jsx +++ b/samples/react/ReactGrid/ReactApp/components/PeopleGrid.jsx @@ -2,7 +2,7 @@ import React from 'react'; import Griddle from 'griddle-react'; import { CustomPager } from './CustomPager.jsx'; import { fakeData } from '../data/fakeData.js'; -import { columnMeta } from '../data/columnMeta.js'; +import { columnMeta } from '../data/columnMeta.jsx'; const resultsPerPage = 10; export class PeopleGrid extends React.Component { @@ -13,6 +13,7 @@ export class PeopleGrid extends React.Component {

People

x.columnName)} columnMetadata={columnMeta} resultsPerPage={resultsPerPage} tableClassName="table" diff --git a/samples/react/ReactGrid/ReactApp/components/PersonEditor.jsx b/samples/react/ReactGrid/ReactApp/components/PersonEditor.jsx new file mode 100644 index 0000000..6cb11d5 --- /dev/null +++ b/samples/react/ReactGrid/ReactApp/components/PersonEditor.jsx @@ -0,0 +1,57 @@ +import React from 'react'; +import Formsy from 'formsy-react'; +import { Input } from 'formsy-react-components'; +import { fakeData } from '../data/fakeData.js'; + +export class PersonEditor extends React.Component { + constructor() { + super(); + this.state = { savedChanges: false }; + } + + onChange() { + this.setState({ savedChanges: false }); + } + + submit(model, reset, setErrors) { + PersonEditor.sendJson('put', `/api/people/${ this.props.params.personId }`, model).then(response => { + if (response.ok) { + this.setState({ savedChanges: true }); + } else { + // Parse server-side validation errors from the response and display them + response.json().then(setErrors); + } + }); + } + + render() { + var personId = parseInt(this.props.params.personId); + var person = fakeData.filter(p => p.id === personId)[0]; + var notificationBox = this.state.savedChanges + &&
Done! Your changes were saved.
; + + return
+
+

Edit { person.name }

+
+ + + + + + + + { notificationBox } + + +
; + } + + static sendJson(method, url, object) { + return fetch(url, { + method: method, + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(object) + }); + } +} diff --git a/samples/react/ReactGrid/ReactApp/components/ReactApp.jsx b/samples/react/ReactGrid/ReactApp/components/ReactApp.jsx index f135152..1efeef7 100644 --- a/samples/react/ReactGrid/ReactApp/components/ReactApp.jsx +++ b/samples/react/ReactGrid/ReactApp/components/ReactApp.jsx @@ -1,6 +1,7 @@ import React from 'react'; import { Router, Route } from 'react-router'; import { PeopleGrid } from './PeopleGrid.jsx'; +import { PersonEditor } from './PersonEditor.jsx'; export default class ReactApp extends React.Component { render() { @@ -8,6 +9,7 @@ export default class ReactApp extends React.Component { + ); } diff --git a/samples/react/ReactGrid/ReactApp/data/columnMeta.js b/samples/react/ReactGrid/ReactApp/data/columnMeta.jsx similarity index 66% rename from samples/react/ReactGrid/ReactApp/data/columnMeta.js rename to samples/react/ReactGrid/ReactApp/data/columnMeta.jsx index f470451..ba23d4f 100644 --- a/samples/react/ReactGrid/ReactApp/data/columnMeta.js +++ b/samples/react/ReactGrid/ReactApp/data/columnMeta.jsx @@ -1,3 +1,12 @@ +import React from 'react'; +import { Link } from 'react-router'; + +class RowActionsComponent extends React.Component { + render() { + return Edit; + } +} + var columnMeta = [ { "columnName": "id", @@ -40,6 +49,13 @@ var columnMeta = [ "order": 7, "locked": false, "visible": true + }, + { + "columnName": "actions", + "order": 8, + "locked": true, + "visible": true, + "customComponent": RowActionsComponent } ]; diff --git a/samples/react/ReactGrid/Views/Home/Index.cshtml b/samples/react/ReactGrid/Views/Home/Index.cshtml index 76f8a6c..25613eb 100755 --- a/samples/react/ReactGrid/Views/Home/Index.cshtml +++ b/samples/react/ReactGrid/Views/Home/Index.cshtml @@ -1,5 +1,5 @@
@section scripts { - + } diff --git a/samples/react/ReactGrid/Views/Shared/_Layout.cshtml b/samples/react/ReactGrid/Views/Shared/_Layout.cshtml index 4e83db4..a6fd7d5 100755 --- a/samples/react/ReactGrid/Views/Shared/_Layout.cshtml +++ b/samples/react/ReactGrid/Views/Shared/_Layout.cshtml @@ -6,7 +6,9 @@ - @RenderBody() +
+ @RenderBody() +
@RenderSection("scripts", required: false) diff --git a/samples/react/ReactGrid/package.json b/samples/react/ReactGrid/package.json index 2249b91..0d92af9 100644 --- a/samples/react/ReactGrid/package.json +++ b/samples/react/ReactGrid/package.json @@ -4,6 +4,8 @@ "dependencies": { "babel-core": "^5.8.29", "bootstrap": "^3.3.5", + "formsy-react": "^0.17.0", + "formsy-react-components": "^0.6.3", "griddle-react": "^0.2.14", "history": "^1.12.6", "react": "^0.14.0",