Set state doesn't work when drop event is fired - reactjs

When I remove the setState(in this case setImgDrag), the state does not take the value of the img selected, basically what I do is get the img from the sidebar and when the onDragStart event is fired I take the scr of the img and store it in a var called imgDrag, that works perfect, the point is that when I try to set the state of the img that is in the div, the state "imgDrag" does not get set. If you have a better implementation I will accept it.
import Img from "./img-card"
const DropImg=()=>{
const [img,setImg]=useState([])
const[imgDrag,setImgDrag]=useState()
const[position,setPosition]=useState({x:0,y:0})
let imgSelected;
let getImg=(e)=>{
let img=e.target.files
for(let i=0;i<img.length;i++){
setImg((prevState)=>{return ( img? [...prevState,URL.createObjectURL(img[i])] : [...prevState]) })
}
}
let dragOver=(e)=>{
e.preventDefault()
let xPosition=e.clientX
let yPosition=e.clientY
setPosition(()=>{return {["x"]:xPosition,["y"]:yPosition}})
console.log(position)
}
let drop=(e)=>{
e.preventDefault();
setImgDrag(imgSelected)
console.log(imgDrag)
}
return (
<div className="flex bg-gray-400">
<div className=" bg-gray-800 w-1/4 rem-width-25 px-5 pt-6 h-screen">
<div className="block">
<div className="relative bg-teal-500 border rounded py-12 m-auto text-center w-11/12 text-white ">
<input type="file" id="img" className="absolute top-0 m-auto left-0 cursor-pointer bg-gray-200 border border-gray-300 mb-3 outline-none py-10 px-5 rounded shadow-sm opacity-0" multiple onChange={getImg} />
Click Here Or Drop An Image
</div>
</div>
<div className="grid w-full grid-cols-3 gap-2 mt-10">
{(img? img.map((src,index)=>{return <Img key={index} id={index} draggable="true" onDragStart={e=>{ imgSelected= e.target.src}} src={src}/>}):null)}
</div>
</div>
<div onDrop={drop} onDragOver={dragOver} className="w-9/12 h-screen">
{imgDrag? <Img src={imgDrag} style={{width:400}}/>: null}
{img? null:<p id="drop-here" className="text-center">Drop Image Here!</p>}
</div>
</div>)
}
export default DropImg

It seems to have a problem using a variable - imgSelected, so try to also use useState for it.
// let imgSelected;
const [imgSelected, setImgSelected] = useState();
...
<div className="grid w-full grid-cols-3 gap-2 mt-10">
{(img? img.map((src,index)=>{
return <Img key={index}
id={index}
draggable="true"
// onDragStart={e=>{ imgSelected= e.target.src}}
onDragStart={e => setImgSelected(e.target.src) }
src={src}/>
}):null)
}
</div>

Related

Flexbox Items Not Vertically Centering In Tailwind

I am making a navbar in Tailwind consisting of links but I cannot get them to vertically center:
Here is what it looks like:
Steps I have tried:
items-center
justify-center
Setting the parent to flex-col
None of these options work.
How do you get the links to be exactly in the middle of the navbar vertically ?
Here is the code:
import React from 'react'
import Logo from '../images/Logo.png'
const Navbar = () => {
return (
<div className="flex justify-between items-center bg-gray-900">
<div className="">
<img className="w-40 py-2 px-2" src={Logo}></img>
</div>
<div className="flex flex-row items-center justify-center">
<p className="px-4 text-white">About</p>
<p className="px-4 text-white">Books</p>
<p className="px-4 text-white">Videos</p>
<p className="px-4 text-white">Quotes</p>
</div>
</div>
)
}
export default Navbar
The divs inside the flex class are aligned at the center, but the issue appears to be the first dive with the h-24 class which also contains the logo image. The logo aligns at the top of the div with the height of h-24 which is taller than the div containing the menu items. If you get rid of the h-24 or align the image vertically, they all align vertically. Try this:
<div class="flex justify-between items-center bg-gray-900">
<div class="h-24 flex items-center">
<img class="w-40 py-2 px-2" src="https://via.placeholder.com/150x50"></img>
</div>
<div class="flex">
<p class="px-4 text-white">About</p>
<p class="px-4 text-white">Books</p>
<p class="px-4 text-white">Videos</p>
<p class="px-4 text-white">Quotes</p>
</div>
</div>
It is working just fine. Please recheck the code you have sent, is it what it is producing the output you have produced in your question.
<div class="flex justify-between items-center bg-gray-900 h-24">
<div class="">
<img class="w-40 py-2 px-2" src=""></img>
</div>
<div class="flex ">
<p class="px-4 text-white">About</p>
<p class="px-4 text-white">Books</p>
<p class="px-4 text-white">Videos</p>
<p class="px-4 text-white">Quotes</p>
</div>
</div>
The output generated by the following code :
EDIT: The problem is that the list items were in tags and not tags - when changing the links from to , the list items centered vertically automatically without any further changes needed.
import React from 'react'
import Logo from '../images/Logo.png'
const Navbar = () => {
return (
<div className="flex justify-between items-center bg-gray-900 fixed inset-x-0 z-40">
<div className="">
<img className="w-40 px-2 mt-6" src={Logo}></img>
</div>
<div className="flex flex-row items-center justify-center mt-6">
<p className="px-4 text-white">About</p>
<p className="px-4 text-white">Books</p>
<p className="px-4 text-white">Videos</p>
<p className="px-4 text-white">Quotes</p>
</div>
</div>
)
}
export default Navbar

Tailwind CSS layout loses background

Using h-screen works until my datepicker comes up which expands the viewport
How do I make the background still fill (once a date box is hovered on it pops up the date picker)? The white space at the bottom of the date picker is the problem. I have a sidebar component for left-hand nav and a main content area.
Main content code:
.main-content {
#apply p-6 h-screen w-screen flex flex-col bg-slate-800 shadow-lg m-0 text-white;
}
Sidebar css:
.sidebar {
#apply h-screen w-20 flex flex-col bg-gray-900 shadow-lg m-0 px-3;
}
Datepicker code:
<div className="flex datepicker group-hover:scale-100 z-10">
<div className="grid grid-col-7 w-64 bg-gray-700 p-2 rounded-lg shadow-xl">
<div className="sub-text text-center">
{DateValue.monthLong} {DateValue.year}
<span
className="m-2 px-2 py-1 bg-gray-700 rounded-3xl hover:bg-gray-900 cursor-pointer"
onClick={(e) => changeMonth(e, false)}
>
<
</span>
<span
className="px-2 py-1 bg-gray-700 rounded-3xl hover:bg-gray-900 cursor-pointer"
onClick={(e) => changeMonth(e, true)}
>
>
</span>
</div>
<hr className="mb-2" />
<div className="grid grid-cols-7 pb-2">
<div className="text-center">Su</div>
<div className="text-center">Mo</div>
<div className="text-center">Tu</div>
<div className="text-center">We</div>
<div className="text-center">Th</div>
<div className="text-center">Fr</div>
<div className="text-center">Sa</div>
</div>
<div className="grid grid-cols-7">{daysAsInput()}</div>
</div>
</div>
CSS (Tailwind Apply)
.datepicker {
#apply absolute transition-all duration-100 scale-0;
}
.datepicker-day {
#apply m-1 bg-gray-700 rounded-lg shadow-lg
cursor-pointer items-center justify-center
p-1 text-sky-400 hover:bg-gray-900;
}
It scales to 100 when the input is hovered over.
Layout code:
<div className="flex">
<Sidebar />
<div className="main-content min-h-screen">{children}</div>
</div>
daysAsInput code:
const daysAsInput = () => {
// loop through the days in the month but start at the first day of the week
const inputs = [];
for (
let i = firstDayOfMonthAligned.day;
i <= firstDayOfMonthAligned.daysInMonth;
i++
) {
// create input that's grayed out if it's not in the current month
inputs.push(
<input
key={'previousMonth ' + i}
className="datepicker-day disabled:text-gray-400"
type="button"
value={i}
disabled={true}
onClick={dateChanged}
/>
);
}
for (let i = 1; i <= daysInMonth; i++) {
inputs.push(
<input
className="datepicker-day"
key={i}
type="button"
name="day {i}"
value={i}
onClick={dateChanged}
/>
);
}
return inputs;
};
The problem is caused by the fact that you position the datepicker absolute.
From the docs:
The element is removed from the normal document flow, and no space is
created for the element in the page layout.
You must take another approach, probably with z-index or javascript.
Try to change it to min-h-screen . That should do the magic
I think the problem is, we need to adjust the height styling of main-content class.
We can add "min-h-full" to the main-content class,
.main-content {
#apply p-6 h-screen w-screen flex flex-col bg-slate-800 shadow-lg m-0 text-white min-h-full;
}
This tailwind class will adjust the height of main-content to 100%. And the white background, have no room anymore.
Here was the reference of min-height
Thank you

Change inner div on hover in react grid tailwind

So, for CSS I am using tailwindcss.
I have implemented integer based approach but when I hover quickly over the divs, the state remains un updated. If the value is 0, the first div is shown else the second div is shown.
Below is the code :
<div className="text-white m-8 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 grid-flow-row gap-8">
{
data.map((d,idx)=>(
<div onMouseEnter={()=>{toggleState(idx,1)}} onMouseLeave={()=>{toggleState(idx,0)}} key={'event'+idx} className="relative h-96 overflow-hidden" style={{background: "-webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0.1)), to(rgba(0, 0, 0, 1))), url('https://images.unsplash.com/photo-1475855581690-80accde3ae2b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=750&q=80') no-repeat",backgroundSize:'cover'}}>
{!v[idx] && (
<div className="absolute w-full py-2.5 bottom-0 inset-x-0 text-white text-center leading-4">
<div className='divide-y-2 px-2 h-full'>
<h2 class="mt-2 mb-2 font-bold text-2xl">{d.title}</h2>
<p class="text-lg">{d.dueDate}</p>
</div>
</div>
)}
{v[idx] && (
<div className="absolute w-full py-2.5 text-white text-center leading-4">
<div className='px-2 w-full'>
<h2 class="mt-2 mb-2 font-bold text-2xl">{d.title}</h2>
<p class="text-lg">{d.desc}</p>
<span className='bottom-0 right-0'>Go to Course =</span>
{/* <a href="#" className='align-bottom'>Go to the Course</a> */}
</div>
</div>
)}
</div>
))
}
</div>
The function for toggle state
const [v,setV] = useState([0,0,0,0,0,0,0]);
const toggleState = (idx,value)=>{
const newV = [...v];
newV[idx]=value;
setV(newV);
}
What is the best way to implement such utility?
It is hard to give you the best help given the out of context snippet of code you gave. But to improve the UX and the performance of your interaction you could avoid to handle all that in the list.
You could start isolating the components of the list and handle the mouse in/out in the single component.
Something like this:
<div>
{data.map((d,idx)=> <YourComponent d={d} />}
</div>
YourComponent:
function YourComponent(props) {
return (
<div onMouseEnter={...} onMouseLeave={...} >
...
</div>
)}
This way every single component would handle itself and the list will not re-render on every mouse move.

React/Tailwind CSS: Search bar filter moving when typed in/filtering data

Its been a while since I coded in react and I'm working on teaching myself again. Also this is the first time I've used Tailwind CSS. I'm working with a navbar component that has a search bar to filter data within a database. I have everything setup correctly for the most part. The issue is that when you type in the search bar, the user img, and buttons moved like the nav sections is being pushed down when the filter response shows up below the search bar.
Here is my code for the navbar with the search bar
import React, { useState } from "react";
import UserDropdown from "../../components/Dropdowns/UserDropdown.js";
import AccountDropdown from "../Dropdowns/AccountDropdown.js";
export default function Navbar({ data }) {
const [filteredData, setFilteredData] = useState([]);
const [wordEntered, setWordEntered] = useState("");
const handleFilter = (event) => {
const searchWord = event.target.value;
setWordEntered(searchWord);
const newFilter = data.filter((value) => {
return value.dealership.toLowerCase().includes(searchWord.toLowerCase());
});
if (searchWord === "") {
setFilteredData([]);
} else {
setFilteredData(newFilter);
}
};
return (
<>
{/* Navbar */}
<div className="relative bg-lightBlue-600 md:pt-32 pb-32 pt-12">
<nav className="absolute top-0 left-0 w-full z-10 bg-transparent md:flex-row md:flex-nowrap md:justify-start flex items-center p-4">
<div className="w-full mx-autp items-center flex justify-between md:flex-nowrap flex-wrap md:px-10 px-4">
{/* Brand */}
<a
className="text-white text-sm uppercase hidden lg:inline-block font-semibold"
href="#pablo"
onClick={(e) => e.preventDefault()}
>
Dashboard
</a>
<div className="md:flex flex-row flex-wrap items-center lg:ml-auto mr-3">
<AccountDropdown />
</div>
{/* Form */}
<form className="md:flex hidden flex-row flex-wrap items-center lg:ml-auto mr-3">
<div className="relative flex w-full flex-wrap items-stretch">
<span className="z-10 h-full leading-snug font-normal absolute text-center text-blueGray-300 absolute bg-transparent rounded text-base items-center justify-center w-8 pl-3 py-3">
<i className="fas fa-search"></i>
</span>
<input
type="text"
placeholder="Search here..."
className="border-0 px-3 py-3 placeholder-blueGray-300 text-blueGray-600 relative bg-white bg-white rounded text-sm shadow outline-none focus:outline-none focus:ring w-full pl-10"
value={wordEntered}
onChange={handleFilter}
/>
</div>
{filteredData.length != 0 && (
<div className="dataResult">
{filteredData.slice(0, 15).map((value) => {
return (
<a className="dataItem" href="/admin/dashboard">
<p>{value.dealership}</p>
</a>
);
})}
</div>
)}
</form>
{/* User */}
<ul className="flex-col md:flex-row list-none items-center hidden md:flex">
<UserDropdown />
</ul>
</div>
</nav>
</div>
{/* End Navbar */}
</>
);
}
Here are a few pics of what it does.
I guess it is because of align-items property. When the data shows, the height of the component is changing so alignment should be flex-start in css. You can remove items-center because its default value is flex-start in css. Or you can replace with items-start.
You wrote
<nav className="absolute top-0 left-0 w-full z-10 bg-transparent md:flex-row md:flex-nowrap md:justify-start flex items-center p-4">
And I think it should be like this
<nav className="absolute top-0 left-0 w-full z-10 bg-transparent md:flex-row md:flex-nowrap md:justify-start flex items-start p-4">
Or this
<nav className="absolute top-0 left-0 w-full z-10 bg-transparent md:flex-row md:flex-nowrap md:justify-start flex p-4">

Trying to change the inner element by using get element and it throws error TypeError: Cannot set property 'innerHTML' of null

I am trying to change the element through get element by id and it is throwing:
TypeError: Cannot set property 'innerHTML' of null.
Is this how we pass parameters or we have other approaches?
My code:
const [isOpen, setIsOpen] = useState(false);
const togglePopup = (name='shraweg') => {
setIsOpen(!isOpen);
let inner = document.getElementById(name)
inner.innerHTML=(
<>
{
isOpen &&
<div className="popup-box">
<div className="flex flex-col box gap-1">
<div>
<p className="font-meduim text-lg">Are you sure you want to kick {" "+player.username+" "} ?</p>
</div>
<div className="flex flex-row gap-14 items-center justify-center">
<button type="submit" onClick={handleKick} value={player._id} className="border font-semibold text-lg border-red-300 rounded-xl hover:bg-red-600 px-6">
Yes
</button>
<button onClick={togglePopup} className="border font-semibold text-lg border-yellow-300 rounded-xl hover:bg-yellow-500 px-6">
No
</button>
</div>
</div>
</div>
}
</>
)
}
Here I've written a function to change the elements inside my html tag:
return (
<legend className="text-xl mb-5 border-yellow-500 border-l-4 pl-2 mt-10">Team Members</legend>
<div className="flex gap-5 flex-col w-full mb-4">
{props.team.players.map((player, key) => (
<div key={key} className="">
<label htmlFor="csgoign" className="flex bg-gray-50 hover:bg-gray-200 p-3 rounded-xl w-full items-center justify-between">
<div className="flex font-medium gap-3">
<img src={"https://robohash.org/"+player.username+"?set=set5"} className="w-12 h-12 rounded-3xl bg-blue-100"/>
<div className="ml-3">
<a href={"http://localhost:3000/userprofile/"+player._id} className="text-2xl w-auto font-semibold hover:text-yellow-600">
{player.username}
</a>
<p className="text-sm font-normal text-gray-700 font-paragraph">
Member since : {player.join_date}
</p>
</div>
</div>
{props.user._id == props.team.team_cap && (
<>
{!(player.username == props.user.username) && (
<div id={player.username}>
{
!isOpen &&
<button type="button" onClick={togglePopup(player.username)} className="border font-semibold text-xl border-red-300 rounded-xl hover:bg-red-600 px-7 py-2">
Kick
</button>
}
</div>
)}
</>
)}
</label>
</div>
))}
</div>
)
onClick={togglePopup(player.username)}
change to
onClick={()=>togglePopup(player.username)}
onClick property should be a function

Resources