Converting xml file data in js object - reactjs

I need some help. I have an app that takes *.xml file through input type file, and converts it into js object.
To do that i am using FileReader and xml-js library from here https://www.npmjs.com/package/xml-js
Now I have two problems that I can't handle.
xml file contains cyrillic symbols, in console they display as ������� ��� ���
The second problem is that, in some reasons, I can't set converted object in state.
Here is my code:
Handler and input for file:
handleFile = (event) => {
let file = event.target.files[0];
let reader = new FileReader();
reader.readAsText(file);
reader.onloadend = () => {
let json = xmljs.xml2js(reader.result, {compact: true, spaces: 4});
this.setState({
file: json
}, console.log ('file', json))
}
};
render() {
return (
<div>
<input type="file" onChange={this.handleFile}/>
</div>
)
}
So what shouls I do to display cyrillic symbols and how to set the object in state?

I fixed it.
Now my code looks so:
handleFile = (event) => {
let file = event.target.files[0];
let reader = new FileReader();
reader.readAsText(file, 'windows-1251');
reader.onloadend = () => {
let json = xmljs.xml2js(reader.result, {compact: true, spaces: 4});
this.setState({
file: json
}, () => {console.log('state', this.state)})
}
};
render() {
return (
<div>
<input type="file" onChange={this.handleFile}/>
</div>
)
}
I added 'windows-1251' to define the encoding type, it helps with cyrillic symbols.
Also i changed callback function after setState to () => {console.log('state', this.state)} after that I can see a current state, with contetnt fron xml file.

Related

React.js logging before operation is finished

onReaderLoad = (e) => {
var obj =JSON.parse(e.target.result)
this.setState(prevState => ({
datasource: [...prevState.datasource, obj]
}))
}
ReadFiles = () => {
let files = this.state.json_files;
for (let i of files){
var reader = new FileReader();
reader.onload = this.onReaderLoad;
reader.readAsText(i);
}
console.log(this.state.datasource)
}
getfolder = (e) => {
var files = e.target.files;
this.setState({
json_files: files
}, () => this.ReadFiles())
}
<input type="file" onChange={this.getfolder} multiple accept=".json" />
Here i am sharing my code.
What i am trying to do is i am reading all the json files from user input and looping them and storing it to react state.
Then inside ReadFiles() function i am logging the state data. But it is always coming empty data.
I think it calling first and then going to the loop.
I wants to log the datasource data from state inside ReadFiles() function after all Looping operation is done
Is there any way to do that ?
Please have a look
You can make use of instance variable in this case to keep track of whether you are processing last file or not. Once you know that last file is being processed, you can set doNextStep to true in state from callback of last processed file. Then in componentDidUpdate, you can do next step(i.e. console log or anything else).
class Example extends React.Component {
constructor(props){
super(props);
// to keep track of if last file is being processed
this.lastFile = false;
// doNextStep will tell us that all setState operations are completed or not
this.state = {
doNextStep: false,
}
}
componentDidUpdate(prevProps, prevState) {
if(prevState.doNextStep !== this.state.doNextStep && this.state.doNextStep) {
console.log(this.state.datasource)
}
}
onReaderLoad = (e) => {
var obj =JSON.parse(e.target.result)
this.setState(prevState => ({
datasource: [...prevState.datasource, obj]
}),
() => if(this.lastFile)) this.setState({doNextStep: true}))
}
ReadFiles = () => {
let files = this.state.json_files;
for (i=0; i<files.length; i++){
if(i == files.length - 1) this.lastFile = true
else this.lastFile = false
var reader = new FileReader();
reader.onload = this.onReaderLoad;
reader.readAsText(i);
}
}
}

React Ant Design multiple files upload doesn't work

I'm in the process of sending multiple files from "React.js" by formData.append() to a backend.
At the backend(Spring boot), I was able to see that multiple files were saved well with postman.
The problem occurred in React.
(I'm using "Ant Design" that is React UI Library.)
Below is the source that append files to formdata with extra data.
const formData = new FormData();
formData.append('webtoonId', this.state.selectedToonId);
formData.append('epiTitle', this.state.epiTitle);
formData.append('eFile', this.state.thumbnail[0].originFileObj);
for( let i = 0; i< this.state.mains.length ; i++){
formData.append('mFiles', this.state.mains[i].originFileObj);
}
uploadEpi(formData)
uploadEpi() is POST API.
Below is about state.
this.state = {
toons: [],
epiTitle :'',
thumbnail : [],
mains : [],
selectedToonID : ''
}
When I submit, Text and single file are stored in the DB normally, but only multiple files cannot be saved.
There was no error. Just multiple files didn't be saved.
The state "mains" is configured as shown below.
I guess it's because I'm using Ant Design incorrectly.
(Ant Design : https://ant.design/components/upload/)
Why I guessed so, because when I add multiple attribute to <Dragger> like below,
<Dragger onChange={this.onChangeMain} beforeUpload={() => false} multiple={true}>
the state "mains" multiple files became undefined.
Below is onChange={this.onChangeMain}
onChangeMain=({ fileList })=> {
this.setState({ mains : fileList }, function(){
console.log(this.state)
});
}
The bottom line is, I want to know how to upload multiple files through <Upload> (or <Dragger>) in "React Ant Design."
I don't know what should I do.
this is my github about this project.
I'd appreciate with your help. thx.
const [loading, setLoading] = useState<boolean>(false);
const [fileList, setFileList] = useState<any[]>([]);
const [/* fileListBase64 */, setFileListBase64] = useState<any[]>([]);
const propsUpload = {
onRemove: (file:any) => {
const index = fileList.indexOf(file);
const newFileList:any = fileList.slice();
newFileList.splice(index, 1);
return setFileList(newFileList)
},
beforeUpload: (file:any) => {
setFileList([...fileList, file]);
return false;
},
onChange(info:any) {
setLoading(true);
const listFiles = info.fileList;
setFileList(listFiles);
const newArrayFiles = listFiles.map((file:any) => file.originFileObj? (file.originFileObj) : file );
const anAsyncFunction = async (item:any) => {
return convertBase64(item)
}
const getData = async () => {
return Promise.all(newArrayFiles.map((item:any) => anAsyncFunction(item)))
}
getData().then(data => {
/* setFileSend(data) */
setFileListBase64(data);
setLoading(false);
// console.log(data);
});
},
directory: true,
fileList: fileList,
};
const convertBase64 = (file:File) => {
return new Promise((resolve, reject) => {
const fileReader = new FileReader();
fileReader.readAsDataURL(file)
fileReader.onload = () => {
resolve(fileReader?.result);
}
fileReader.onerror = (error) => {
reject(error);
}
})
}
const handleDeleteListFiles = () => {
setFileList([]);
setFileListBase64([]);
}
It seems like you are overriding the value of mFiles.
const formData = new FormData();
formData.append('webtoonId', this.state.selectedToonId);
formData.append('epiTitle', this.state.epiTitle);
formData.append('eFile', this.state.thumbnail[0].originFileObj);
let mFiles = [];
for( let i = 0; i< this.state.mains.length ; i++){
mFiles[i] = this.state.mains[i].originFileObj;
}
formData.append('mFiles', mFiles)
uploadEpi(formData)
Maybe this can work: formData.append('mFiles[]', mFiles)
If you add [] to the string it should not overwrite but add to the array

React Laravel - File showing in state but not in controller

My project has React as frontend and Laravel as backend.
I am trying to upload a file and the details of the file appear in state while uploading but not in the controller and hence not able to upload it in folder.
Component has
<div className="form-group col-sm-4">
<div className="imgPreview">{$imagePreview}</div>
<label>Profile Pic</label>
<input className="form-control" type="file" name="profile_pic" onChange={(e)=>this._handleImageChange(e)}/>
</div>
further codes are:
_handleImageChange(e) {
e.preventDefault();
let reader = new FileReader();
let file = e.target.files[0];
reader.onloadend = () => {
this.setState({
fileselected: file,
profile_pic: file.name,
imagePreviewUrl: reader.result
});
}
reader.readAsDataURL(file)
}
Data gets uploaded though axios
submitHandler = e =>{
e.preventDefault()
this.props.drprofilecreate(this.state)
}
export const drprofilecreate = (data) => dispatch =>{
console.log("Coming form profile create action ")
console.log(data)
return axios.post('/api/v1/drProfileCreate', data)
.then( res =>res.data )
.then(drprofile =>
dispatch({
type: DRPROFILECREATE,
payload: drprofile,
}),
)
}
When I view the data being uploaded, it shows the file with its details like name, size etc. But the same does not come in the controller. It shows a blank array.
public function drProfileCreate(Request $request){
$data = $request->all();
$response = [
'success' =>true,
'datax' =>'Dr Profile uploaded in Contorller. Check',
'data' => $data
];
return response()->json($response, 201);
}
Hence Iam not able to upload the image. Help please. Appreciated

MERN+ Cloudinary: Unsupported source URL

I'm trying to upload file to cloudinary. Here is part of my react component
...
addItem() {
...
let file = this.fileInput.value;
keywords !== "" && this.props.onAddItem(keywords, place, image);
...
}
render() {
return (
....
<Input
type="file"
innerRef={(input) => {this.fileInput = input}}
name="image"
id="image"
placeholder=""/>
)
}
Here is action file:
export function onAddItem(keywords, place, file, id, isChangebale = false) {
return (dispatch) => {
axios.all([
axios.post('https://api.cloudinary.com/v1_1/myservername/image/upload',
{upload_preset: "mypresetname", file: file}),
axios.post('http://localhost:3001/api/items/', { keywords, place, id, isChangebale })
])
.then(axios.spread((cloudinaryRes, localRes) => {
console.log(cloudinaryRes, localRes);
}))
I receive error xhr.js:178 POST https://api.cloudinary.com/v1_1/testovich/image/upload 400 (Bad Request) and in response headers "X-Cld-Error: Unsupported source URL: C:\fakepath\2017-12-07_19-06-445.png"
When I test using postman I have correct response.
So it looks like I do something wrong when pass file from rect component to action file. How to pass correct path/file to cloudinary?
There were two mistakes:
1. in react component there should be
let file = this.fileInput.files[0];//I upload only one file
instead of
let file = this.fileInput.value;
in action file
export function onAddItem(keywords, place, image, id, isChangebale = false) {
const formData = new FormData();
formData.append("file", image);
formData.append("upload_preset", "mypresetname");
return (dispatch) => {
axios.all([
// AJAX upload request using Axios )
axios.post('https://api.cloudinary.com/v1_1/myservername/image/upload',
formData,
instead of:
export function onAddItem(keywords, place, file, id, isChangebale = false) {
return (dispatch) => {
axios.all([
axios.post('https://api.cloudinary.com/v1_1/myservername/image/upload',
{upload_preset: "mypresetname", file: file}),
Convert the image to a base64 like const base64Img = data:image/jpg;base64,${file.data};
The file.data represents the data property from response from image picker.
Then I passed the base64Img to data like
return RNFetchBlob.fetch('POST', apiUrl, headerProps, [ { name: 'file', fileName: file.fileName, type: file.type, data: base64Img } ]);
Hope it helps.

Confused on blob:url and converting it to base64 in react-dropzone

I am using the package react-dropzone (https://github.com/okonet/react-dropzone) to get images from the user. The user uploads their image and everything is fine, but Im only getting something like "blob:http//blahblah" from it and I need the image to be in base64 png.
my dropzone component:
<Dropzone ref="dropzone" multiple={false} onDrop={this.onDrop.bind(this)} >
{this.state.files ?<img className="img-responsive" src={this.state.files[0].preview}></img>
: <div>Upload Photo</div> }
</Dropzone>
and the drop function that gets the blob url :
onDrop (files ) {
if ( files.length === 0 ) {
alert("upload img please")
return;
}
console.log('Received files: ', files);
this.setState({files:files})
var blobURL = files[0].preview
var reader = new FileReader();
reader.readAsDataURL(blobURL)
}
I would get an error :Uncaught TypeError: Failed to execute 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob'.
I think it is because im trying to pass in an object-url that points to a blob, but where would I be able to get blob so I can convert to base64?
I would suggest to use a promise to get the result of async convertion by FileReader.readAsDataURL method. Here's the sample how it can be done:
const promise = new Promise((resolve, reject) => {
const reader = new FileReader()
reader.readAsDataURL(files[0])
reader.onload = () => {
if (!!reader.result) {
resolve(reader.result)
}
else {
reject(Error("Failed converting to base64"))
}
}
})
promise.then(result => {
// dispatch or do whatever you need with result
}, err => {
console.log(err)
})

Resources