two React Componets in One section we upload image and can increase the number of input other section we will preview those images - javascript

I am working on a page
have two sections. In one section we upload image and can increase the number of input, in the other section we will preview the image.
I don't know I am not getting the right id that I want to edit.
we can add more fields on click of button and remove then at the end post data at api endpoint?
RightSection
const RightSection = ({ inputImage, setInputImage }) => {
const handleAddFields = () => {
if (inputImage.length <= 9) {
const values = [...inputImage];
values.push({
id: values.length + 1,
name: `Drop Image ${values.length + 1} Here`,
});
setInputImage(values);
}
};
const handleRemoveFields = () => {
if (inputImage.length > 3) {
const values = [...inputImage];
values.splice(values.length - 1, 1);
setInputImage(values);
}
};
const handleInputChange = (id, event) => {
console.log(id, event.target.id, "=====");
const newInputFields = inputImage.map((i) => {
if (id === i.id) {
i.url = URL.createObjectURL(event.target.files[0]);
i.name = event.target.files[0].name;
// push image object in array
setInputImage([
...inputImage,
{
id: id,
url: URL.createObjectURL(event.target.files[0]),
name: event.target.files[0].name,
},
]);
}
return i;
});
setInputImage(newInputFields);
};
console.log(inputImage);
return (
<>
<div id="right" className="flex">
<div className="margin">
<div className="inlineflex">
<H1>Background Image</H1>
<div>
<AddIcon onClick={handleAddFields} />
<RemoveIcon onClick={handleRemoveFields} />
</div>
</div>
</div>
<div
style={{
margin: "0 auto",
position: "relative",
width: "80%",
}}
>
{inputImage.map((inputField, index) => (
<FileInput key={index}>
<label
htmlFor={inputField.id}
onClick={(e) => {
console.log("click", index + 1);
}}
>
{inputField.name}
</label>
<input
id={index + 1}
onChange={(event) => handleInputChange(inputField.id, event)}
accept="image/*"
type="file"
/>
</FileInput>
))}
</div>
</div>
</>
);
};
LeftSection
const LeftSection = ({ inputImage }) => {
return (
<>
<div id="left" className="flex">
<div className="margin">
<H1>Preview</H1>
</div>
<Grid>
{Array.isArray(inputImage) &&
inputImage.map((item, index) => {
if (item?.url?.includes("http") || item?.url?.includes("https")) {
return (
<div key={index}>
<img src={item?.url} alt={item?.name} />
</div>
);
}
})}
</Grid>
</div>
</>
);
};
BackgroundImage
let initaValue = [
{ id: 1, name: "Drop Image 1 Here", url: "" },
{ id: 2, name: "Drop Image 2 Here", url: "" },
{ id: 3, name: "Drop Image 3 Here", url: "" },
];
const BackgroundImage = () => {
const [inputImage, setInputImage] = useState(initaValue);
return (
<>
<Container>
<RightSection inputImage={inputImage} setInputImage={setInputImage} />
<LeftSection inputImage={inputImage} setInputImage={setInputImage} />
</Container>
</>
);
};
export default BackgroundImage;
I think there is some issue with the handleInputChange function on the RightSection component.
Somehow I am not able to update the item with the correct id in the array.
Is there any other efficient solution for this problem?

Related

React dynamic form bug

I've created script for dynamic form, but there's 2 things which I can't get and my head is exploding right now, hopefully somebody would help me with that.
After creating new fields - I can't remove fields depends on button which was clicked.
And after removing some of those fields, I have this error with fieldsenter image description here
import React from "react";
import {useState , useEffect} from "react";
import ReactDOM from "react-dom";
import "./index.css";
const Form = () =>{
const [fieldsLength, fieldsLengthChanger] = useState(1);
const [fields, fieldsChanger] = useState([{
id : 1,
name: "",
phone: "",
age: ""
}])
return (
<>
<div className="form__wrapper">
<h2>Form </h2>
{
fields.map((elem, index) => {
return(
<FormElement {...elem} fields={fields} fieldsChanger={fieldsChanger} fieldsLength={fieldsLength} fieldsLengthChanger={fieldsLengthChanger}/>
)
})
}
<AddMore fieldsLength={fieldsLength} fieldsLengthChanger={fieldsLengthChanger} fields={fields} fieldsChanger={fieldsChanger}/>
</div>
</>
)
}
const FormElement = ({fieldsLength ,...props}) =>{
function inputHandler(e, id){
console.log(e.target.name);
const values = [...props.fields];
values[id-1][e.target.name] = e.target.value;
props.fieldsChanger(values);
}
function removeElement(e,id){
e.preventDefault();
var arr = [...props.fields];
const newArray = arr.filter(function(elem,index){
console.log("index:" , index, "ID : ", id);
if (index + 1 != id){
return elem;
}
});
// console.log(newArray);
// arr.splice(3, 1);
props.fieldsChanger([])
props.fieldsChanger(newArray);
}
return (
<div className="group__form">
<div className="form__element">
<input type="text" value={props.fields.name} name="name" onChange={e => inputHandler(e , props.id)} />
</div>
<div className="form__element">
<input type="text" value={props.fields.phone} name="phone" onChange={e => inputHandler(e , props.id)}/>
</div>
<div className="form__element">
<input type="text" value={props.fields.age} name="age" onChange={e => inputHandler(e , props.id)}/>
</div>
{
fieldsLength > 1 ? <div className="remove__field">
<a href="#" onClick={e=>removeElement(e , props.id)}>Remove</a>
</div> : ""
}
</div>
)
}
const AddMore = (props) =>{
function addMore(){
props.fieldsLengthChanger(props.fields.length + 1);
props.fieldsChanger([...props.fields, {id:props.fields.length + 1 , name: "" , phone : "" , age :''} ]);
}
return (
<div className="add__more">
<a href="#" onClick={e=> addMore()}>Add element</a>
</div>
)
}
ReactDOM.render(<Form/> , document.getElementById("root"));
Where I'm wrong - would be really helpfull to understand what is the problem
Always use key when rendering list.
<FormElement key={elem.id} {...elem} ...
https://reactjs.org/docs/lists-and-keys.html#keys
1. You should use the props.id to remove a form instead of using index.
e.g. this must be a bug.
if (index + 1 != id) {
return elem;
}
2. And you should use id by the unique value generation instead of using array's length.
3. You should provide the key prop in the render of the form fields. Otherwise, React can't distinguish forms in rendering.
And the key should be unique whenever you add or remove items.
e.g. See the updated code. You need to use elem.id. (Of course, you should generate id in the add method.
{fields.map((elem, index) => {
return (
<FormElement
key={elem.id}
{...elem}
fields={fields}
fieldsChanger={fieldsChanger}
fieldsLength={fieldsLength}
fieldsLengthChanger={fieldsLengthChanger}
/>
);
})}
4. You could basically use a timestamp. Please use your own generation logic in the production. You can use uuid generation package.
{
id: new Date().getTime(),
name: "",
phone: "",
age: ""
}
My advices:
You don't need to use this state variable const [fieldsLength, fieldsLengthChanger] = useState(1);
Because we can get this value by fields.length.
There are a few problems in terms of components design. e.g. Please try to define addMore() in form then you don't need to pass fields, fieldsChanger as props.
Here is a full working code with your old code commented.
const Form = () => {
const [fieldsLength, fieldsLengthChanger] = useState(1);
const [fields, fieldsChanger] = useState([
{
id: new Date().getTime(),
name: "",
phone: "",
age: ""
}
]);
return (
<>
<div className="form__wrapper">
<h2>Form </h2>
{fields.map((elem, index) => {
return (
<FormElement
key={elem.id}
{...elem}
fields={fields}
fieldsChanger={fieldsChanger}
fieldsLength={fieldsLength}
fieldsLengthChanger={fieldsLengthChanger}
/>
);
})}
<AddMore
fieldsLength={fieldsLength}
fieldsLengthChanger={fieldsLengthChanger}
fields={fields}
fieldsChanger={fieldsChanger}
/>
</div>
</>
);
};
const FormElement = ({ fieldsLength, ...props }) => {
function inputHandler(e, id) {
console.log(e.target.name);
const values = [...props.fields];
const item = values.find((x) => x.id === props.id);
if (item) {
item[e.target.name] = e.target.value;
}
// values[id - 1][e.target.name] = e.target.value;
props.fieldsChanger(values);
}
function removeElement(e, id) {
e.preventDefault();
var arr = [...props.fields];
const newArray = arr.filter(function (elem, index) {
/*console.log("index:", index, "ID : ", id);
if (index + 1 != id) {
return elem;
}*/
return elem.id !== id;
});
// console.log(newArray);
// arr.splice(3, 1);
props.fieldsChanger([]);
props.fieldsChanger(newArray);
}
return (
<div className="group__form">
<div className="form__element">
<input
type="text"
value={props.fields.name}
name="name"
onChange={(e) => inputHandler(e, props.id)}
/>
</div>
<div className="form__element">
<input
type="text"
value={props.fields.phone}
name="phone"
onChange={(e) => inputHandler(e, props.id)}
/>
</div>
<div className="form__element">
<input
type="text"
value={props.fields.age}
name="age"
onChange={(e) => inputHandler(e, props.id)}
/>
</div>
{fieldsLength > 1 ? (
<div className="remove__field">
<a href="#" onClick={(e) => removeElement(e, props.id)}>
Remove
</a>
</div>
) : (
""
)}
</div>
);
};
const AddMore = (props) => {
function addMore() {
props.fieldsLengthChanger(props.fields.length + 1);
props.fieldsChanger([
...props.fields,
//{ id: props.fields.length + 1, name: "", phone: "", age: "" }
{ id: new Date().getTime(), name: "", phone: "", age: "" }
]);
}
return (
<div className="add__more">
<a href="#" onClick={(e) => addMore()}>
Add element
</a>
</div>
);
};

how to map image array with filter in ReactJS

I'm absolutely beginner in ReactJS and I want to filter and map
const Shop = [
{
img : jam,
category: 'jam'
},
{
img : headset,
category:'headset'
},
{
img : sepatu,
category:'sepatu'
}
];
let ShopItem = [
{
id : 1,
img : jam,
category : 'jam',
price : 'Rp. 900,000'
},
{
id : 2,
img : jam,
category : 'jam',
price : 'Rp. 900,000'
},
{
id : 3,
img : headset,
category : 'headset',
price : 'Rp. 900,000'
}
]
function Content(){
const [shopItems,toogleshopItems]=useState(false);
let [items,showItems]=useState('');
const toogleShop = ()=>{
toogleshopItems(!shopItems);
console.log(shopItems);
}
function showshopItems(){
return(
<>
{Shopitem.map((shopitem, shopitemIndex) => {
return Shop.map((shop, shopIndex) => {
if (shop.category == shopitem.category)
return <img className="image-place" src={shopitem.img} />;
});
})}
</>
)
}
return(
<>
<div className="content">
<div className="content-wrapper">
<div className="content-title">Browse Categories</div>
<div className="image-flex">
{
Shop.map((shops)=>
<React.Fragment key={shops.category}>
<img onClick={toogleShop} className="image-place" src={shops.img}/>
</React.Fragment>
)}
</div>
<hr/>
{shopItems? showshopItems() : console.log("no") }
</div>
</div>
</>
)
}
export default Content
how to map shopitem image that has the same category value with shop category value...
when I click picture watch
if I click the picture 1 it will show child picture that has category jam
Finally I found out whats your problem. You should have a state for getting current category when user clicks on the top image and filter the items based on the state. I've created a sample based on your request:
export default function App() {
const [currentCategory, setCategory] = useState();
const TopSlide = () => {
return (
<div className="topSlide">
{Shop.map((shop, index) => {
return (
<img
alt=""
className="topSlideImage"
src={shop.img}
onClick={() => {
setCategory(shop.category);
}}
/>
);
})}
</div>
);
};
const DownSlide = () => {
return (
<div className="downSlide">
{ShopItem.filter((x) => x.category === currentCategory).map(
(shop, index) => {
return <img alt="" className="downSlideImage" src={shop.img} />;
}
)}
</div>
);
};
return (
<div className="App">
{TopSlide()}
<hr />
{DownSlide()}
</div>
);
}

ReactJS: Creating a "dynamic" render of Row and Col

I have an array of object with "id", "name", "value" that I pass to a component and it divided in row and col in this way:
export const RenderDetailRow = props => {
const columns = [];
props.content.forEach((content, idx) => {
columns.push(
<div className="col-sm py-3" key={`item_${idx}`}>
<b>{content.name + ': '}</b>
<Input type="text" name={content.name} id={content.id} readOnly value={content.value} />
</div>
);
if ((idx + 1) % props.display[0].number === 0) {
columns.push(<div className="w-100"></div>);
}
});
return (
<div className="row" style={{ margin: 30 }}>
{columns}
</div>
);
};
I have two kind of problem, the first:
Each child in a list should have a unique "key" prop.
I have inserted the key but I have this error.
If the number of field is odd I have a long Input, it is possible to create a empty field o something like this?
For example Date and Created By has every one 1/2 of the space, while Last Modified has 2/2. How can I do?
Thank you
EDIT.
props.display[0].number is only a number that i pass (for example 2,3,4) to obtain the number of cols
EDIT2:
Example of Array that I pass:
const Content = [
{
id: 'id',
name: 'ID',
value: realm.id,
},
{
id: 'realmId',
name: 'ID Realm',
value: realm.realmId,
},
{
id: 'name',
name: 'name',
value: realm.name,
}
]
const Display = [
{
number: 2,
},
];
so my render is:
render(
<RenderDetailRow content={Content} display={Display} />
)
For 1, you are missing key in if block
Try point 2:
function chunkArray(array, size) {
if(array.length <= size){
return [array]
}
return [array.slice(0,size), ...chunkArray(array.slice(size), size)]
}
export const RenderDetailRow = props => {
const columns = props.content.map((content, idx) => {
return (
<div
key={`item_${idx}`}
className="col-sm py-3"
>
<b>{content.name + ': '}</b>
<Input type="text" name={content.name} id={content.id} readOnly value={content.value} />
</div>
);
});
const rows = chunkArray(columns, NUMBER_OF_ROWS);
return rows.map((row, index) => (
<div className="row" key={index} style={{ margin: 30 }}>
{row[index]}
{row[index].length - NUMBER_OF_ROWS !== 0
? // (render row[index].length - NUMBER_OF_ROWS) empty columns here
: null}
</div>
))
};

react Carousel from scratch logic with visibility

what's the logic or algorithm for a Carousel? I'm done my research for 1 item per display but in my case I need to display 3 items, when I click on the next I expect the first item is hidden and the 4th item appear.
<div className="App">
<div className="Container">
{items.map((item, i) => (
<div className={`item ${i < lastIndex ? "visible" : "hidden"}`}>
{item.name}
</div>
))}
</div>
<div className="prev">{"<"}</div>
<div className="next">{">"}</div>
</div>
https://codesandbox.io/s/frosty-babbage-djron?file=/src/App.js
You will have to keep track of the first and last index that should be displayed. Anything outside them, you can skip
import React, { useState } from "react";
import "./styles.css";
const items = [
{
name: "box 1"
},
{
name: "box 2"
},
{
name: "box 3"
},
{
name: "box 4"
},
{
name: "box 5"
}
];
export default function App() {
const [firstIndex, setFirstIndex] = useState(0);
const [lastIndex, setLastIndex] = useState(3);
return (
<div className="App">
{/* <h1>{lastIndex}</h1> */}
<div className="Container">
{items.map((item, i) => {
if (i >= firstIndex && i < lastIndex) {
return (
<div key={item.name} className={"visible"}>
{item.name}
</div>
);
} else {
return null;
}
})}
</div>
<div
className="prev"
onClick={() => {
if (firstIndex > 0) {
setFirstIndex(firstIndex - 1);
setLastIndex(lastIndex - 1);
}
}}
>
{"<"}
</div>
<div
className="next"
onClick={() => {
if (lastIndex < items.length) {
setFirstIndex(firstIndex + 1);
setLastIndex(lastIndex + 1);
}
}}
>
{">"}
</div>
</div>
);
}
https://codesandbox.io/s/elated-banach-6bfh2?file=/src/App.js
EDIT Updated the code to prevent first and last index going out of bound of items length
I hope this will help for you!
export default function App() {
const [startIndex, setStartIndex] = useState(1);
const [lastIndex, setLastIndex] = useState(3);
return (
<div className="App">
<div className="Container">
{
items.map((item, i) => {
if (i >= startIndex - 1 && i <= lastIndex)
return (
<div className={`item ${i < lastIndex ? "visible" : "hidden"}`} key={i}>
{item.name}
</div>
)
})
}
</div>
<div className="prev"
onClick={() => {
setStartIndex(startIndex - 1)
setLastIndex(lastIndex - 1)
}}
>{"<"}</div>
<div className="next"
onClick={() => {
setStartIndex(startIndex + 1)
setLastIndex(lastIndex + 1)
}}
>
{">"}
</div>
</div>
);
}

How to make a simple loop slider in the React?

Sorry for my English)
Do not judge strictly, since I just started working with the react.
I made a simple slider on the react and now I want to make it cyclic.
But I can’t. In my code it seems to be cyclic, but for some reason it skips the last picture.
how can i fix it?
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [
{
id: 1,
name: "Product 1",
price: 50,
q: 0,
category: "Sporting Goods",
images: [
"https://ihatetomatoes.net/demos/_rw/01-real-estate/tn_property04.jpg",
"https://ihatetomatoes.net/demos/_rw/01-real-estate/tn_property02.jpg",
"https://ihatetomatoes.net/demos/_rw/01-real-estate/tn_property01.jpg",
"https://ihatetomatoes.net/demos/_rw/01-real-estate/tn_property03.jpg"
],
currentImageIndex: 0,
isCycleMode: false,
cantGoPrev: false,
cantGoNext: true
},
{
id: 2,
name: "Product 2",
price: 70,
q: 0,
category: "Sporting Goods",
images: [
"https://ihatetomatoes.net/demos/_rw/01-real-estate/tn_property04.jpg",
"https://ihatetomatoes.net/demos/_rw/01-real-estate/tn_property02.jpg",
"https://ihatetomatoes.net/demos/_rw/01-real-estate/tn_property01.jpg",
"https://ihatetomatoes.net/demos/_rw/01-real-estate/tn_property03.jpg",
"https://ihatetomatoes.net/demos/_rw/01-real-estate/tn_property02.jpg",
"https://ihatetomatoes.net/demos/_rw/01-real-estate/tn_property01.jpg",
"https://ihatetomatoes.net/demos/_rw/01-real-estate/tn_property03.jpg"
],
currentImageIndex: 0,
isCycleMode: false,
cantGoPrev: false,
cantGoNext: true
}
]
};
}
nextSlideHandler = (e, item, index ) => {
let arr = [...this.state.data];
let newIndex = this.state.data[index].currentImageIndex;
if (e.currentTarget.dataset.direction === "next") {
if (newIndex < this.state.data[index].images.length - 1) {
newIndex = this.state.data[index].currentImageIndex + 1;
arr[index].cantGoPrev = true;
this.setState({data:arr})
}
if (newIndex === this.state.data[index].images.length - 1) {
newIndex = 0;
arr[index].cantGoNext = true;
this.setState({data:arr})
}
} else {
if (newIndex > 0) {
newIndex = this.state.data[index].currentImageIndex - 1;
arr[index].cantGoNext = true;
this.setState({data:arr})
}
if (newIndex === 0) {
arr[index].cantGoPrev = false;
this.setState({data:arr})
}
}
arr[index].currentImageIndex = newIndex;
this.setState({ data:arr });
}
render() {
return (
<div className="App">
<div>
<h3>Products</h3>
<div className="collection">
{this.state.data.map((item, index) => (
<div key={item.id} className="product">
<div className="product__image">
<div>
<button
disabled={!item.cantGoPrev}
data-direction="prev"
onClick={(e)=> this.nextSlideHandler(e,item, index)}
className="prev"
>
prev
</button>
</div>
<div>
<img
src={item.images[item.currentImageIndex]}
alt=""
/>
{item.images.currentImageIndex}
</div>
<div>
<button
disabled={!item.cantGoNext}
data-direction="next"
onClick={(e)=> this.nextSlideHandler(e, item, index)}
className="next"
>
next
</button>
</div>
</div>
<div className="product__name">{item.name}</div>
<div className="product__price">{item.price}</div>
</div>
))}
</div>
</div>
</div>
);
}
}
What is the best way to write a slider?
I will be glad of any help
First: There are many ways to achieve what you are trying to do, but this is how I would have done it.
Instead of using index to update different state, I would make a own component for Product. Inside that component you have full access to that products state and props. This makes it easier to work with the correct data.
I would also remove the next/previous-logic from the state and just do a check if the buttons should be active on render.
class App extends React.Component {
constructor (props) {
super(props)
this.state = {
data: [
{
id: 1,
name: 'Product 1',
price: 50,
q: 0,
category: 'Sporting Goods',
images: [
'https://ihatetomatoes.net/demos/_rw/01-real-estate/tn_property04.jpg',
'https://ihatetomatoes.net/demos/_rw/01-real-estate/tn_property02.jpg',
'https://ihatetomatoes.net/demos/_rw/01-real-estate/tn_property01.jpg',
'https://ihatetomatoes.net/demos/_rw/01-real-estate/tn_property03.jpg'
],
currentImageIndex: 0,
isCycleMode: false
},
{
id: 2,
name: 'Product 2',
price: 70,
q: 0,
category: 'Sporting Goods',
images: [
'https://ihatetomatoes.net/demos/_rw/01-real-estate/tn_property04.jpg',
'https://ihatetomatoes.net/demos/_rw/01-real-estate/tn_property02.jpg',
'https://ihatetomatoes.net/demos/_rw/01-real-estate/tn_property01.jpg',
'https://ihatetomatoes.net/demos/_rw/01-real-estate/tn_property03.jpg',
'https://ihatetomatoes.net/demos/_rw/01-real-estate/tn_property02.jpg',
'https://ihatetomatoes.net/demos/_rw/01-real-estate/tn_property01.jpg',
'https://ihatetomatoes.net/demos/_rw/01-real-estate/tn_property03.jpg'
],
currentImageIndex: 0,
isCycleMode: false
}
]
}
}
handleChange = (arr) => {
// State updates based on other state should be asynchronous
// https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous
this.setState((state, props) => {
const oldArr = [...state.data]
const arrIndex = oldArr.findIndex(x => x.id === arr.id)
oldArr[arrIndex] = arr
return ({
data: oldArr
})
})
}
render () {
return (
<div className='App'>
<div>
<h3>Products</h3>
<div className='collection'>
{this.state.data.map((item) => (
<Product
item={item}
key={item.id}
onChange={this.handleChange}
/>
))}
</div>
</div>
</div>
)
}
}
class Product extends React.Component {
handleSlideChange = (e) => {
const arr = { ...this.props.item }
if (e.currentTarget.dataset.direction === 'next') {
arr.currentImageIndex++
} else {
arr.currentImageIndex--
}
this.props.onChange(arr)
};
render () {
const { item } = this.props
return (
<div key={item.id} className='product'>
<div className='product__image'>
<div>
<button
disabled={item.currentImageIndex <= 0}
data-direction='prev'
onClick={this.handleSlideChange}
className='prev'
>
Prev
</button>
</div>
<div>
<img src={item.images[item.currentImageIndex]} alt='' />
{item.images.currentImageIndex}
</div>
<div>
<button
disabled={item.currentImageIndex >= item.images.length - 1}
data-direction='next'
onClick={this.handleSlideChange}
className='next'
>
Next
</button>
</div>
</div>
<div className='product__name'>{item.name} {item.currentImageIndex}</div>
<div className='product__price'>{item.price}</div>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Categories