반응형
이전 - (18) FileUpload에 대한 이벤트 보완
현재 - (19) 불러오기 버튼 추가하기
파일이 업로드 된 후, drag & drop 영역이 사라졌기 때문에, 다시 파일을 불러오려면 새로고침을 해야한다.
따라서 불러오기 버튼을 추가하자.
불러오기 버튼은 FileUpload에 추가하도록 하자.
따라서 App.js에서 MyTable과 FileUpload 위치를 바꾼다.
<div className="App">
<FileUpload setCsvObject={setCsvObject} />
<MyTable csvFile={csvObject}/>
</div>
input의 파일 선택 버튼을 일반 버튼에 연결하려면, input 파일을 hidden으로 만들어서 event로 연결한다.
자세한 설명은 링크를 참고하자.
fileUploadFlag가 true가 되면 ( ) 안의 input이 사라지기 때문에 getElementById로 찾을 수 없다.
따라서 input을 하나 더 만들고 hidden으로 숨겨둔다.
const onClickFileLoad = () => {
let my_input = document.getElementById("my-input");
my_input.click();
}
return (
<div>
<button onClick={onClickFileLoad}>불러오기</button>
<input
id="my-input"
style={{visibility : "hidden"}}
type="file"
accept=".csv"
onChange={(e) => lib.handleUpload(e, setCsvObject, flagOn)}
/>
...
아래와 같이 불러오기 버튼이 생겼다.
그리고 input에 handleUpload를 그대로 연결하였기 때문에 정상적으로 동작한다.
그러나 불러오기는 file이 업로드 된 후 나타나면 되므로 아래처럼 고친다.
{fileUploadFlag && <button onClick={onClickFileLoad}>불러오기</button>}
이제 파일을 불러온 후 불러오기 버튼이 나타난다.
하지만 이전 table이 계속 남아 있게 된다.
myTable을 만들 때, 이미 table이 있는 경우에 기존 myTable을 destory하는 것으로 위의 버그를 해결할 수 있다.
const init = (csvFile) => {
if (csvFile === undefined || csvFile.HEIGHT === 0) return;
const container = document.getElementById("hot-app");
if(myTable !== undefined) myTable.destroy();
myTable = new Handsontable(container, {
...
});
};
최종 코드는 아래와 같다.
//App.js
import React, { useState } from "react";
//import * as lib from "./components/library";
import FileUpload from "./components/FileUpload";
import MyTable from "./components/MyTable";
//import ReduxTest from "./components/ReduxTest";
//import AnotherReduxTest from "./components/AnotherReduxTest";
const csvObjectDefault = {
HEIGHT: 0,
WIDTH: 0,
csv: [],
};
const App = () => {
const [csvObject, setCsvObject] = useState(csvObjectDefault);
return (
<div>
{/* <ReduxTest/>
<AnotherReduxTest/> */}
<button onClick={() => console.log(csvObject)}>print csv</button>
<div className="App">
<FileUpload setCsvObject={setCsvObject} />
<MyTable csvFile={csvObject}/>
</div>
</div>
);
};
export default App;
// FileUpload.js
import React, { useState } from "react";
import { connect } from "react-redux";
import { actionCreators } from "./store";
import * as lib from "./library.js";
import "../css/FileUpload.scss";
const FileUpload = ({ setCsvObject, fileUploadFlag, flagOn, flagOff }) => {
const [dropFlag, setDropFlag] = useState(false);
const onClickFileLoad = () => {
let my_input = document.getElementById("my-input");
my_input.click();
};
return (
<div>
{fileUploadFlag && <button onClick={onClickFileLoad}>불러오기</button>}
<input
id="my-input"
style={{ visibility: "hidden" }}
type="file"
accept=".csv"
onChange={(e) => lib.handleUpload(e, setCsvObject, flagOn)}
/>
{!fileUploadFlag && (
<div
id="drag-drop-field"
className={dropFlag ? "in" : ""}
onDrop={(e) => lib.handleOnDrop(e, setDropFlag, setCsvObject, flagOn)}
onDragOver={(e) => lib.handleDragOver(e, setDropFlag)}
onDragLeave={(e) => lib.handleOnDragLeave(e, setDropFlag)}
>
<p>drag & drop</p>
<input
type="file"
accept=".csv"
onChange={(e) => lib.handleUpload(e, setCsvObject, flagOn)}
/>
</div>
)}
</div>
);
};
function mapStateToProps(state, ownProps) {
//console.log(state);
return { fileUploadFlag: state };
}
function mapDispatchToProps(dispatch, ownProps) {
return {
flagOn: () => dispatch(actionCreators.flagOn()),
flagOff: () => dispatch(actionCreators.flagOff()),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(FileUpload);
//MyTable.js
import React, { useEffect, useState } from "react";
import { connect } from "react-redux";
import * as lib from "./library.js";
import "handsontable/dist/handsontable.full.css";
import Handsontable from "handsontable";
let myTable;
let currentRow, currentColumn;
const getCell = (cell) => {
if(cell === null) return ``;
return cell.includes(",") ? `"${cell}"` : `${cell}`;
}
const csvDownLoad = () => {
let rows = myTable.countRows();
let cols = myTable.countCols();
let tmpTables = myTable.getData(0, 0, rows - 1, cols - 1);
let maxRow, maxCol;
maxCol = 0;
for(let r = 0; r < rows; r++) {
for(let c = cols - 1; c >=0; c--) {
if(!(tmpTables[r][c] === "" || tmpTables[r][c] === null)) {
maxCol = (maxCol < c) ? c : maxCol;
break;
}
}
}
maxRow = 0;
for(let c = 0; c < cols; c++) {
for(let r = rows - 1; r >=0; r--) {
if(!(tmpTables[r][c] === "" || tmpTables[r][c] === null)) {
maxRow = (maxRow < r) ? r : maxRow;
break;
}
}
}
let parsing = myTable.getData(0, 0, maxRow, maxCol)
.map((item) => item.map((cell) => getCell(cell)));
let realTable = parsing.map((item) => item.join(",")).join("\n");
lib.downLoadCsv(realTable);
return;
};
const MyTable = ({ csvFile, fileUploadFlag }) => {
const [displayIndex, setDisplayIndex] = useState("");
const [displayCell, setDisplayCell] = useState("");
const selectCell = () => {
let selected = myTable.getSelectedLast();
currentRow = selected[0];
currentColumn = selected[1];
if(currentRow < 0 || currentColumn < 0) return;
setDisplayCell(myTable.getValue());
setDisplayIndex(`${lib.rowToAlpha(currentColumn + 1)}${currentRow + 1}`);
}
const setValueCell = (e) => {
if(currentRow < 0 || currentColumn < 0) return;
setDisplayCell(e.target.value);
myTable.setDataAtCell(currentRow, currentColumn, e.target.value);
}
const init = (csvFile) => {
if (csvFile === undefined || csvFile.HEIGHT === 0) return;
const container = document.getElementById("hot-app");
if(myTable !== undefined) myTable.destroy();
myTable = new Handsontable(container, {
data: lib.makeTable(csvFile, 2, 3),
colHeaders: true, /* column header는 보이게 설정 */
rowHeaders: true, /* row header 보이게 설정 */
colWidths: [60, 60, 60, 60, 60, 60, 60],
wordWrap: false, /* 줄 바꿈 x */
width: "50%",
manualColumnResize: true, /* column 사이즈 조절 */
manualRowResize: true, /* row 사이즈 조절 */
manualColumnMove: true, /* column move 허용 */
manualRowMove: true, /* row move 허용 */
dropdownMenu: true, /* dropdown 메뉴 설정 */
filters: true, /* 필터 기능 on */
contextMenu: true, /* cell 클릭 시 메뉴 설정 */
licenseKey: "non-commercial-and-evaluation",
afterSelection: selectCell,
});
};
useEffect(() => {
init(csvFile);
}, [csvFile]);
return (
<div>
{fileUploadFlag && (
<div>
<button onClick={csvDownLoad}>DOWNLOAD</button>
<div>
<span>{displayIndex}</span>
<input value={displayCell} onChange={setValueCell} />
</div>
<div id="hot-app"></div>
</div>
)}
</div>
);
};
function mapStateToProps(state, ownProps) {
//console.log(state);
return { fileUploadFlag: state };
}
export default connect(mapStateToProps)(MyTable);
이전 - (18) FileUpload에 대한 이벤트 보완
반응형
'개발 > React' 카테고리의 다른 글
리액트 라우터 - URL query string 받아오기 (0) | 2022.02.07 |
---|---|
리액트 같은 이름의 파일 재업로드 (같은 파일 다시 열기) (0) | 2021.12.03 |
React Handsontable로 csv 편집기 만들기 (18) (0) | 2021.06.28 |
React Handsontable로 csv 편집기 만들기 (17) (0) | 2021.06.26 |
React Handsontable로 csv 편집기 만들기 (16) (0) | 2021.06.14 |
댓글