File input not updating state correctly React? - javascript

Ok so I have a form that has file inputs on it for images (and it previews the image before submission) but only the first input updates (no matter which input I use to put my image up).
Here are the repro steps:
Click "Add Question" button 2 or more times
Click (because drop doesn't work yet) on the second dropzone and upload a file.
See that the first dropzone updates and not the second
Here's a CodeSandbox for it.
And here is my code for the drop zone component:
class DropZone extends Component {
constructor(props){
super(props)
this.state = {
file: "",
fileId: uuid()
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(event) {
this.setState({
file: URL.createObjectURL(event.target.files[0])
})
//document.getElementsByClassName("dropZone").style.backgroundImage = 'url(' + this.state.file + ')';
}
render() {
return (
<div >
<input type="file" id="file" name="file" class="inputFile" onChange={this.handleChange}/>
<label key={uuid()} for="file" value={this.state.file} onchange={this.handleChange}>
<div class="dropZone" key={uuid()}>
Drop or Choose File
<img src={this.state.file} id="pic" name="file" accept="image/*"/>
</div>
</label>
<div>
</div>
</div>
);
}
}
I am new to React and JS so any explanation would help loads. Thanks!

It is not an issue with React but with HTML bindings. You need to provide a unique id to the input box and the label htmlFor attribute. I have updated the code below. and your code sandbox here -> https://codesandbox.io/s/kkj7j61noo
class DropZone extends Component {
constructor(props){
super(props)
this.state = {
file: "",
fileId: uuid()
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(event) {
this.setState({
file: URL.createObjectURL(event.target.files[0])
})
//document.getElementsByClassName("dropZone").style.backgroundImage = 'url(' + this.state.file + ')';
}
render() {
const uniqueId = this.state.fileId;
return (
<div >
<input type="file" id={uniqueId} name={uniqueId} class="inputFile" onChange={this.handleChange}/>
<label key={uuid()} htmlFor={uniqueId} value={this.state.file}>
<div class="dropZone" key={uuid()}>
Drop or Choose File
<img src={this.state.file} id="pic" name="file" accept="image/*"/>
</div>
</label>
<div>
</div>
</div>
);
}
}

Related

How do I reset the value of the file input?

How do I reset this.fileInput to empty or null or undefined?
class FileInput extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.fileInput = React.createRef(); }
handleSubmit(event) {
event.preventDefault();
alert(`Selected file - ${this.fileInput.current.files[0].name}`);
// Assume I have uploaded the file here
// How do I reset this.fileInput to empty Ref?
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Upload file:
<input type="file" ref={this.fileInput} /> </label>
<br />
<button type="submit">Submit</button>
</form>
);
}
}
ReactDOM.render(
<FileInput />,
document.getElementById('root')
);
You can use input type="reset"
<form onSubmit={this.handleSubmit}>
<label>
Upload file:
<input type="file" ref={this.fileInput} /></label>
<br />
<input type="reset" defaultValue="Reset" />
<button type="submit">Submit</button>
</form>
You actually trying to "reset" the form, so you should call HTMLFormElement.reset().
export default class FileInput extends React.Component {
fileInput = React.createRef();
formRef = React.createRef();
handleSubmit = (event) => {
event.preventDefault();
alert(`Selected file - ${this.fileInput.current.files[0].name}`);
this.formRef.current.reset();
};
render() {
return (
<form ref={this.formRef} onSubmit={this.handleSubmit}>
<label>
Upload file:
<input type="file" ref={this.fileInput} />
</label>
<br />
<button type="submit">Submit</button>
</form>
);
}
}
just clear the value of your ref
this.fileInput.current.value = ''

Delete/reset a displayed picture from vue js

i want to remove image src,
here is my template
<div class="file-upload-section">
<label id="preview" for="file-upload">
<img v-if="url" :src="url" />
</label>
<div class="file-upload">
<label class="file-upload-button" for="file-upload">Upload Image</label>
<input type="file" id="file-upload" #change="onFileChange"/>
</div>
<div v-if="url">
<button #click="removeImage()">Remove image</button>
</div>
</div>
this is my script
data: function () {
return {
url: null,
file: null
}
},
methods: {
onFileChange (e) {
this.file = e.target.files[0]
this.url = URL.createObjectURL(this.file)
},
removeImage: function () {
this.url = null
}
}
}
this is all i did, am i doing anything wrong or there is another way to delete a picture from a img
Your code is working; I tried it in my environment. It works perfectly. The issue could be re-rendering. I removed the "file" variable, as this seems no use based on your code, and I created scoped variable inside onFileChange function.
For a re-rendering issue to fix, add the key in your "img" tag and give it a unique value which will change on the "add" and "remove" image. In the below case, I use "URL" as a key.
<img :key="url" v-if="url" :src="url" />
Here is the code, give it a try:
<template>
<div class="file-upload-section">
<label id="preview" for="file-upload">
<img :key="url" v-if="url" :src="url" />
</label>
<div class="file-upload">
<label class="file-upload-button" for="file-upload">Upload Image</label>
<input type="file" id="file-upload" #change="onFileChange"/>
</div>
<div v-if="url">
<button #click="removeImage()">Remove image</button>
</div>
</div>
</template>
<script>
export default {
data: function () {
return {
url: null
}
},
methods: {
onFileChange (e) {
let file = e.target.files[0]
this.url = URL.createObjectURL(file)
},
removeImage: function () {
this.url = null
}
}
}
</script>
Edit:
On testing your code, I noticed the file preview does reset (the url variable), however the value of the input, did not. I assume that's what you mean, thus:
You can use a ref on the file input, and reset it as well.
Add a ref to your input:
<input type="file" id="file-upload" ref="file" #change="onFileChange"/>
Also, update your removeImage method accordingly:
removeImage: function () {
this.url = ""
this.$refs.file.value = ""
}
Pen here
In Vuejs in order to bind an event you should use v-on:click or in short way :click:
<button :click="removeImage">Remove image</button>
https://v2.vuejs.org/v2/guide/events.html

Render the form input binding from external function in react

I am trying to bind the input from the function, as per the below code
class ProfessionalLearningAction extends Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.ensureDataFetched();
}
handleChange(e) {
let change = {}
change[e.target.name] = e.target.value
this.setState(change)
}
render() {
return (
<div className="container">
<h1>Edit/Add Professional Learning</h1>
<p>This component demonstrates Add/Edit data from the server and working with URL parameters.</p>
<br /><br />
{renderProfessionalLearningTable(this.props)}
</div>
);
}
}
function renderProfessionalLearningTable(props) {
return (
<form className="container">
<div className="form-row">
<div className="form-group col-sm-6">
<label>Course Name *</label>
<input type="text" className="form-control" value={props.professionalLearnings.courseName || ''} onChange={ props.handleChange }
aria-describedby="Course Name" placeholder="Enter a course name" />
</div>
</div >
</form >
);
}
Keep getting the error
Failed prop type: You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultValue`. Otherwise, set either `onChange` or `readOnly`.
Since I know from the error message that I need to define handlechange event. I tried the below code
<input type="text" className="form-control" value={props.professionalLearnings.courseName || ''} onChange={this.handleChange}
aria-describedby="Course Name" placeholder="Enter a course name" />
Since I know it is a function call which is external to the class. How can I fix this error?
Its because you don't pass onchange props. And make sure whenever you made a component it should start with Capital Name(ReactJS component names must begin with capital letters?).
class ProfessionalLearningAction extends Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.ensureDataFetched();
}
handleChange(e) {
let change = {}
change[e.target.name] = e.target.value
this.setState(change)
}
render() {
return (
<div className="container">
<h1>Edit/Add Professional Learning</h1>
<p>This component demonstrates Add/Edit data from the server and working with URL parameters.</p>
<br /><br />
<RenderProfessionalLearningTable {...this.props} handleChange={this.handleChange}/> //Pass the handlechange component
</div>
);
}
}
function RenderProfessionalLearningTable(props) {
return (
<form className="container">
<div className="form-row">
<div className="form-group col-sm-6">
<label>Course Name *</label>
<input type="text" className="form-control" value={props.professionalLearnings.courseName || ''} onChange={ props.handleChange }
aria-describedby="Course Name" placeholder="Enter a course name" />
</div>
</div >
</form >
);
}

React JS - How to rerender Independed component?

I am new to this React JS, please in this question. I Have 4 components(Insert,delete,update and show). when i insert data in Insert component then immediately it should show those details in Show components. Please find my sample code. Thanks in advance for your help.
main.js :
import React from 'react';
import ReactDOM from 'react-dom';
import Insert from './Insert.js';
import Show from './Show.js';
import Delete from './Delete.js';
import Update from './update.js';
ReactDOM.render(<Insert/>, document.getElementById('Insert'))
ReactDOM.render(<Show />, document.getElementById('Show'))
ReactDOM.render(<Delete />, document.getElementById('Delete'))
ReactDOM.render(<Update/>, document.getElementById('Update'))
My Index.html :
<table border="2" align="center">
<tr>
<td>
<h1> Insert New Record </h1>
<div id = "Insert"></div>
</td>
<td>
<h1> Show Existing Records </h1>
<div id = "Show"> </div>
</td>
</tr>
<tr>
<td>
<h1> Delete Emp Record </h1>
<div id="Delete"> </div>
</td>
<td>
<h1> Update Existing Records </h1>
<div id="update" > </div>
</td>
</tr>
<script src = "index.js"></script>
Now i need to refresh the Show component whenever i perform insert, update, delete operations.
My sample Insert Component :
import React from 'react';
import Fetch from 'react-fetch';
import Show from './show'
class Insert extends React.Component {
constructor(props) {
super(props);
this.state = {
Id:0 ,
name:'' ,
mobile: '',
email: '',
dept : '',
role :'',
child : Show
};
this.handleSubmit = this.handleSubmit.bind(this);
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(event) {
const target = event.target;
const Id= target.Id;
const name = target.name;
const mobile = target.mobile;
const email = target.email;
const dept = target.dept;
const role = target.role;
this.setState({[Id]: event.target.value});
this.setState({[name]: event.target.value});
this.setState({[mobile]: event.target.value});
this.setState({[email]: event.target.value});
this.setState({[dept]: event.target.value});
this.setState({[role]: event.target.value});
}
handleSubmit(event) {
let employee={
Id:this.state.Id,
name:this.state.name,
mobile:this.state.mobile,
email:this.state.email,
dept:this.state.dept,
role:this.state.role
}
fetch('http://localhost:25424/api/Employee/CreateNewEmployee/', {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Access-Control-Allow-Origin' : 'http://localhost:7777' ,
'Access-Control-Allow-Headers' : 'Origin, X-Requested-With, Content-Type, Accept',
'Access-Control-Allow-Methods' : 'POST'
},
body: JSON.stringify(employee)
})
.then(function(resp){
})
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label >ID</label>
<input type="number" name="Id" value={this.state.Id} onChange={this.handleInputChange} />
<br/>
<label >name</label>
<input type="text" name="name" value={this.state.name} onChange={this.handleInputChange} />
<br/>
<label >Mobile</label>
<input type="text" name="mobile" value={this.state.mobile} onChange={this.handleInputChange} />
<br/>
<label >Email</label>
<input type="text" name="email" value={this.state.email} onChange={this.handleInputChange} />
<br/>
<label >Dept</label>
<input type="text" name="dept" value={this.state.dept} onChange={this.handleInputChange} />
<br/>
<label >Role</label>
<input type="text" name="role" value={this.state.role} onChange={this.handleInputChange} />
<br/>
<input type="submit" value="Submit" />
</form>
);
}
}
export default Insert;
This is the file structure you need to aim for in a React app
- src/
- components/
- insert.js
- delete.js
- update.js
- show.js
- main.js
- index.html
for example:
main.js // should contain all the data(state) and should flow downwards to your child components
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import 'insert' from /route/to/insert.js
import 'delete' from /route/to/delete.js
import 'show' from /route/to/show.js
import 'update' from /route/to/update.js
class Main extends Component {
constructor(props) {
super(props);
this.state = {//initialize state object}
}
render() {
return ( //jsx
<table border="2" align="center">
<tr>
<(insert.js component)/>
<(delete.js component)/>
</tr>
<tr>
<(update.js component)/>
<(show.js component)/>
</tr>
)
}
}
ReactDOM.reder(<Main/>, document.querySelector('one DOM element'))
and then... make each separate components to render out JSX into the main.js
Hope that makes sense :/
You dont have a parent child relationship in between you components. You will need all of this in one parent React component, lets say Main.jsx.
and it should look something like this:
Main.jsx:
import React from 'react';
class Main extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.state = {
flag: 0,
}
handleSubmit(){
this.setState({flag : this.state.flag});
}
render() {
return(<div>
<Insert handleSubmit = {this.handleSubmit}/>
<Show/>
<Delete/>
<Update />
</div>);
}
}
export default Main
You can put the structure of DOM or layout as per your desire in render. In handleSubmit function m reassigning the same state again so that it can re render. You can also use this.forceUpdate() for this but it is not advisable in some cases.
Your handleSubmit function in Insert Component would look need to call the props function as this.props.handleSubmit() so that it can re render the main component which in turn will re render your show update and delete.
Hope it helps.

how to display the table using react js

Im new to reactjs and Im just trying to create a page with the userName and password. When the submit is clicked it should display a list of table names in the same page. For this I have two react components, placed it in a separate js file. So when the button is clicked the table names should be generated. I have tried a sample code but I'm unable to display the list. So looking for help in reactjs.
tableContent.js
import React from 'react';
class tableContent extends React.Component {
render() {
return (
<select name="sometext" multiple="multiple">
<option>Table1</option>
<option>Table2</option>
<option>Table3</option>
<option>Table4</option>
<option>Table5</option>
</select>
)
}
}
export default tableContent;
login.js
import React from 'react';
import tableContent from './tables';
class Login extends React.Component{
constructor(){
super();
this.state={
showComponent : false,
};
this.buttonClick = this.buttonClick.bind(this);
}
buttonClick(){
this.setState({
showComponent: true,
})
}
render(){
return(
<div>
<form>
<label>userName :</label>
<input type="text" />
<br/>
<label>Password :</label>
<input type="text" />
<button onClick={this.buttonClick.bind(this)}> Submit </button>
</form>
<tableContent />
</div>
)
}
}
export default Login;
Change the Name tableContent to TableContent, because name of the react component must start will upper case letter otherwise it will be treated as html element.
Use e.preventDefault(); inside buttonClick function to prevent the form submission automatically.
Check the working code:
class Login extends React.Component{
constructor(){
super();
this.state={
showComponent : false,
};
}
buttonClick(e){
e.preventDefault();
this.setState({
showComponent: true,
})
}
render(){
return(
<div>
<form>
<label>userName :</label>
<input type="text" />
<br/>
<label>Password :</label>
<input type="text" />
<button onClick={this.buttonClick.bind(this)}> Submit </button>
</form>
{this.state.showComponent && <TableContent />}
</div>
)
}
}
class TableContent extends React.Component {
render() {
return (
<select name="sometext" multiple="multiple">
<option>Table1</option>
<option>Table2</option>
<option>Table3</option>
<option>Table4</option>
<option>Table5</option>
</select>
)
}
}
ReactDOM.render(<Login/>, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id ='app'/>

Categories