JSON.stringify()函数将文件对象替换为一个空对象 [英] JSON.stringify() function is replacing the file object with an empty one

查看:115
本文介绍了JSON.stringify()函数将文件对象替换为一个空对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好,有人可以帮我解决这个复杂的问题吗?:我正在使用Spring Boot v2.0.5和React.js v15.6.2,ReactDom v15.6.2,React Bootstrap v0.32.4创建应用程序,并且前端和服务器端部分之间的链接是通过在Web上使用Spring注释的静态Web服务组成的.后面的API以及前面的API.我的React组件是按照父子设计模式的概念制作的,这意味着:我的某些组件可以是其他组件的子组件,反之亦然.

Hello guys, can anyone please help me to solve this complicated issue? : I'm creating an application using Spring boot v2.0.5 and React.js v15.6.2, ReactDom v15.6.2, React Bootstrap v0.32.4, and the linking between my frontend and serverside parts is made of restful web services using Spring annotations on the back and fetch API on the front. My React components are made by following the Parent-Children design pattern concept, that means: some of my components can be children of some others and vice versa.

它如何工作?

我有一个具有列和行的表,表中的每一行都有一个唯一的ID,2个下拉菜单,1个文本输入,2个日期选择器和 1个导致主要问题的文件上传输入;通过单击"+文档"按钮,用户可以添加更多具有与以前相同组成部分的行.每行都有一个唯一的增量编号,类型编号(整数);下拉菜单和输入事件由父组件内部的一种方法根据其标签名称进行处理;我将用户输入的所有数据存储在对象({})的列表([])中.

I have a table with columns and rows, each row inside the table has a unique id, 2 drop-downs, 1 text input, 2 datepickers and 1 file upload input which is causing the main issue; The user can add more rows that has same components as the previous ones, by clicking on the "+ Document" button; Each row has a unique incremental Id of type number (integer); the drop-downs and the inputs events are handled by one method inside the parent component based on their tag names; I'm storing all data entered by the user inside a list ([]) of objects({}).

示例:如果用户仅填写第一行;存储在列表状态内的对象将是这样的:

Example: if the user fill only the first row; the object stored inside the list state will be like this:

[{id:0,type:"forms",lang:"all",libelle:"some strings",dateBegin:"11-12-2018",dateEnd:"12-12-2018",document:{File(154845)}]

如果用户添加了另一行,然后像第一行一样填充了该行,则列表将如下所示:

if the user adds one other row and then filled it like the first one, the list will be like this:

  [{id:0,type:"forms",lang:"all",libelle:"some strings",dateBegin:"11-12-2018",dateEnd:"12-12-2018",document:{File(154845)},{id:1,type:"howTo",lang:"en",libelle:"some strings",dateBegin:"11-12-2018",dateEnd:"01-01-2019",document:{File(742015)}]

查看此图片以查看表格的外观: 表格演示

该表作为Presentational组件类(主要组件的子代)中的代码

class Presentational extends React.Component {

  constructor(props) {
   super(props);

   this.state = {
    docObjList: [],
    element: (
      <FormDocRowItem // this contains the table tbody tds elements..
        id={1}
        handleChanges={this.props.handleChanges}/>)
   };

     this.handleAddDocumentRow = this.handleAddDocumentRow.bind(this);
 }

  // handleAddDocumentRow method
  handleAddDocumentRow(e) {

   const value = e.target.value;
   const name = e.target.name;

   if (name === 'add') {
    let arr = this.state.docObjList; // get the list state

    // assign the new row component
    arr = [...arr, Object.assign({}, this.state.element)]; 

    // set the new list state
    this.setState({docObjList: arr});
   }

   // if name === 'delete' logic..
 }

   // render method
   render() {
          const {handleReset} = this.props;
      return(
       <FormGroup>
              <Form encType="multipart/form-data">
                <Table striped bordered condensed hover>
                  <thead>
                  <tr>
                    <th>id</th>
                    <th>Type</th>
                    <th>Lang</th>
                    <th>Title</th>
                    <th>Date begin</th>
                    <th>Date end</th>
                    <th>+ Document</th>
                    <th>Options</th>
                  </tr>
                  </thead>
                  <tbody>

                  {this.state.element} // this row is required as initialization
                  {
                    this.state.docObjList.map((doc, index) => {
                      // as index in map() starts from 0 and there is an   
                      // already row component above => The index inside the 
                      // table should start from 1 except The key property 
                      // which should know the right index of the function 
                      const id = index+1; 

                      return (
                        <tr key={index}> 
                          <td>
                            {id}
                          </td>
                          <td>
                            <DocumentTypes id={id} handleChange={this.props.handleChanges}/>
                          </td>
                          <td>
                            <DocumentLanguage id={id} handleChange={this.props.handleChanges}/>
                          </td>
                          <td>
                            <DocumentLibelle id={id} handleChange={this.props.handleChanges}/>
                          </td>
                          <td>
                            <FormControl  id={''+id} name="dateBegin" componentClass="input" type="date"
                                         onChange={this.props.handleChanges}/>
                          </td>
                          <td>
                            <FormControl  id={''+id} name="dateEnd" componentClass="input" type="date"
                                         onChange={this.props.handleChanges}/>
                          </td>
                          <td>
                            <Document  id={id} handleChange={this.props.handleChanges}/>
                          </td>
                          {
                            this.state.docObjList.length == index + 1 &&
                            <td>

                              <button type="button" style={{verticalAlign: 'middle', textAlign: 'center'}} id={index + 1}
                                      name="delete"
                                      onClick={this.handleAddDocumentRow}>
                                Delete
                              </button>
                            </td>
                          }
                        </tr>
                      );
                    })
                  }
                  </tbody>
                </Table>
                <button type="button" name="add" onClick={this.handleAddDocumentRow}>+ Document</button>

                <FormGroup>
                  <Button type="reset"
                          style={{marginRight: '20%'}}
                          className="btn-primary"
                          onClick={this.props.handleClickSubmit}>Submit</Button>
                  <Button name="back" onClick={this.props.handleClickSubmit}>Annuler</Button>
                </FormGroup>
              </Form>
       </FormGroup>
        )
  }
}

行组件类(Presentational的子组件)

const FormDocRowItem = (props) => {

  const {id} = props; // the ID here is refering the column that is going to be 
                      // show inside the table not the index of the map function
  return(
    return (
      <tr>
        <td>
          {id}
        </td>
        <td>
          <DocumentTypes id={id} handleChange={this.props.handleChanges}/>
        </td>
        <td>
          <DocumentLanguage id={id} handleChange={this.props.handleChanges}/>
        </td>
        <td>
          <DocumentLibelle id={id} handleChange={this.props.handleChanges}/>
        </td>
        <td>
          <FormControl id={''+id} name="dateBegin" componentClass="input" type="date" onChange={this.props.handleChanges}/>
        </td>
        <td>
          <FormControl id={''+id} name="dateEnd" componentClass="input" type="date" onChange={this.props.handleChanges}/>
        </td>
        <td>
          <Document id={id} handleChange={this.props.handleChanges}/>
        </td>
      </tr>
    );
  }

}

父组件类(主要组件)

   constructor(props) {
     this.state ={
       docDataList: [],
       formIsReadyToSubmit: false
     } 

     this.handleSubmit = this.handleSubmit.bind(this); // button submit click
     this.handleReset = this.handleReset.bind(this); // button reset click
     this.fillWithData = this.fillWithData.bind(this); // handle changes

   }

   // handleReset method..

   fillWithData(e) {

    const name = e.target.name; // get the name of the target
    const id = parseInt(e.target.id); // get the id of the target
    let value = e.target.value; // get the value of the target
    let arr = this.state.docDataList; // get the list state

    // if the target is a file upload
    if (name === 'selectDocument') 
      value = e.target.files[0];

    // create properties with null values starting from the first onchange 
    // event handling, to not get a misplaced properties inside the
   // objects of the list state
    arr.map((x) => {
      x.type = x.type ? x.type : null;
      x.lang = x.lang ? x.lang : null;
      x.libelle = x.libelle ? x.libelle : null;
      x.dateBegin = x.dateBegin ? x.dateBegin : null;
      x.dateEnd = x.dateEnd ? x.dateEnd : null;
      x.document = x.document ? x.document : null;
    });

    // if the event target name is not delete
    if (name != 'delete') {
      // check if the object id already exist in the table
      // if it exists, the new value should replace the previous one
      // and not allowed to add a new object to the list state
      if ((arr.find((x) => x.id == id))) {
        // loop through the list state to find the id of the object
        arr.map((x) => {
          if (x.id == id) {
            // helper variable to prevent empty strings
            const val = value != '' ? value : null;

            switch (name) {
              case 'selectType':
                x.type = val;
                break;
              case 'selectLang':
                x.lang = val;
                break;
              case 'libelle':
                x.libelle = val;
                break;
              case 'dateBegin':
                x.dateBegin = val;
                break;
              case 'dateEnd':
                x.dateEnd = val;
                break;
              case 'selectDocument':
                x.document = val;
                break;
            }
          }
        });
        // assign the new list to my docDataList state
        // mentioning that the id of the element already exist
        this.setState({docDataList: arr}, () => {
          console.log(' ID exist; new dataList :', this.state.docDataList);
        });
      }
      // if the id doesn't exist (means that the button +document is clicked)
      else {
        // again, a helper variable as the previous statement 
        const val = value != '' ? value : null;

        this.setState({
          docDataList: [...arr, Object.assign({
            id: id,
            type: name === 'selectType' ? val : null,
            lang: name === 'selectLang' ? val : null,
            libelle: name === 'libelle' ? val : null,
            dateBegin: name === 'dataBegin' ? val : null,
            dateEnd: name === 'dateEnd' ? val : null//,
            //document: name==='selectDocument'? val:null
          })]
        }, () => {
          console.log('ID doesnt exist; new dataList :', this.state.docDataList);
        });
      }
    }
  }

HandleSubmit()方法(在Parent组件类内部)

// Submit button click handler
  handleSubmit(e) {

      let docDataList = this.state.docDataList;

      // if the user didn't touch any thing on the table rows
      // that means the list is empty and its length = 0
      if (docDataList.length === 0) {
        this.setState({
          alerts: {
            message: 'Please enter your document information ',
            show: true
          }
        });
      }
      // if the user has entered a data on the table row
      else if (docDataList.length > 0) {

        let data = new FormData(); // object which will be sent 

        // check the docDataList before request
        console.log('DocDataList before request:', docDataList); 
        data.append('docDataList', JSON.stringify(docDataList)); 

        fetch('http://localhost:8080/api/files/uploadFile', {
          method: 'POST',
          body: data
        }).then(response => {
          console.log('success document upload', response);
        }).catch(error => {
          console.log('error', error);
        });

        this.setState({
          formIsReadyToSubmit: true, 
          docDataList: [], // reset the list
          alerts: {updateAlert: true} // make an alert
        });
      }

    }

要查看当我用数据填充行时控制台显示的内容: 点击此处请

To see what the console show when I fill the row with data: CLICK HERE PLEASE

要查看请求的响应,请执行以下操作: 请点击此处

To see the response of the request: CLICK HERE PLEASE

注意:在观看了这些屏幕截图之后,您可能会注意到,还有一个名为"arrContrats"的数据列表,我没有在它的问题中提及它,因为它没有任何问题.问题出在"docDataList"列表上.预先感谢

NOTE: You may notice after watching those screenshots, that there is an extra list of data called "arrContrats" which which I didn't mention it in my issue because it doesn't have any problem; the problem is with the "docDataList" list. Thanks in advance

推荐答案

如果您的问题是您得到了浏览器中的 File 对象,然后在其上(或包含它的东西)使用 JSON.stringify 并在JSON中获取 {} ,这是正确的.浏览器的 File 对象没有自己的可枚举属性. JSON.stringify 仅包含自己的可枚举属性.

If your problem is that you're getting a File object from the browser, and then later using JSON.stringify on it (or something containing it) and getting {} for it in the JSON, that's correct. The browser's File object has no own, enumerable properties. JSON.stringify only includes own, enumerable properties.

如果希望 File 对象具有各种属性(继承的访问器属性),则需要将它们复制到新对象.

If you want the various properties that File objects have (inherited accessor properties), you'll need to copy them to a new object.

如果需要文件数据,则无法直接从 File 对象获取,必须使用

If you want the file data, you can't get it directly from the File object, you have to use a FileReader for that.

这篇关于JSON.stringify()函数将文件对象替换为一个空对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆