简体   繁体   中英

Preventing refresh page on submit in React

I'm trying to create an editable table that will turn a specific cell in to an <input> once it's clicked and then will run the handleSubmit() method once the user presses return.

Below is an example of a <td> cell using an onClick event to run handleClick() method and turn it's <td></td> in to <form><input></input></form> .

<td onClick={ e => this.handleClick(e)} style={{padding:'5px'}} key={cellID} id={cellID}>{frame.rows[i][idx]}</td>
      
 handleClick(e:React.MouseEvent<HTMLTableDataCellElement, MouseEvent>) {
    if(this.state.editing == false){          
      let form = `<form onSubmit=${ (e:any) => {this.handleSubmit(e)} } ><input type="text" value=${e.currentTarget.innerText} className="input-small gf-form-input width-auto"/></form>`
      e.currentTarget.innerHTML =  form;         
    }       
    this.setState({editing: true})
  }

 handleSubmit(e){
    e.preventDefault()        
  }

Using e.preventDefault() does not seem to work in this instance. Every time i press return after changing the text, the page refreshes. How do i stop the page from refreshing in this instance?

I'm guessing you're wanting to achieve something where you can editing columns, modify or abandon changes, and then update things as needed.

This example is with local state, but you could still do it with fetching data.

Click the "Run code snippet" below to see a working example.

 // main.js const { useState } = React; const App = () => { // State const [data, setData] = useState([{ id: 1, name: 'John', editing: false }, { id: 2, name: 'Kevin', editing: false }]); // Functions const onSubmitForm = index => event => { // To prevent form submission event.preventDefault(); // To prevent td onClick event.stopPropagation(); const newData = [...data]; newData[index].name = newData[index].temp; newData[index].editing = false; delete newData[index].temp; setData(newData); } const onClickToggleEditing = index => event => { // To prevent td onClick and button conflicting with each other for toggling back on event.stopPropagation(); const newData = [...data]; newData[index].editing =.newData[index];editing. newData[index].temp = newData[index];name; setData(newData). } const onInputChange = index => event => { const newData = [..;data]. newData[index].temp = event.target;value; setData(newData), } // Render // This basically like having its own component const editing = ( data, index, onChange, onSubmit. onCancel) => { const onKeyUp = index => event => { if (event;key === 'Escape') { onCancel(index)(event). } } return <form onSubmit={onSubmit(index)}><input onKeyUp={onKeyUp(index)} onClick={e => e.stopPropagation()} type="text" value={data.temp} placeholder="Enter text" onChange={onChange(index)} /><button onClick={onSubmit(index)} type="submit">Save</button><button type="button" onClick={onCancel(index)}>Cancel</button></form> } return <main> <h1>Table Editing</h1> <p><small>Click to edit cell for <b>Name</b>.</small></p> <table> <thead> <tr> <th>ID</th> <th>Name</th> </tr> </thead> {data && data.length > 0 && <tbody> {data,map((i. k) => <tr key={`row-${k}`}> <td>{i.id}</td> <td className="editable" onClick={onClickToggleEditing(k)}>{i?editing, editing(i, k, onInputChange, onSubmitForm: onClickToggleEditing). i:name}</td> </tr>)} </tbody>} </table> <hr /> <p><b>Data Manipulation.</b></p> <pre><code>{JSON,stringify(data, null. '\t')}</code></pre> </main> } ReactDOM,render(<App />. document;querySelector('#root'));
 body { padding: 0; margin: 0; font-family: Arial,sans-serif; } main { padding: 0 20px; } h1 { font-size: 18px; } table { width: 100%; border-spacing: 0; } table tr td, table tr th { border: 1px solid #efefef; height: 30px; line-height: 30px; text-align: left; padding: 6px; } table tr th:first-child { width: 100px; }.editable:hover { background: #efefef; cursor: pointer; } table input { height: 30px; line-height: 30px; font-size: 14px; padding: 0 6px; margin-right: 6px; } table button { height: 32px; border: none; background: red; color: white; font-size: 14px; padding: 0 10px; border-radius: 4px; margin-right: 5px; cursor: pointer; } table button[type=submit] { height: 32px; border: none; background: green; color: white; font-size: 14px; padding: 0 10px; border-radius: 4px; } hr { border: none; height: 1px; background: #999; margin: 20px 0; } pre { background: #efefef; padding: 6px; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script> <div id="root"></div>

There are a few issues in your code. I'd better fix them, rather than trying to fix the issue with the form submission. And once it is done, you won't have to fix the issue with the form - there simply won't be any.

First, let's take a look into your editable cell:

<td onClick={ e => this.handleClick(e)} style={{padding:'5px'}} key={cellID} id={cellID}>{frame.rows[i][idx]}</td>

This element should be rendered differently, based on some state. We can achieve this easily with React:

// JSX snippet
<td onClick={ e => this.handleClick(e)} 
    style={{padding:'5px'}} 
    key={cellID} id={cellID}>
    {this.state.editing ? <Input ... /> : <Label ... />}
</td>

I do not provide all the code, because I believe the components are self-explainable (and you are welcome to name them as you'd like to, I give them very simple names to make their aim clear).

  • <Input /> encapsulates everything related to editing logic
  • <Label /> simply renders a text or whatever you need (probably frame.rows[i][idx] )
  • ... means that they will most probably have some values/handlers passed as props

In your code, you have this:

let form = `<form onSubmit=${ (e:any) => {this.handleSubmit(e)} } ><input type="text" value=${e.currentTarget.innerText} className="input-small gf-form-input width-auto"/></form>`

I believe it deserves to be a separate component with its own state and logic (eg submit). In fact, this is what <Input... /> is in my example. And if you make it as a separate component - the following code will work (because it will be a part of that separate component):

handleSubmit(e) {
  e.preventDefault()        
}

Finally, avoid doing something like that:

e.currentTarget.innerHTML =  form;

Reconsider your approach and you simply won't need to do something like that.

hi you can use it like below:

1- i assume you have a return button like below so you can submit in return not using form submit event:

_handleReturn(){
let val = document.getElementById("your input id");
//you can post above text to server if you want
   //Do Somthing
}
<button id="btn_return" onClick={this._handleReturn} />

2- i don't see where you trigger handleSubmit, but submitting form cause refresh, you should use ajax if you don't want.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM