Cannot pass multiple attributes of an elements to a java script function - javascript

I am trying to pass the id and name attributes from below elements to handle Click event but only the id is being passed. When debugging name shows "undefined". Did I miss anything
function App() {
const [id, setId] = React.useState('')
const [name, setName] = React.useState('')
const handleClick = event => {
debugger
setName(event.target.name)
setId(event.target.id)
}
return (
<form>
<svg width="800" height="250">
<rect onClick={handleClick} id="0" name="Rectangle" x="10" y="10" width="150" height="150" fill="green" />
<circle onClick={handleClick} id="1" name="Circle" cx="300" cy="90" r="75" fill="red" />
<polygon onClick={handleClick} id="2" name="Triangle" points="500,10 600,160 400,160" style={{ fill: "blue" }} />
</svg>
<Display id={id} name={name} />
</form>
)
}
Debugging screen shot below

const handleClick = event => {
// debugger
setName(event.target.id);
setId(event.target.getAttribute("name"));
};
demo
https://codesandbox.io/s/frosty-breeze-emiwc?file=/src/App.js

Please try this:
<rect onClick={(e) => {
this.clickMe(e, {id: "0", name: "Rectangle"})
}}>Click Me</rect>
The function body
function clickMe(event, attribute){
console.log(attribute.id);
console.log(attribute.name);
}

Related

React - How to show skeleton placeholders until Array map function ended

I have a country list component that contains country phone codes, country names and their flags using map() function so it takes a bit long to load. I need to get the information if map() function ended or still working then use it for showing then hiding placeholders. How could I achieve that?
I couldn't find proper solutions on Internet or couldn't use them. Like when using Promise(all) in a React Component, I've been having hardness to figure out how syntax should be.
<CountryList /> component:
// Packages I used for countries
import { getCountries, getCountryCallingCode } from "react-phone-number-input"
import countryNames from "react-phone-number-input/locale/en.json"
import ReactCountryFlag from "react-country-flag"
// The array comes from package
const countries = getCountries()
<CountryList>
{countries.map((country) => (
<CountryItem key={country} value={country}>
<ReactCountryFlag countryCode={country} svg />
<span>
{countryNames[country]}
<span>+{getCountryCallingCode(country)}</span>
</span>
</CountryItem>
))}
</CountryList>
<CountryItemSkeleton /> component:
// The package I used for skeleton placeholder
import ContentLoader from "react-content-loader"
<CountryItemSkeleton>
<CountryItem>
<ContentLoader>
<rect x="0" y="0" rx="3" ry="3" width="40" height="30" />
<rect x="52" y="8" rx="7" ry="7" width="248" height="14" />
</ContentLoader>
</CountryItem>
<CountryItem>
<ContentLoader>
<rect x="0" y="0" rx="3" ry="3" width="40" height="30" />
<rect x="52" y="8" rx="7" ry="7" width="248" height="14" />
</ContentLoader>
</CountryItem>
<CountryItem>
<ContentLoader>
<rect x="0" y="0" rx="3" ry="3" width="40" height="30" />
<rect x="52" y="8" rx="7" ry="7" width="248" height="14" />
</ContentLoader>
</CountryItem>
</CountryItemSkeleton>
Everything here is synchronous so you cannot wait for or monitor the map() progress.
What you can try though is loading the country list in an effect hook so that it's populated after your component is mounted. On the initial render you can use your skeleton component
const [countries, setCountries] = useState([]);
// run once on mount
useEffect(() => {
setCountries(getCountries());
}, []);
// or even with a small delay
useEffect(() => {
const timer = setTimeout(setCountries, 200, getCountries());
return () => {
clearTimeout(timerId);
};
}, []);
return countries.length === 0 ? (
<CountryItemSkeleton />
) : (
<CountryList>
{countries.map((country) => (
<CountryItem key={country} value={country}>
{/* etc */}
</CountryItem>
))}
</CountryList>
);

Both click() and dispatchEvent does not trigger automatic click in reactjs

I have a react component that has an SVG image. I have divided the SVG into multiple react box. I have query selector which selects all the react box and JS click event to auto click that react.
I tried working with both click and dispatch event. But none of them works in my scenario.
Below is the section of the code I am working on.
componentDidMount() {
var element = document.querySelectorAll("square");
for(var i = 0; i<element.length; i++) {
element[i].dispatchEvent(new Event('click'));
}
}
render(){
return (
<React.Fragment>
<div className="col-12">
<svg viewBox="0 0 100 100">
<image xlinkHref={imageFile} height="100%" width="100%" />
<g><rect className="square" x="10" y="10" width="20" height="10" fillOpacity=".2" onClick={() =>console.log("clicked")}></rect> </g>
<g><rect className="square" x="30" y="10" width="20" height="10" fillOpacity=".4" onClick={() =>console.log("clicked")}></rect> </g>
</svg>
</div>
</React.Fragment>
)
}
I also tried using the click() function and did not work for SVG images and also is there a way we could automate a click in each square every 10 seconds?
You forgot a . in the query selector so the node list was actually empty.
If you want to automate a click in each square every 10 seconds, this code does the trick:
const elements = document.querySelectorAll(".square");
const intervalsIdentifiers = Array.from(elements).map(x => setInterval(() => x.dispatchEvent(new Event('click')), 10000));
The dispatchEvent method is indeed the only way, because the rect element doesn't have a click method (only HTML elements do, not SVG elements) as demonstrated below:
console.log('click' in SVGRectElement.prototype); // false
console.log(HTMLElement.prototype.hasOwnProperty('click')); // true
console.log(HTMLButtonElement.prototype instanceof HTMLElement); // true (a button has the click method)
console.log(SVGRectElement.prototype instanceof HTMLElement); // false
The full working code (native JavaScript but should work as well with React in the componentDidMount hook):
const elements = document.querySelectorAll(".square");
const intervalsIdentifiers = Array.from(elements).map(x => setInterval(() => x.dispatchEvent(new Event('click')), 10000));
<div className="col-12">
<svg viewBox="0 0 100 100">
<image xlink:Href="https://img-19.ccm2.net/8vUCl8TXZfwTt7zAOkBkuDRHiT8=/1240x/smart/b829396acc244fd484c5ddcdcb2b08f3/ccmcms-commentcamarche/20494859.jpg" height="100%" width="100%" />
<g><rect class="square" x="10" y="10" width="20" height="10" fillOpacity=".2" onclick="console.log('clicked')"></rect> </g>
<g><rect class="square" x="30" y="10" width="20" height="10" fillOpacity=".4" onclick="console.log('clicked')"></rect> </g>
</svg>
</div>

React SVG style element on hover

I have an array of squares inside SVG-based React component and I need to apply custom style (fill color set to purple) to square under cursor on hover.
I tried that with both CSS :hover and onMouseOver events, neither did work.
Any clues are much appreciated
const { render } = ReactDOM,
rootNode = document.getElementById('root')
const Matrix = ({m, n}) => (
<svg
viewBox={`0 0 ${m*10+10} ${n*10+10}`} xmlns="http://www.w3.org/2000/svg"
>
<defs>
<rect
id="cell"
width="5"
height="5"
className="cell"
onMouseOver={({target}) => target.style.cssText="fill:purple"}
/>
</defs>
<g>
{
Array(n).fill().map((row, rowIdx) => (
<g key={rowIdx}>
{
Array(m).fill().map((col, colIdx) => (
<g key={colIdx}>
<use
x={5+colIdx*5}
y={5+rowIdx*5}
xlinkHref="#cell"
fill="lightgray"
stroke="white"
strokeWidth=".4"
/>
</g>
))
}
</g>
))
}
</g>
</svg>
)
render (
<Matrix m={10} n={10} />,
rootNode
)
#cell:hover {
fill: purple;
}
.cell:hover {
fill: purple;
}
<script src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script></script><div id="root"></div>
If you have to color each square you must have to use your class .cell inside the <use /> of each cell:
<use
className="cell"
x={5+colIdx*5}
y={5+rowIdx*5}
xlinkHref="#cell"
fill="grey"
stroke="white"
strokeWidth=".4"
/>
And now you can use your css style:
.cell:hover {
fill: purple;
}
Snippet:
const { render } = ReactDOM,
rootNode = document.getElementById('root')
const Matrix = ({m, n}) => (
<svg
viewBox={`0 0 ${m*10+10} ${n*10+10}`} xmlns="http://www.w3.org/2000/svg"
>
<defs>
<rect
id="cell"
width="5"
height="5"
/>
</defs>
<g>
{
Array(n).fill().map((row, rowIdx) => (
<g key={rowIdx}>
{
Array(m).fill().map((col, colIdx) => (
<g key={colIdx}>
<use
className="cell"
x={5+colIdx*5}
y={5+rowIdx*5}
xlinkHref="#cell"
fill="grey"
stroke="white"
strokeWidth=".4"
/>
</g>
))
}
</g>
))
}
</g>
</svg>
)
render (
<Matrix m={10} n={10} />,
rootNode
)
.cell:hover {
fill: purple;
}
<script src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script></script><div id="root"></div>

My Custom made Seek Bar is not working Properly HTML5?

I am making a video player in React.js I am trying to make custom seekbar with sync to video but my seek is not working properly as expected while user dragging see this GIF.Seek bar is not responding to the user movement it is going back to the origin position.Hope this Gif will help you to identify the problem
My React Code.
import React, {Component} from 'react'
import './index.css'
class SampleVideo extends Component{
state = {
play:false,
pause:false,
onHover:false,
isMouseDown:false,
seekedPercentage:"0%"
};
componentDidMount(){
this.video.addEventListener('timeupdate', this.updateProgressBar, false);
}
updateProgressBar = () => {
let percentage = Math.floor((100 / this.video.duration) * this.video.currentTime);
this.setState({
seekedPercentage:`${percentage}%`
});
};
handleVideoPausePlay = () => {
return this.state.play ? this.pause() : this.play();
};
play = () => {
this.video.play();
this.setState({
play:true,
pause:false
})
};
pause = () => {
this.video.pause()
this.setState({
play:false,
pause:true
})
};
handleSeek = e => {
if(this.state.isMouseDown){
console.log("Dragginf")
let vid_duration = e.nativeEvent.offsetX / this.seek.offsetWidth;
let percentage = vid_duration * 100;
this.video.currentTime = vid_duration * this.video.duration;
this.setState({
seekedPercentage:`${percentage}%`
})
}else {
console.log('i don;t Move ')
}
};
handleMouseDown = e => {
this.setState({ isMouseDown:true })
};
handleMouseUp = e => {
this.setState({ isMouseDown:false });
};
render(){
// console.log(this.state);
return(
<div className="container">
<div onMouseEnter={e => this.setState({onHover:true})} onMouseLeave={e => this.setState({ onHover:false })} className="video-wrapper">
<video ref={(c) => this.video = c} width="100%" height="100%" controls muted={true}>
<source src="vid/test.MKV" type="video/mp4" />
<source src="vid/test.MKV" type="video/ogg" />
Your browser does not support the video tag.
</video>
{ this.state.onHover ? <div className="video-controls-container">
<div className="vid-title">
</div>
<div className="vid-control">
<div className="vid-seekbar">
<div ref={s => this.seek = s} onMouseUp={this.handleMouseUp} onMouseDown={this.handleMouseDown} onMouseMove={this.handleSeek} className="video-seek-bar">
<div style={{width:this.state.seekedPercentage}} className="videobarlevelbar">
</div>
<div className="seekControl">
<div className="seekImage"><img src="/css/0d20f779-fd6f-49e2-903a-aed7380a00a2.webp" alt="dsvds" /></div>
<div className="seekRound" />
</div>
</div>
</div>
<div className="vid-mini-controller">
{ !this.state.play ? <div onClick={this.handleVideoPausePlay} className="play-btn">
<svg height="32px" style={{enableBackground: 'new 0 0 24 32'}} version="1.1" viewBox="0 0 24 32" width="24px" xmlSpace="preserve" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink"><g id="Layer_1" /><g id="play"><polygon points="0,0 24,16 0,32 " style={{fill: '#fff'}} /></g></svg>
</div> : <div onClick={this.handleVideoPausePlay} className="pause-btn">
<svg height="32px" id="svg2" width="32px" version="1.1" viewBox="0 0 32 32" xmlSpace="preserve">
<g id="background">
<rect height="32" width="32" fill="none"/>
</g>
<g id="pause">
<g>
<rect fill="#fff" height="24" width="8" x="20" y="4"/>
<rect fill="#fff" height="24" width="8" x="4" y="4"/>
</g>
</g>
</svg>
</div> }
</div>
</div>
</div> : "" }
</div>
</div>
)
}
}
export default SampleVideo
I just tried your code without the css part, and it works fine on a video with the default html5 player. Does it work with a video or do you have the same issue ?
Could you post your css so I can give it a try ?

SVG Knockout text styling issue: unexplained cropped bottom

I've tried to build a react component for knockout text and I run into a styling issue I can't explain to myself.
Here is my attempt.
const styles = {
container: {
backgroundSize: "cover",
backgroundImage: "url(http://brokensquare.com/Code/assets/landscape.jpg)",
padding: "20% 20%"
},
knockout: {
borderRadius: 200,
overflow: "hidden"
}
};
const Knockout = ({ text, style }) => {
const s = style || {};
return (
<div style={styles.knockout}>
<svg viewBox="0 0 200 25">
<rect
fill={s.backgroundColor || "rgba(0,0,0,0.6)"}
x="0"
y="0"
width="100%"
height="100%"
mask="url(#knockout-text)"
/>
<mask id="knockout-text">
<rect fill="#fff" x="0" y="0" width="100%" height="100%" />
<text y="70%" fill="#000" textAnchor="middle" x="50%">
{text}
</text>
</mask>
</svg>
</div>
);
};
const App = Radium(() => (
<div>
<div style={styles.container}>
<Knockout style={{}} text={"VERY INSPIRATION"} />
</div>
</div>
));
As you can see the bottom is cropped for some reason, instead of having the side completely rounded, drawing half a circle. Can anyone here see why and how I could fix this ? Thanks.
add this css, it will work
svg {
display: block
}
you can check below codesandbox
https://codesandbox.io/s/71qxyx6m86
I added styles as below
render(
<div>
<App />
<Style
rules={{
"*": {
margin: 0,
padding: 0,
boxSizing: "border-box"
},
svg: {
display: "block"
}
}}
/>
</div>,
document.getElementById("root")

Categories

Resources