Related
So as part of my project I'm trying to ammend this boilerplate of React-Pdf-Highlighter to accept pdf highlights from flask-api instead of a local file( the example came with a local/json import) ..
I have tried to check with console.log the fetch is not the problem, but I feel for somereason the 'testHighlights' state is not what it should be .
<<App.js>>
// #flow
/* eslint import/no-webpack-loader-syntax: 0 */
import React, { Component } from "react";
import PDFWorker from "worker-loader!pdfjs-dist/lib/pdf.worker";
import {
PdfLoader,
PdfHighlighter,
Tip,
Highlight,
Popup,
AreaHighlight,
setPdfWorker
} from "react-pdf-highlighter";
import Spinner from "./Spinner";
import Sidebar from "./Sidebar";
import testHighlights from "./test-highlights";
import type {
T_Highlight,
T_NewHighlight
} from "react-pdf-highlighter/src/types";
import "./style/App.css";
setPdfWorker(PDFWorker);
type Props = {};
type State = {
url: string,
highlights: Array<T_Highlight>
};
const getNextId = () => String(Math.random()).slice(2);
const parseIdFromHash = () =>
document.location.hash.slice("#highlight-".length);
const resetHash = () => {
document.location.hash = "";
};
const HighlightPopup = ({ comment }) =>
comment.text ? (
<div className="Highlight__popup">
{comment.emoji} {comment.text}
</div>
) : null;
const PRIMARY_PDF_URL = "https://arxiv.org/pdf/1708.08021.pdf";
const SECONDARY_PDF_URL = "https://arxiv.org/pdf/1604.02480.pdf";
const searchParams = new URLSearchParams(document.location.search);
const initialUrl = searchParams.get("url") || PRIMARY_PDF_URL;
class App extends Component<Props, State> {
state = {
url: initialUrl,
highlights: testHighlights[initialUrl]
? [...testHighlights[initialUrl]]
: []
};
state: State;
resetHighlights = () => {
this.setState({
highlights: []
});
};
toggleDocument = () => {
const newUrl =
this.state.url === PRIMARY_PDF_URL ? SECONDARY_PDF_URL : PRIMARY_PDF_URL;
this.setState({
url: newUrl,
highlights: testHighlights[newUrl] ? [...testHighlights[newUrl]] : []
});
};
scrollViewerTo = (highlight: any) => {};
scrollToHighlightFromHash = () => {
const highlight = this.getHighlightById(parseIdFromHash());
if (highlight) {
this.scrollViewerTo(highlight);
}
};
componentDidMount() {
window.addEventListener(
"hashchange",
this.scrollToHighlightFromHash,
false
);
}
getHighlightById(id: string) {
const { highlights } = this.state;
return highlights.find(highlight => highlight.id === id);
}
addHighlight(highlight: T_NewHighlight) {
const { highlights } = this.state;
console.log("Saving highlight", highlight);
this.setState({
highlights: [{ ...highlight, id: getNextId() }, ...highlights]
});
}
updateHighlight(highlightId: string, position: Object, content: Object) {
console.log("Updating highlight", highlightId, position, content);
this.setState({
highlights: this.state.highlights.map(h => {
const {
id,
position: originalPosition,
content: originalContent,
...rest
} = h;
return id === highlightId
? {
id,
position: { ...originalPosition, ...position },
content: { ...originalContent, ...content },
...rest
}
: h;
})
});
}
render() {
const { url, highlights } = this.state;
return (
<div className="App" style={{ display: "flex", height: "100vh" }}>
<Sidebar
highlights={highlights}
resetHighlights={this.resetHighlights}
toggleDocument={this.toggleDocument}
/>
<div
style={{
height: "100vh",
width: "75vw",
position: "relative"
}}
>
<PdfLoader url={url} beforeLoad={<Spinner />}>
{pdfDocument => (
<PdfHighlighter
pdfDocument={pdfDocument}
enableAreaSelection={event => event.altKey}
onScrollChange={resetHash}
// pdfScaleValue="page-width"
scrollRef={scrollTo => {
this.scrollViewerTo = scrollTo;
this.scrollToHighlightFromHash();
}}
onSelectionFinished={(
position,
content,
hideTipAndSelection,
transformSelection
) => (
<Tip
onOpen={transformSelection}
onConfirm={comment => {
this.addHighlight({ content, position, comment });
hideTipAndSelection();
}}
/>
)}
highlightTransform={(
highlight,
index,
setTip,
hideTip,
viewportToScaled,
screenshot,
isScrolledTo
) => {
const isTextHighlight = !Boolean(
highlight.content && highlight.content.image
);
const component = isTextHighlight ? (
<Highlight
isScrolledTo={isScrolledTo}
position={highlight.position}
comment={highlight.comment}
/>
) : (
<AreaHighlight
highlight={highlight}
onChange={boundingRect => {
this.updateHighlight(
highlight.id,
{ boundingRect: viewportToScaled(boundingRect) },
{ image: screenshot(boundingRect) }
);
}}
/>
);
return (
<Popup
popupContent={<HighlightPopup {...highlight} />}
onMouseOver={popupContent =>
setTip(highlight, highlight => popupContent)
}
onMouseOut={hideTip}
key={index}
children={component}
/>
);
}}
highlights={highlights}
/>
)}
</PdfLoader>
</div>
</div>
);
}
}
export default App;
<<test-highlights.js >>
const testHighlights =async () => {
const res= await fetch('http://127.0.0.1:5000/jsonapi')
const data =await res.json()
console.log(data)
this.state.testHighlights = data
return testHighlights;
}
export default testHighlights;
You can't assign state like this
this.state.testHighlights = data
You must use this.setState function to do it
this.setState({ testHighlights: data });
That is why your testHighlights state isn't what you was expected
how do you change the state back to blank when the form has been submitted?
I tried to empty it again when the form was submitted, but the state still has value
when it is finished, submit the state back to the initial state
state = {
importExcel: '',
active: true
};
handlerChange = e => {
this.setState({
importExcel: e.target.files[0],
active: !this.state.active
});
};
handlerOnSubmit = e => {
e.preventDefault()
const formData = new FormData();
formData.append('importExcel', this.state.importExcel);
api.post('web/user/import', formData)
.then(res => {
const { message, success } = res.data;
const alert = swal({
title: success === false ? 'Gagal Upload' : 'Berhasil Upload',
text: message,
icon: success === false ? 'error' : 'success',
// timer: 5000,
button: true
})
if (success === false) {
return alert
} else {
return alert
}
})
this.setState({
importExcel: '',
active: true
})
}
if (success === false) {
return alert
} else {
return alert
}
You are returning function every time. So the code below this line doesn't execute.
I'm trying to create a very simple Content Management System for creating and updating blog posts. I managed to successfully create and delete blog posts but I'm having difficulty wrapping my head around when I try to edit them.
The problem I'm running into is if I have 3 fields that are Editable for the Blog Post.
1) Blog Topic
2) Blog Picture
3) Blog Content
If I edit 1 field such as Blog Topic with test data and I submit the changes, the data that was in Blog Picture and Blog Content get lost and submit nothing even though there was data there previously and I'm not sure why. However, if I set the defaultValue to my state whenever I save to make changes, the problem gets fixed but I want my inputs to have the initial value in there field also.
Here is my code:
import React from "react";
import ReactDOM from "react-dom";
import Header from "../common/Header";
import Footer from "../common/Footer";
import Adminediting from "../common/isEditing";
import Addblogtopic from "./Addblogtopic";
import { Modal, Button } from "react-bootstrap";
import { Link, Redirect } from "react-router-dom";
import Moment from "moment";
import dataTip from "data-tip";
import { confirmAlert } from "react-confirm-alert";
import CKEditor from "ckeditor4-react";
import blogtopicsService from "../../services/Blogservice";
import appController from "../../controllers/appController";
class Blogtopics extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: false,
blogData: [],
blogCategory: "",
blogContent: "",
blogId: "",
hoverSelected: false,
isEditing: false,
fileObject: "",
fileName: "",
fileSize: "",
fileType: "",
filePayload: "",
blogPicture: "",
email: "",
firstName: "",
lastName: "",
roleId: "",
userId: "",
errorMsg2: false,
errorMsg3: false
};
}
Selectblogtopics = async () => {
const blogTopics = await blogtopicsService.selectblogTopics();
this.setState({
blogData: blogTopics
});
};
toggleHover = hoverState => {
this.setState({ hoverSelected: hoverState });
};
updateImage = e => {
let file = e.target.files[0];
var dataTypeURL = new FileReader();
var arrayBuffer = new FileReader();
this.setState({
fileObject: file,
fileName: file.name,
fileSize: file.size,
fileType: file.type
});
dataTypeURL.onload = e => {
this.setState({
filePayload: e.target.result,
blogPicture: e.target.result
});
};
dataTypeURL.readAsDataURL(file);
arrayBuffer.readAsArrayBuffer(file);
};
editBlog = editingState => {
this.setState({
isEditing: !editingState
});
//Publish Changes
setTimeout(async () => {
this.setState({
isLoading: false
});
const uploadData = {
blogCategory: this.state.blogCategory,
blogContent: this.state.blogContent,
modifiedDate: Moment().format("YYYY-MM-DD hh:mm:ss"),
blogId: this.state.blogId,
fileType: this.state.fileType,
fileName: this.state.fileName,
fileSize: this.state.fileSize,
filePayload: this.state.filePayload
};
const updateBlog = await blogtopicsService.editBlog(uploadData);
location.href = "/blog";
}, 1000);
}
};
handleClose = () => {
this.setState({ show: false });
};
handleShow = () => {
this.setState({ show: true });
};
onChange = async (e, blogId) => {
await this.setState({
[e.target.name]: e.target.value,
blogId: blogId
});
};
deleteBlog = blogId => {
confirmAlert({
customUI: ({ onClose }) => {
return (
<div className="custom-ui">
<h1>Are you sure</h1>
<p>You want to delete this blog?</p>
<button onClick={onClose}>Cancel</button>
<button
onClick={() => {
this.confirmDelete(blogId);
onClose();
}}
>
Confirm
</button>
</div>
);
}
});
};
confirmDelete = async blogId => {
// Delete the blog
const deleteBlog = await blogtopicsService.deleteBlog({ blog_id: blogId });
// Re-render the blog posts after deleting
await this.Selectblogtopics();
};
async componentDidMount() {
await this.userData();
await this.Selectblogtopics();
}
render() {
return (
<div className="fluid-container">
<div className="blogContainer">
<Header />
<Adminediting
title={this.props.match.path}
editState={this.editBlog}
/>
<div className="container">
<div className="editSection">
<div className="text-right">
<span className="data-tip-bottom" data-tip="Add Blog Post">
<i className="fas fa-plus" onClick={this.handleShow} />
</span>
</div>
</div>
<div className="blogContent">
{this.state.blogData.map((rows, index) => (
<div className="blogWrapper" key={index}>
{rows.blog_status === 1 ? (
<div
className="row"
>
<Modal show={this.state.show} onHide={this.handleClose}>
<Modal.Header closeButton>
<Modal.Title>Add Blog Post</Modal.Title>
</Modal.Header>
<Modal.Body>
<Addblogtopic
handleClose={this.handleClose}
selectblogTopics={this.Selectblogtopics}
/>
</Modal.Body>
</Modal>
<div className="col-md-4">
<img
src={
"https://s3-us-east-1.amazonaws.com/" +
rows.blog_thumbnail
}
alt="test"
/>
{this.state.isEditing === true ? (
<div className="input-group">
<input
type="file"
className="d-block mt-4"
name="blogPicture"
onChange={e => this.updateImage(e)}
/>
</div>
) : null}
</div>
<div className="col-md-6">
{this.state.isEditing === true ? (
<input
type="text"
name="blogCategory"
onChange={e => this.onChange(e, rows.blog_id)}
defaultValue={rows.blog_category}
/>
) : (
<Link
to={
"/blog/" +
rows.blog_id +
"/" +
appController.friendlyUrl(rows.blog_category)
}
id="blogUrl"
>
<h3
id="blogTopic"
dangerouslySetInnerHTML={{
__html: rows.blog_category
}}
/>
</Link>
)}
{this.state.roleId === 1 ? (
<div className="editSection">
<div className="text-right">
<span
className="data-tip-bottom"
data-tip="Delete Blog Post"
>
<i
className="far fa-trash-alt"
onClick={e => this.deleteBlog(rows.blog_id)}
/>
</span>
</div>
</div>
) : null}
<div
className={
this.state.hoverSelected == index
? "blogSection hover"
: "blogSection"
}
>
{this.state.isEditing === true ? (
<CKEditor
data={rows.blog_content}
onChange={(event, editor) => {
const data = event.editor.getData();
this.setState({
blogContent: data
});
}}
/>
) : rows.blog_content.length > 50 ? (
<div
className="cmsStyles"
dangerouslySetInnerHTML={{
__html: rows.blog_content.substr(0, 50) + " ..."
}}
/>
) : (
<div
className="cmsStyles"
dangerouslySetInnerHTML={{
__html: rows.blog_content
}}
/>
)}
</div>
</div>
</div>
) : null}
</div>
))}
</div>
</div>
</div>
<Footer />
</div>
);
}
}
export default Blogtopics;
Back End Data
var db = require("../dbconnection");
const AWS = require("aws-sdk");
var blog = {
insertblogPost: function(data, callback) {
var uniquePicture = "blogphoto" + "-" + data.fileName;
var awsFolder = "awsfolder" + "/" + uniquePicture;
db.query(
"insert blog_topics set blog_category=?, blog_thumbnail=?, blog_content=?, blog_author=?",
[data.blogTopic, uniquePicture, data.blogContent, "random user"]
);
var buf = new Buffer(
data.filePayload.replace(/^data:image\/\w+;base64,/, ""),
"base64"
);
//Upload file into AWS S3 Bucket
var s3 = new AWS.S3();
var params = {
Bucket: "testbucket",
Key: awsFolder,
Body: buf,
ContentType: data.fileType,
ACL: "public-read"
};
s3.putObject(params, function(err, data) {
if (err) {
console.log(err, err.stack);
} else {
return data;
}
}),
callback(true);
},
deleteBlog: function(data, callback) {
db.query(
"UPDATE blog_topics set blog_status=? where blog_id=?",
["0", data.blog_id],
callback
);
},
editBlog: function(data, callback) {
var uniquePicture = "blogphoto" + "-" + data.fileName;
var awsFolder = "awsfolder" + "/" + uniquePicture;
db.query(
"UPDATE blog_topics set blog_category=?, blog_thumbnail=?, blog_content=?, blog_author=?, modified_date=? where blog_id=?",
[
data.blogCategory,
uniquePicture,
data.blogContent,
"Test Username",
data.modifiedDate,
data.blogId
]
);
var buf = new Buffer(
data.filePayload.replace(/^data:image\/\w+;base64,/, ""),
"base64"
);
//Upload file into AWS S3 Bucket
var s3 = new AWS.S3();
var params = {
Bucket: "awsbucket",
Key: awsFolder,
Body: buf,
ContentType: data.fileType,
ACL: "public-read"
};
s3.putObject(params, function(err, data) {
if (err) {
console.log(err, err.stack);
} else {
return data;
//console.log(data);
}
}),
callback(true);
},
selectblogTopics: function(data, callback) {
db.query(
"select blog_id, blog_category, blog_thumbnail, blog_content, blog_status, blog_author, created_date, modified_date from blog_topics",
callback
);
},
selectblogArticle: function(data, callback) {
db.query(
"select blog_id, blog_category, blog_thumbnail, blog_content, blog_author, created_date from blog_topics where blog_id=?",
[data.blogId],
callback
);
},
editArticle: function(data, callback) {
var uniquePicture = "blogphoto" + "-" + data.fileName;
var awsFolder = "awsfolder" + "/" + uniquePicture;
db.query(
"UPDATE blog_topics set blog_category=?, blog_thumbnail=?, blog_content=?, blog_author=?, modified_date=? where blog_id=?",
[
data.blogCategory,
uniquePicture,
data.blogContent,
"test user",
data.modifiedDate,
data.blogId
]
);
var buf = new Buffer(
data.filePayload.replace(/^data:image\/\w+;base64,/, ""),
"base64"
);
//Upload file into AWS S3 Bucket
var s3 = new AWS.S3();
var params = {
Bucket: "awsfolder",
Key: awsFolder,
Body: buf,
ContentType: data.fileType,
ACL: "public-read"
};
s3.putObject(params, function(err, data) {
if (err) {
console.log(err, err.stack);
} else {
return data;
}
}),
callback(true);
}
};
module.exports = blog;
You can create a generic method to update all blog info.
setBlogProperty(index, propName, propValue) {
this.setState(state => {
state.blogData[index][propName] = propValue;
return state;
});
};
Then call this method on onChange event of your input element.
<input
type="text"
name="blogCategory"
onChange={e => this.setBlogProperty(index, 'blog_category', e.target.value)}
defaultValue={rows.blog_category}
/>
I have a JSON file called by a fetch() request. I have two input of type="range" .I want to merge the two.
Something like this.
I'd like to make the double slider , however if I position two elements on top of one another, only the top one is accepting mouse clicks. I do not wish to use any external library in React for the slider or the space between the two handlers, which is colourised.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
library: null,
librarySecond: null,
perPage: 20,
currentPage: 1,
maxPage: null,
filterTotalF: "",
filterTotalS: "",
rangevalTotalF: "",
rangevalTotalS: ""
};
}
componentDidMount() {
fetch("/json,bc", {
method: "get"
})
.then(response => response.text())
.then(text => {
let Maindata = JSON.parse(text.replace(/\'/g, '"'));
this.setState(
state => ({
...state,
data: Maindata
}),
() => {
this.reorganiseLibrary();
}
);
})
.catch(error => console.error(error));
}
reorganiseLibrary = () => {
const { filterTotalF, filterTotalS, perPage, data } = this.state;
let library = data;
let librarySecond = data;
librarySecond = _.chunk(librarySecond, perPage);
this.setState({
librarySecond,
currentPage: 1,
maxPage: librarySecond.length === 0 ? 1 : librarySecond.length
});
let defaultFilterF = null;
defaultFilterF = filterTotalF
? filterTotalF
: this.renderMinFilter(librarySecond);
let defaultFilterS = null;
defaultFilterS = filterTotalS
? filterTotalS
: this.renderMaxFilter(librarySecond);
if (defaultFilterF !== "" && defaultFilterS !== "") {
library = library.filter(
item =>
item.totalCom >= defaultFilterF && item.totalCom <= defaultFilterS
);
}
if (filterExitTimeDepF !== "" && filterExitTimeDepS !== "") {
library = library.filter(
item =>
this.rendershowexittimeDep(
item.info.departureinformation.ticketinfooo.exitinfo.showexittime
) >= filterExitTimeDepF &&
this.rendershowexittimeDep(
item.info.departureinformation.ticketinfooo.exitinfo.showexittime
) <= filterExitTimeDepS
);
}
if (filterExitTimeDesF !== "" && filterExitTimeDesS !== "") {
library = library.filter(
item =>
this.rendershowexittimeDes(
item.info.returninformation.ticketinfooo.exitinfo.showexittime
) >= filterExitTimeDesF &&
this.rendershowexittimeDes(
item.info.returninformation.ticketinfooo.exitinfo.showexittime
) <= filterExitTimeDesS
);
}
library = _.chunk(library, perPage);
this.setState({
library,
currentPage: 1,
maxPage: library.length === 0 ? 1 : library.length
});
};
renderMinFilter = librarySecond => {
return librarySecond.reduce((acc, lib) => {
const libMin = Math.min(...lib.map(item => item.totalCom));
return acc === undefined ? libMin : libMin < acc ? libMin : acc;
}, undefined);
};
renderMaxFilter = librarySecond => {
return librarySecond.reduce((acc, lib) => {
const libMax = Math.max(...lib.map(item => item.totalCom));
return libMax > acc ? libMax : acc;
}, 0);
};
// Previous Page
previousPage = event => {
this.handleClick(event);
this.setState({
currentPage: this.state.currentPage - 1
});
};
// Next Page
nextPage = event => {
this.handleClick(event);
this.setState({
currentPage: this.state.currentPage + 1
});
};
// handle filter
handleFilterTotal = evt => {
let value = evt.target.value;
let key = evt.target.getAttribute("data-key");
if (key == "1") {
this.setState(
{
filterTotalF: evt.target.value,
rangevalTotalF: evt.target.value
},
() => {
this.reorganiseLibrary();
}
);
} else if (key == "2") {
this.setState(
{
filterTotalS: evt.target.value,
rangevalTotalS: evt.target.value
},
() => {
this.reorganiseLibrary();
}
);
}
};
// handle per page
handlePerPage = evt =>
this.setState(
{
perPage: evt.target.value
},
() => this.reorganiseLibrary()
);
// handle render of library
renderLibrary = () => {
const { library, currentPage } = this.state;
if (!library || (library && library.length === 0)) {
return (
<div className="nodata">
<div className="tltnodata">برای جستجوی شما نتیجه ای یافت نشد!</div>
<div className="textnodata">
شما می توانید با انجام مجدد عملیات جستجو,نتیجه مورد نظر خود را
بیابید
</div>
</div>
);
}
return library[currentPage - 1]
.sort((a, b) => a.total - b.total)
.map((item, i) => (
<div className="item">
<span>{item.id}</span>
</div>
));
};
renderMinTotal = () => {
const { librarySecond } = this.state;
if (!librarySecond || (librarySecond && librarySecond.length === 0)) {
return "";
}
return librarySecond.reduce((acc, lib) => {
const libMin = Math.min(...lib.map(item => item.totalCom));
return acc === undefined ? libMin : libMin < acc ? libMin : acc;
}, undefined);
};
renderMaxTotal = () => {
const { librarySecond } = this.state;
if (!librarySecond || (librarySecond && librarySecond.length === 0)) {
return "";
}
return librarySecond.reduce((acc, lib) => {
const libMax = Math.max(...lib.map(item => item.totalCom));
return libMax > acc ? libMax : acc;
}, 0);
};
render() {
const {
library,
currentPage,
perPage,
maxPage,
rangevalTotalF,
rangevalTotalS,
librarySecond
} = this.state;
let defaultRangeF = null;
defaultRangeF = rangevalTotalF ? (
<span>{rangevalTotalF}</span>
) : (
<span>{this.renderMinTotal()}</span>
);
let defaultRangeS = null;
defaultRangeS = rangevalTotalS ? (
<span>{rangevalTotalS}</span>
) : (
<span>{this.renderMaxTotal()}</span>
);
return (
<div>
<div className="filter-box">
<div className="wrapper">
<input
type="range"
min={this.renderMinTotal()}
max={this.renderMaxTotal()}
defaultValue={this.renderMaxTotal()}
step="1000"
onChange={this.handleFilterTotal}
data-key="2"
className="exitTimeSecond"
/>
<div className="rangevalSecond">{defaultRangeS}</div>
</div>
<div className="wrapper">
<input
type="range"
min={this.renderMinTotal()}
max={this.renderMaxTotal()}
defaultValue={this.renderMinTotal()}
step="1000"
onChange={this.handleFilterTotal}
data-key="1"
className="exitTimeFirst"
/>
<div className="rangevalFirst">{defaultRangeF}</div>
</div>
</div>
{this.renderLibrary()}
<ul id="page-numbers">
<li className="nexprevPage">
{currentPage !== 1 && (
<button onClick={this.previousPage}>
<span className="fa-backward" />
</button>
)}
</li>
<li className="controlsPage active">{this.state.currentPage}</li>
<li className="restControls">...</li>
<li className="controlsPage">{this.state.maxPage}</li>
<li className="nexprevPage">
{currentPage < maxPage && (
<button onClick={this.nextPage}>
<span className="fa-forward" />
</button>
)}
</li>
</ul>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("Result"));
so I follow up this documentation for creating a editable row; It's a CSS library for React from Ant Design, I am stuck at the following:
How do I pass the changed row, the newData[index] to an onChange event?
How do I update a set of row of data to a back-end rest api? I managed to create data using form from Ant Design, but I don't know how to update it using editable row
Fyi, the back end works perfectly with postman: create, update, delete
How do I get the id of this code?
axios.put("/api/product/update/:id"
I tried to replace the id with ${id}, ${index}, ${products[index]} (with template literal) but it doesn't work.
Here are the full code:
import React from 'react';
import axios from 'axios';
import { Table, Input, InputNumber, Popconfirm, Form } from 'antd';
const FormItem = Form.Item;
const EditableContext = React.createContext();
const EditableRow = ({ form, index, ...props }) => (
<EditableContext.Provider value={form}>
<tr {...props} />
</EditableContext.Provider>
);
const EditableFormRow = Form.create()(EditableRow);
class EditableCell extends React.Component {
getInput = () => {
if (this.props.inputType === 'number') {
return <InputNumber />;
}
return <Input />;
};
render() {
const {
editing,
dataIndex,
title,
inputType,
record,
index,
...restProps
} = this.props;
return (
<EditableContext.Consumer>
{(form) => {
const { getFieldDecorator } = form;
return (
<td {...restProps}>
{editing ? (
<FormItem style={{ margin: 0 }}>
{getFieldDecorator(dataIndex, {
rules: [{
required: true,
message: `Please Input ${title}!`,
}],
initialValue: record[dataIndex],
})(this.getInput())}
</FormItem>
) : restProps.children}
</td>
);
}}
</EditableContext.Consumer>
);
}
}
class EditableTable extends React.Component {
constructor(props) {
super(props);
this.state = { products: [], editingKey: '' };
this.columns = [
{
title: 'Product Name',
dataIndex: 'productname',
width: '25%',
editable: true,
},
{
title: 'OS',
dataIndex: 'os',
width: '10%',
editable: true,
},
{
title: 'Category',
dataIndex: 'category',
width: '15%',
editable: true,
},
{
title: 'Model',
dataIndex: 'model',
width: '20%',
editable: true,
},
{
title: 'Serial Number',
dataIndex: 'serialnumber',
width: '20%',
editable: true,
},
{
title: 'Operation',
dataIndex: 'operation',
width: '10%',
render: (text, record) => {
const editable = this.isEditing(record);
return (
<div>
{editable ? (
<span>
<EditableContext.Consumer>
{form => (
<a
href="javascript:;"
onClick={() => this.save(form, record.id)}
style={{ marginRight: 8 }}
>
Save
</a>
)}
</EditableContext.Consumer>
<Popconfirm
title="Sure to cancel?"
onConfirm={() => this.cancel(record.id)}
>
<a>Cancel</a>
</Popconfirm>
</span>
) : (
<a onClick={() => this.edit(record.id)}>Edit</a>
)}
</div>
);
},
},
];
}
handleCategoryChange = event => { this.setState({ category: event.target.value }) }
handleProductNameChange = event => { this.setState({ productname: event.target.value }) }
handleOsNameChange = event => { this.setState({ os: event.target.value }) }
handleModelchange = event => { this.setState({ model: event.target.value }) }
handleSerialnumberChange = event => { this.setState({ serialnumber: event.target.value }) }
handlePriceChange = event => { this.setState({ price: event.target.value }) }
handleEquipmentChange = event => { this.setState({ equipment_condition: event.target.value }) }
handleDetailChange = event => { this.setState({ detail: event.target.value }) }
handleImageChange = event => { this.setState({ image: event.target.value }) }
handleSubmit = event => {
event.preventDefault();
axios.put(`/api/product/update/:id`,
{
category: this.state.category,
productname: this.state.productname,
os: this.state.os,
serialnumber: this.state.serialnumber,
model: this.state.model,
price: this.state.price,
equipment_condition: this.state.equipment_condition,
detail: this.state.detail,
image: this.state.image
})
}
componentDidMount() {
axios.get('/api/product').then(res => {
this.setState({ products: res.data });
});
}
isEditing = (record) => {
return record.id === this.state.editingKey;
};
edit(id) {
console.log('products', this.state.products.id);
// console.log('recordid', record.id);
this.setState({ editingKey: id });
}
save(form, id) {
console.log('key', id)
form.validateFields((error, row) => {
if (error) {
return;
}
const newData = [...this.state.products];
const index = newData.findIndex(item => id === item.id);
if (index > -1) {
const item = newData[index];
newData.splice(index, 1, { ...item, ...row, });
this.setState({ products: newData, editingKey: '' });
console.log('newData', newData[index]) // data I want to update to API
console.log('category', newData[index].category) // category
} else {
newData.push(this.state.products);
this.setState({ products: newData, editingKey: '' });
}
});
}
cancel = () => {
this.setState({ editingKey: '' });
};
render() {
const components = {
body: {
row: EditableFormRow,
cell: EditableCell,
},
};
const columns = this.columns.map((col) => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: record => ({
record,
inputType: col.dataIndex === 'serialnumber' ? 'number' : 'text',
dataIndex: col.dataIndex,
title: col.title,
editing: this.isEditing(record),
}),
};
});
return (
<Table
rowKey={this.state.id}
components={components}
bordered
dataSource={this.state.products}
columns={columns}
rowClassName="editable-row"
/>
);
}
}
export default EditableTable;
Update:
So I try put axios inside the save method, like so:
save(form, id) {
form.validateFields((error, row) => {
if (error) {
return;
}
const newData = [...this.state.products];
const index = newData.findIndex(item => id === item.id);
if (index > -1) {
const item = newData[index];
newData.splice(index, 1, { ...item, ...row, });
this.setState({ products: newData, editingKey: '' });
console.log('newData', newData[index]) // data I want to update to API
console.log('index', index) // index adalah index array
console.log('id', id) // id adalah nomor index dalam tabel database, jangan sampai tertukar
console.log('category', newData[index].category)
console.log('productname', newData[index].productname)
console.log('os', newData[index].os)
console.log('serialnumber', newData[index].serialnumber)
console.log('model', newData[index].model)
console.log('detail', newData[index].detail)
axios.put(`/api/product/update/:${id}`,
{
category: newData[index].category,
productname: newData[index].productname,
os: newData[index].os,
serialnumber: newData[index].serialnumber,
model: newData[index].model,
price: newData[index].price,
equipment_condition: newData[index].equipment_condition,
detail: newData[index].detail,
image: newData[index].image
})
} else {
newData.push(this.state.products);
this.setState({ products: newData, editingKey: '' });
}
});
It doesn't update the data on the database.
Someone might still need this, The antd table api.
You can pass the render key in your column with one to three parameters depending on what you need
function(text, record, index) {}
The column will look like this:
const column = [{
dataIndex: "firstName",
render: (text, record, index) => console.log(text, record, index)
}]
So there's this weird syntax that I have to remove from the url api.
Pay attention to the very minor details of the url; I noticed it from the console log from the back end / node:
axios.put(`/api/product/update/${id}`,
{
category: newData[index].category,
productname: newData[index].productname,
os: newData[index].os,
serialnumber: newData[index].serialnumber,
model: newData[index].model,
price: newData[index].price,
equipment_condition: newData[index].equipment_condition,
detail: newData[index].detail,
image: newData[index].image
})