How to preview selected image in React.js? - javascript

How to preview selected image in react js? this is my code.
I am new to react.js and I still have no idea how to call functions or like this.
const HomepagePage = (props) => {
const hiddenFileInput = React.useRef(null);
const handleClick = event => {
hiddenFileInput.current.click();
};
const handleChange = event => {
const fileUploaded = event.target.files[0];
props.handleFile(fileUploaded);
};
return (
<>
<Button
className="common-pointer font-bold lg:ml-[44px] xl:ml-[56px] 2xl:ml-[63px] 3xl:ml-[75px] lg:text-[18px] xl:text-[23px] 2xl:text-[25px] 3xl:text-[31px] text-center tracking-ls1 w-[63%]"
onClick={handleClick}
shape="RoundedBorder5"
>
Upload Image
</Button>
<input type="file"
ref={hiddenFileInput}
onChange={handleChange}
style={{display:'none'}}
/>
<Img
src="images/img_11.png"
className="absolute lg:h-[382px] xl:h-[478px] 2xl:h-[537px] 3xl:h-[645px] w-[100%]"
alt="Eleven"
/>
The image selected from the button should replace the image 11. Any idea how to do this?

Related

onClick does not work when I load image from database ReactJs

I am making a user profile page with an image avatar.
The code works perfectly until the user re-enters the profile page; in that case, nothing happens when the user clicks on the profile image.
It should remove the image on the first click, and then he should be able to upload a different image.
I store the image as a base64 string.
Code I use to set preview image:
const [image, setImage] = useState(null);
const [preview, setPreview] = useState(null);
useEffect(()=> {
if(image){
const reader = new FileReader();
reader.onloadend = () => {
setPreview(reader.result);
}
reader.readAsDataURL(image);
}else{
setPreview(null);
}
}, [image]);
Code I use to set preview form DB if it exists:
if(userData[11] != ''){
setImage(null);
setPreview(userData[11]);
}
And finally, in return of component:
{preview ? (<img class="image-preview" onClick={() => {setImage(null)}} src={preview} />) :(
<div class="image-upload">
<label for="file-input">
<img src="https://icons.iconarchive.com/icons/bokehlicia/captiva/128/multimedia-photo-manager-icon.png"/>
</label>
<input accept="image/*" onChange ={(e) =>{
const file = e.target.files[0];
if(file && file.type.substring(0, 5) === "image"){
setImage(file);
} else{setImage(null);}
}} id="file-input" type="file" />
</div>)}
onClick event in tag causes me trouble.

React way of grabbing a button element and using disable property

I have the following code where a user can select a file and hit upload and the Choose button is disabled.
Code Sanbox link is here:
import "primeicons/primeicons.css";
import "primereact/resources/themes/lara-light-indigo/theme.css";
import "primereact/resources/primereact.css";
import "primeflex/primeflex.css";
import "../../index.css";
import ReactDOM from "react-dom";
import React, { useRef, useState } from "react";
import { FileUpload } from "primereact/fileupload";
export const FileUploadDemo = () => {
const toast = useRef(null);
const [disableButton, setDisableButton] = useState(false);
const onUpload = () => {
toast.current.show({
severity: "info",
summary: "Success",
detail: "File Uploaded"
});
};
const onTemplateAdvancedSelect = (e) => {
console.log("Printing onTemplateAdvancedSelect ");
console.log(e);
let inputFileType = document.querySelector("input[type=file]");
//setDisableButton(true);
inputFileType.classList.add("toDisableOnSelect");
inputFileType.disabled = true;
let htmlCollection = document.getElementsByClassName(
"p-button p-component p-button-icon-only"
);
console.log("Printing htmlCollection");
console.log(htmlCollection.length);
console.log(htmlCollection);
// htmlCollection.addEventListener("click", function () {
// inputFileType.disabled = false;
// });
//console.log(htmlCollection.item(19));
};
return (
<div>
<div className="card">
<h5>Advanced</h5>
<FileUpload
multiple={false}
name="demo[]"
url="https://primefaces.org/primereact/showcase/upload.php"
onUpload={onUpload}
id={"myId"}
accept="image/*"
maxFileSize={1000000}
onSelect={onTemplateAdvancedSelect}
disabled={disableButton}
emptyTemplate={
<p className="p-m-0">Drag and drop files to here to upload.</p>
}
/>
</div>
</div>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<FileUploadDemo />, rootElement);
So Inside onTemplateAdvancedSelect function, I want to set inputFileType.disabled to false once user hits the cross icon as shown below:
I don't want to use getElementByClassName just like I have attempted to use in my code of above function. What would be a better way to achieve my goal?
Primereact version I'm using : 4.2.2
One solution is customizing the row item of the selected file.
so the itemTemplate prop is exactly for that goal.
export const FileUploadDemo = () => {
const toast = useRef(null);
const fileUploadRef = useRef(null) // reference to uploader node
const [disableButton, setDisableButton] = useState(false);
const onTemplateRemove = (file, callback) => {
// setTotalSize(totalSize - file.size);
const domInput = fileUploadRef.current.fileInput;
domInput.disabled = false;
callback();
}
const onTemplateAdvancedSelect = () => {
const domInput = fileUploadRef.current.fileInput; // pure dome element
domInput.disabled = true;
}
const itemTemplate = (file, props) => {
return (
<>
<div>
<img alt={file.name} role="presentation" src={file.src} width="50" />
</div>
<div class="p-fileupload-filename">{file.name}</div>
<div>{file.size}</div>
<div>
{ /* here you have access to that button */}
<button
type="button"
class="p-button p-component p-button-icon-only"
onClick={() => onTemplateRemove(file, props.onRemove)}>
<span class="p-button-icon p-c pi pi-times"></span>
<span class="p-button-label p-c"> </span>
</button>
</div>
</>
)
}
return (
<div>
<div className="card">
<h5>Advanced</h5>
<FileUpload
ref={fileUploadRef} // pass a reference for `input` manipulation
multiple={false}
name="demo[]"
url="https://primefaces.org/primereact/showcase/upload.php"
onUpload={onUpload}
id={"myId"}
accept="image/*"
maxFileSize={1000000}
/* here we should pass the customized template as prop */
itemTemplate={itemTemplate}
onSelect={onTemplateAdvancedSelect}
disabled={disableButton}
emptyTemplate={
<p className="p-m-0">Drag and drop files to here to upload.</p>
}
/>
</div>
</div>
);
Please use useRef hook provided by react. Example below:
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` points to the mounted text input element
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
I'm trying to understand your use case. Do you want to remove the image from the upload stack by clicking the x button?
I think you should rather use the built-in API to trigger functionality. If that doesn't help you can extend the library.
You don't need to do a getElementsByClassName. You can use the onRemove event to handle the file remove event.
<FileUpload
multiple={false}
name="demo[]"
url="https://primefaces.org/primereact/showcase/upload.php"
onUpload={onUpload}
id={"myId"}
accept="image/*"
maxFileSize={1000000}
onSelect={onTemplateAdvancedSelect}
disabled={disableButton}
emptyTemplate={
<p className="p-m-0">Drag and drop files to here to upload.</p>
}
onRemove={(e, file) => setDisableButton(false)}
/>

File is replacing file, not adding in React (Next.js)

Please review my code first.
const test = () => {
const [files, setFiles] = useState ([]);
//I think I have to edit following statement.
const handleFile = (e) => {
const newFiles = []
for (let i=0; i < e.target.files.length; i++) {
newFiles.push(e.target.files[i])
}
setFiles(newFiles)
};
return (
{files.map((file, index) => (
<div>
<div key={index}>
<p>
{file.name}
</p>
<Button size='small' onClick={() => {deleteSelectedFile(file.name)}}>
Delete
</Button>
</div>
</div>
))}
<div>
<label onChange={handleFile}>
<input type='file' multiple />+ Attach File
</label>
</div>
)
}
with handleFile statement, I can appropriately get the files.
However, when I upload one file at a time and then upload one file again,
the file is not added. the file replaces file.
There is not problem when I upload multiple time at once.
For example, I upload 'hello.jpg', and it renders well in the screen. Then, I upload 'goodbye.jpg', it renders well, but 'goodbye.jpg' replaces 'hello.jpg'.
Therefore, what I see is just 'goodbye.jpg' [button], not
'hello.jpg' [button]
'goodbye.jpg' [button]
.
I want my files to stacked up, without replacing.
I need some wisdom!
In my opinion, you only need to spread the prev state values and the files during the change event.
import { useState } from "react";
export default function App() {
const [files, setFiles] = useState([]);
const handleChange = (e) => {
// This is what you need
setFiles((prev) => [...prev, ...Object.values(e.target.files)]);
};
return (
<div>
<label onChange={handleChange}>
<input type="file" multiple />
</label>
{files.map((file) => {
return <p>{file.name}</p>;
})}
</div>
);
}
how about you don't create a new variable for new files, you just set the state for the files since it's an array
setFiles(oldFile => [...oldFile,e.target.files[i]]);
If it's possible you can drop a codepen link

React: Can we pass 2 forms from 2 different child components to a parent, and submit them with a button which is inside the parent component?

I am trying to somehow pass the data from 2 forms and 2 different components to the parent component and then somehow console.log all of this data with a button that is inside the parent component. Then I will simply send these data to a JSON file or a dummy database.
When I press the submit button of course nothing is triggered right now because I simply don't know how to pass the function from the children to the parent. I have tried many ways, but I would appreciate it if you could show me a way to lift the state and combine the forms.
For the input, in order to pass refs, I have used React.forwardRef()
It would be easy to just have 1 big component with 1 form and then the button inside this component, but since it is a fun project, I want to learn how to implement this functionality in case I will use it in the future. You can find a screenshot on this link:
[]
[1]: https://i.stack.imgur.com/myV0N.jpg
Here we go:
1. Parent component
const BookingComponent = () => {
return (
<div>
<CRContainer className="booking-crcontainer">
<CRColumn>
<PickUpCarComponent />
</CRColumn>
<CRColumn>
<CustomerInfo />
</CRColumn>
</CRContainer>
<CRContainer className="booking">
<Button type="submit" btnText="hello there" />
</CRContainer>
</div>
);
};
export default BookingComponent;
2. Child 1
const CustomerInfo = (props) => {
const firstlRef = useRef();
const lastNameRef = useRef();
const onTrigger = (e) => {
e.preventDefault();
//console.log(first1Ref.current.value)
console.log("heaheaheah");
};
return (
<>
<Subtitle stitle={SubtitleLabels.customerInfo} />
<div className="customer-info-container">
<form onSubmit={onTrigger}>
<div>
<LabeledInput
labelText={CustomerInfoLabels.firstName}
type="text"
inputPlaceholder={GeneralLabels.placeholder}
ref={firstlRef}
></LabeledInput>
<LabeledInput
labelText={CustomerInfoLabels.lastName}
type="text"
inputPlaceholder={GeneralLabels.placeholder}
ref={lastNameRef}
></LabeledInput>
</div> ...................
3. Child 2
Haven't put the refs here yet.
const PickUpCarComponent = () => {
return (
<div>
<Subtitle stitle={SubtitleLabels.pickUp} />
<form>
<div className="booking-inner-container">
<div>
<LabeledInput labelText={"Pick-up date*"} type="date"></LabeledInput>
<LabeledInput labelText={"Pick-up time*"} type="time"></LabeledInput>
</div>
<DropDown type="CarGroup" labeltext="Car Group*" attribute="name" />
<DropDown type="RentalOffice" labeltext="Region*" attribute="region" />
</div>
</form>
</div>
);
};
export default PickUpCarComponent;
4. Input Component
const LabeledInput = React.forwardRef((props, ref) => {
const { labelText, type, inputPlaceholder, onChange, className } = props;
return (
<div className={`input-container ${className}`}>
<label htmlFor="labelText">{labelText}</label>
<input
type={type}
placeholder={inputPlaceholder}
onChange={onChange}
ref={ref}
/>
</div>
);
});
export default LabeledInput;
you can use context to pass form handlers to child component then in the child component you can useContext and get value and handlers of parent form and use them.
const FormContext = React.createContext({});
const BookingComponent = () => {
const [values, setValues] = useState();
const handleChange = useCallback((e) => {
//handle child event in parent and save child state in
//parent to use later in submit button
}, []); //set dependency if it's needed
const contextValue = useMemo(() => ({ handleChange }), [handleChange]);
return (
<FormContext.Provider value={contextValue}>
<div>
<CRContainer className="booking-crcontainer">
<CRColumn>
<PickUpCarComponent />
</CRColumn>
<CRColumn>
<CustomerInfo />
</CRColumn>
</CRContainer>
<CRContainer className="booking">
<Button type="submit" btnText="hello there" />
</CRContainer>
</div>
</FormContext.Provider>
);
};
const LabeledInput = (props) => {
const formContext = useContext(FormContext);
const { labelText, type, inputPlaceholder, className } = props;
return (
<div className={`input-container ${className}`}>
<label htmlFor="labelText">{labelText}</label>
<input
type={type}
placeholder={inputPlaceholder}
onChange={formContext.handleChange}
ref={ref}
/>
</div>
);
};

React Change button color onClick realtime - dynamically change/update attribute in firebase

I'm using firebase and react to create a realtime chat (based off of a tutorial online). i want to be able to click on any of the chat bubbles (which are actually buttons) that have already been sent and have it change color (for any user that is on the chat page).
It first prompts the user for a name and then allows you to send messages: chat image. Should I create an onClick function that somehow changes the color and then pushes that attribute to firebase? How can I go about doing this? How can I dynamically update data on firebase from my code?
This is what I have so far:
export default function TwoTruths() {
const [input, setInput] = useState("");
const [name, setUsername] = useState("");
const [messages, setMessages] = useState();
useEffect(() => {
setUsername(prompt("Please enter your name"));
}, []);
const handleSend = (e) => {
e.preventDefault();
db.collection("twoTruths").add({
message: input,
name: name,
image: image,
timestamp: firebase.firestore.FieldValue.serverTimestamp()
});
setInput("");
};
return (
<div className="twoTruths">
{messages.map((message) =>
message.name ? (
<div className="twoTruths__message">
<Avatar
className="twoTruths__image"
alt={message.name}
src={message.image}
/>
<button className="twoTruths__text">{message.message}</button>
</div>
) : (
<div className="twoTruths__message">
<button className="twoTruths__textUser" >{message.message}</button>
</div>
)
)}
<form className="twoTruths__input">
<input
value={input}
onChange={(e) => setInput(e.target.value)}
className="twoTruths__inputField"
placeholder="Type here..."
type="text"
/>
<button onClick={handleSend} className="twoTruths__inputButton">
{" "}
SEND{" "}
</button>
</form>
</div>
);
}

Categories

Resources