javascript - Mallen laddas inte upp i sidofältet utan uppdatering (React)
Jag är ny på React och jag har försökt att ladda upp några mallar till backend-servern så att de visas i sidofältet, men det fungerar inte förrän sidan uppdateras (min gissning är att sidan behöver renderas igen). Jag har implementerat en fönster-uppdatering vid klick på uppladdningsknappen, men jag undrar om det finns en bättre lösning för detta. Mina koder för mallarna finns nedan. All hjälp skulle uppskattas mycket eftersom jag är ny.
Backend App.js
const express = require('express');
const path = require('path');
const favicon = require('serve-favicon');
const logger = require('morgan');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const fileUpload = require('express-fileupload');
const cors = require('cors');
const app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(cors());
app.use(fileUpload());
app.use('/public', express.static(__dirname + '/public'));
app.post('/upload', (req, res, next) => {
console.log(req);
let xmlFile = req.files.file;
xmlFile.mv(`${__dirname}/public/${req.body.filename}.xml`, function(err) {
if (err) {
return res.status(500).send(err);
}
res.json({file: `public/${req.body.filename}.xml`});
});
})
app.get('/file', function (req, res) {
const fs = require('fs');
//joining path of directory
const directoryPath = path.join(__dirname, 'public');
//passsing directoryPath and callback function
fs.readdir(directoryPath, function (err, files) {
//handling error
if (err) {
return console.log('Unable to scan directory: ' + err);
} else {
res.json({files: files});
}
//listing all files using forEach
files.forEach(function (file) {
// Do whatever you want to do with the file
console.log(file);
});
});
});
app.get('/file/:fileName', function (req, res) {
const fs = require('fs');
console.log(req.params);
const directoryPath = path.join(__dirname, 'public');
fs.readFile(directoryPath + '\\'+ req.params.fileName, 'utf8', function (err, data) {
//handling error
if (err) {
return console.log('Unable to read file: ' + err);
} else {
res.json({content: data});
}
});
});
// catch 404 and forward to error handler
app.use(function(req, res, next) {
const err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
app.listen(8000, () => {
console.log('8000');
});
module.exports = app;
`
App.tsx
import * as React from 'react';
import './sass/App.css';
import 'primereact/resources/primereact.min.css';
import 'primereact/resources/themes/omega/theme.css';
import 'font-awesome/css/font-awesome.css';
import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap/dist/css/bootstrap-theme.css';
import './resources/primereact.css';
import * as classNames from 'classnames';
import { BrowserRouter as Router, Redirect, Route, Switch, Link } from 'react-router-dom';
import Sidebar from './Sidebar';
import Home from './Home';
import CapitalHomelessness from './CapitalHomelessness';
import FormTemplateComponent from './FormTemplateComponent';
import { FileUploadComponent } from './FileUploadComponent';
import { Menu } from 'primereact/components/menu/Menu';
interface AppProps { }
interface AppState {
loadedContent: Document;
loadedCapitalHomelessnessContent: Document;
menuActive: boolean;
langCo: string;
items: any;
}
class App extends React.Component<AppProps, AppState> {
loadedContent: Document;
formItems = [];
menu: Menu;
constructor(props: AppProps) {
super(props);
this.state = {
loadedContent: null,
loadedCapitalHomelessnessContent: null,
menuActive: false,
langCo: 'en',
items: [
{
label: 'Admin',
items: [
{label: 'Home', icon: 'fa fa-home',
command: () => { window.location.href = '/Home'; }},
{label: 'New Template', icon: 'fa fa-plus-square',
command: () => { window.location.href = '/FileUploadComponent'; }},
{label: 'List Template', icon: 'fa fa-list-ol',
command: () => { window.location.href = '/CapitalHomelessness'; }}
]
},
{
label: 'Form',
items: this.formItems
}
],
};
this.openMenu = this.openMenu.bind(this);
this.closeMenu = this.closeMenu.bind(this);
this.onSidebarClick = this.onSidebarClick.bind(this);
this.getMenuItems = this.getMenuItems.bind(this);
this.switchLang = this.switchLang.bind(this);
}
async componentWillMount() {
await this.getMenuItems();
this.setState({ menuActive: !this.state.menuActive });
}
componentDidMount() {
// this.formItems = [];
// this.getMenuItems();
// tslint:disable-next-line:no-console
console.log(this.state.items);
}
// tslint:disable-next-line:typedef
openMenu(event) {
// tslint:disable-next-line:no-console
console.log(event);
this.setState({ menuActive: !this.state.menuActive });
event.preventDefault();
}
// tslint:disable-next-line:typedef
closeMenu(event) {
this.setState({ menuActive: false});
event.preventDefault();
}
// tslint:disable-next-line:typedef
onSidebarClick(event) {
// tslint:disable-next-line:no-console
console.log(event);
if (event.target.nodeName === 'A' && event.target.parentNode.className.indexOf('layout-menu') === -1) {
this.closeMenu(event);
}
}
async getMenuItems() {
const response = await fetch('http://localhost:8000/file');
const json = await response.json();
json.files.forEach(async element => {
this.formItems.push({
label: element.split('.').slice(0, -1).join('.'), icon: 'fa fa-file',
command: async () => {
window.location.href = `/FormLoading/:${element}`;
this.forceUpdate();
}
});
});
}
switchLang() {
const newLancCode = (this.state.langCo === 'fr' ? 'en' : 'fr');
this.setState({ langCo: newLancCode });
}
render() {
return (
<Router>
<div className="layout-wrapper">
<div id="layout-topbar">
<a className="menu-button" onClick={this.openMenu}>
<i className="fa fa-bars" />
</a>
<Link to="/" className="logo">
<img alt="logo" src="resources/images/ontario-logo.png" id="top-logo" height="50px" width="100px"/>
</Link>
<a className="title">
<h3>Dynamic Template Form</h3>
</a>
<ul className="topbar-menu">
<li>
<Link to="/signin"> Sign in </Link>
</li>
<li>
<Link to="#" onClick={this.switchLang}> {this.state.langCo === 'fr' ? 'english' : 'Français'} </Link>
</li>
</ul>
</div>
{/* tslint:disable-next-line:max-line-length */}
<div id="layout-sidebar" className={classNames({ 'active': this.state.menuActive === true })} onClick={this.onSidebarClick}>
<div className="nano-content">
<div>
<Menu model={this.state.items} ref={el => this.menu = el}/>
</div>
</div>
</div>
<div id="layout-content">
<Switch>
<Route path="/" exact={true} component={Home} />
<Route
path="/Home"
render={(props) => <Home {...props} />}
/>
<Route
path="/FileUploadComponent"
render={(props) => <FileUploadComponent {...props} />}
/>
<Route
path={`/FormLoading/:fileName`}
render={(props) => <FormTemplateComponent {...props} langCo={this.state.langCo}/>}
/>
</Switch>
</div>
</div>
</Router>
);
}
}
export default App;
`
Filuppladdningskomponent.tsx
import * as React from 'react';
import { Growl, GrowlMessage } from 'primereact/components/growl/Growl';
import { Panel } from 'primereact/components/panel/Panel';
import { Button } from 'primereact/components/button/Button';
import sidebar from './Sidebar';
interface Props {
}
interface State {
imageURL: string;
}
export class FileUploadComponent extends React.Component<Props, State> {
growl: Growl;
fileName: HTMLInputElement;
uploadInput: HTMLInputElement;
constructor(props: Props) {
super(props);
this.state = {
imageURL: '',
};
this.setState(this.state);
this.handleUploadImage = this.handleUploadImage.bind(this);
}
handleUploadImage(ev: any) {
ev.preventDefault();
const data = new FormData();
data.append('file', this.uploadInput.files[0]);
data.append('filename', this.fileName.value);
fetch('http://localhost:8000/upload', {
method: 'POST',
body: data,
}).then((response) => {
response.json().then((body) => {
this.setState({ imageURL: `http://localhost:8000/${body.file}` });
});
});
// this.growl.props.show({severity: 'info', summary: 'Success', detail: 'File Uploaded', closable: true, sticky: false, life: 1});
// tell sidebar component to update its menu items
}
reloadPage () {
window.location.reload();
}
render() {
return (
<Panel header="Template Uploading">
<form onSubmit={this.handleUploadImage}>
<div className="ui-g-12">
<input ref={(ref) => { this.uploadInput = ref; }} type="file" />
</div>
<div className="ui-g-12">
<input ref={(ref) => { this.fileName = ref; }} type="text" placeholder="Enter the name of file" /> *Required
</div>
<br />
<div>
<button onClick={this.reloadPage}>Upload</button>
</div>
<Growl ref={(el) => { this.growl = el; }} />
</form>
</Panel >
);
}
}
export default FileUploadComponent
Sidofält.tsx
import * as React from 'react';
import { Link } from 'react-router-dom';
import 'nanoscroller';
import * as $ from 'jquery';
import * as classNames from 'classnames';
import { Menu } from 'primereact/components/menu/Menu';
interface AppProps { loadFileContent: (fileName: string) => any; }
interface AppState {
items: any;
loaded: boolean;
}
class Sidebar extends React.Component<AppProps, AppState> {
scrollContainer: any;
formItems = [];
constructor(props: AppProps) {
super(props);
this.state = {
items: [
{
label: 'Admin',
items: [{label: 'New Template', icon: 'fa fa-plus-square',
command: () => { window.location.href = '/FileUploadComponent'; }},
{label: 'List Template', icon: 'fa fa-list-ol',
command: () => { window.location.href = '/CapitalHomelessness'; }}
]
},
{
label: 'Form',
items: this.formItems
}
],
loaded: false
};
this.openMenu = this.openMenu.bind(this);
this.getMenuItems = this.getMenuItems.bind(this);
}
// tslint:disable-next-line:typedef
openMenu(event, val) {
setTimeout(() => $(this.scrollContainer).nanoScroller(), 350);
event.preventDefault();
}
componentDidMount() {
// this.getMenuItems();
$(this.scrollContainer).nanoScroller({ flash: true });
// get all templates from Templates folder
}
componentWillMount() {
// tslint:disable-next-line:no-console
console.log('will mount');
this.getMenuItems();
}
componentWillUnmount() {
$(this.scrollContainer).nanoScroller({ destroy: true });
}
async getMenuItems() {
const request = async () => {
const response = await fetch('http://localhost:8000/file');
const json = await response.json();
json.files.forEach(async element => {
var loadedContetnt = await this.props.loadFileContent(element);
this.formItems.push({
label: element.split('.').slice(0, -1).join('.'), icon: 'fa fa-file',
data: loadedContetnt,
command: async () => {
// var loadedContetnt = await this.props.loadFileContent(element);
// tslint:disable-next-line:no-console
console.log(loadedContetnt);
window.location.href = '/FormLoading';
}
});
});
};
request();
// fetch('http://localhost:8000/file', {
// method: 'GET'
// }).then((response) => {
// response.json().then((body) => {
// body.files.forEach(element => {
// // tslint:disable-next-line:no-console
// console.log('command');
// this.formItems.push({
// label: element.split('.').slice(0, -1).join('.'), icon: 'fa fa-file',
// command: () => {
// var loadedContetnt = this.props.loadFileContent(element);
// // tslint:disable-next-line:no-console
// console.log(loadedContetnt);
// // window.location.href = '/FormLoading';
// }
// });
// });
// });
// this.setState({ loaded: true });
// });
// tslint:disable-next-line:no-console
console.log(this.state.items);
}
render() {
return (
<div ref={(el) => this.scrollContainer = el} className="nano">
<div className="nano-content">
<div>
<Menu model={this.state.items} />
</div>
{/* <div className="layout-menu">
<div>
<Link className="fa fa-home" to="/">Home</Link>
</div>
<div> </div>
<div>
<Link className="fa fa-wpforms" to="/CapitalHomelessness">Rent Supplement Form</Link>
</div>
<div>
<Link className="fa fa-wpforms" to="/RentSupplement">Rent Supplement Form (New)</Link>
</div>
<div>
<Link className="fa fa-wpforms" to="/TransformationHousing">Trans. Housing Form (New)</Link>
</div>
<div> </div>
<div>
<Link className="fa fa-upload" to="/upload">Upload Form Template</Link>
</div>
<div>
<Link className="fa fa-database" to="/retrieve">Retrieve Form Template</Link>
</div>
</div> */}
</div>
</div>
);
}
}
export default Sidebar;