whenever my layout changes, it will save the new changes into localstorage and update my layout state
onLayoutChange(layouts) {
saveToLS("layouts", layouts);
}
However, the issue occurs When the page is refreshed. layout was updated before it was fetched from local storage, this means it discard all the changes and reset the layout to default. The image below shows what i mean
What should I do to prevent this from happening?? I am following this guide. It is working on the guide but not for me, really appreciate any help
Here is the full code I am using
const originalLayouts = getFromLS("layouts") || {};
const ResponsiveReactGridLayout = WidthProvider(Responsive);
class MinMaxLayout extends React.PureComponent {
static defaultProps = {
margin:[0,0],
className:"layout",
cols: { lg: 1, md: 10 },
rowHeight: 100
};
constructor(props) {
super(props);
this.state = {
layouts: JSON.parse(JSON.stringify(originalLayouts)),
inputWidthVal: "",
inputHeightVal:"",
items: [0, 1, 2, 3, 4].map(function (i, key, list) {
return {
id: uuidV4(),
i: i.toString(),
x: i * 2,
y: 0,
w: 1,
h: 1
};
}),
charts: [0].map(function (i, key, list) {
return {
id: uuidV4(),
i: i.toString(),
x: i,
y: 0,
w: 4,
h: 3
};
}),
newCounter: 0,
chartCounter:0
};
this.onAddItem = this.onAddItem.bind(this);
this.onChartItem = this.onChartItem.bind(this);
this.onBreakpointChange = this.onBreakpointChange.bind(this);
}
createElement(el) {
const removeStyle = {
position: "absolute",
left: "11px",
top: 0,
cursor: "pointer"
};
const i = el.i;
return (
<div key={el.id} data-grid={el} >
<span
className="remove"
style={removeStyle}
onClick={this.onRemoveItem.bind(this, i)}
>
x
</span>
</div>
);
}
// this is the charts that was created when the DOM was render
createChart(el) {
const removeStyle = {
position: "absolute",
left: "11px",
top: 0,
cursor: "pointer"
};
const i = el.i;
return (
// <div key={el.id} data-grid={el} onClick={((e) => this.handleClick(e))}>
<div key={el.id} data-grid={el} className="graph">
<Newvsresturnvisitors />
<span
className="remove"
style={removeStyle}
onClick={this.onRemoveChartItem.bind(this, i)}
>
x
</span>
</div>
);
}
onAddItem() {
this.setState({
// Add a new item. It must have a unique key!
items: this.state.items.concat({
id: uuidV4(),
i: "n" + this.state.newCounter,
x: (this.state.items.length * 2) % (this.state.cols || 12),
y: Infinity, // puts it at the bottom
w: 1,
h: 1
}),
// Increment the counter to ensure key is always unique.
newCounter: this.state.newCounter + 1
});
}
onChartItem() {
this.setState({
// Add a new item. It must have a unique key!
charts: this.state.charts.concat({
id: uuidV4(),
i: "n" + this.state.chartCounter,
x: (this.state.charts.length * 2) % (this.state.cols || 12),
y: 0, // puts it at the bottom
w: 4,
h: 3
}),
// Increment the counter to ensure key is always unique.
chartCounter: this.state.chartCounter + 1
});
}
// We're using the cols coming back from this to calculate where to add new items.
onBreakpointChange(breakpoint, cols) {
this.setState({
breakpoint: breakpoint,
cols: cols
});
}
onRemoveItem(i) {
this.setState({ items: _.reject(this.state.items, { i: i }) });
}
clearAllItem = ()=>{
this.setState({ items: [], charts: [] });
}
onRemoveChartItem(i){
this.setState({ charts: _.reject(this.state.charts, { i: i }) });
}
inputCanvasDimension = e =>{
const re = /^[0-9\b]+$/;
if (e.target.value === '' || re.test(e.target.value)) {
if(e.currentTarget.className === "inputWidth"){
this.setState({inputWidthVal: e.currentTarget.value});
}else if(e.currentTarget.className === "inputHeight"){
this.setState({inputHeightVal: e.currentTarget.value});
}
}
}
setCanvasDimension = () =>{
var canvas = document.getElementById("DetailLocationContainer");
if((this.state.inputWidthVal < 1000) || (this.state.inputHeightVal < 3000)){
alert("Width should not be less than 1000 and height should not be less than 3000");
}else {
canvas.style.width= this.state.inputWidthVal + "px";
canvas.style.height= this.state.inputHeightVal + "px";
}
}
saveToLS(key, value) {
var secondObject = Object.entries(value)[1];
if (global.localStorage) {
global.localStorage.setItem(
"rgl-8",
JSON.stringify({
[key]: value
})
);
}
}
onLayoutChange(layout, layouts) {
this.saveToLS("layouts", layouts);
}
onDrop = (layout, layoutItem, _event) => {
if(_event.dataTransfer.mozSourceNode.className === "textwidget"){
this.setState({
items: this.state.items.concat({
id: uuidV4(),
i: "n" + this.state.newCounter,
x: layoutItem.x,
y: layoutItem.y,
w: 1,
h: 1
}),
newCounter: this.state.newCounter + 1
});
}else if(_event.dataTransfer.mozSourceNode.className === "chart"){
this.setState({
// Add a new item. It must have a unique key!
charts: this.state.charts.concat({
id: uuidV4(),
i: "n" + this.state.chartCounter,
x: (this.state.charts.length * 2) % (this.state.cols || 12),
y: Infinity, // puts it at the bottom
w: 5,
h: 6
}),
// Increment the counter to ensure key is always unique.
chartCounter: this.state.chartCounter + 1
});
}
};
reset = () =>{
// window.location.reload(true);
this.setState({ layouts: {} });
}
render() {
return (
<div className="container" id="container">
<div className="btn_container">
<div>
<span>Width </span>
<input className="inputWidth" value={this.state.inputWidthVal} onChange={this.inputCanvasDimension}/>
<span> Height </span>
<input className="inputHeight" value={this.state.inputHeightVal} onChange={this.inputCanvasDimension}/>
<button onClick={this.setCanvasDimension}>Apply</button>
<button onClick={this.reset}><CachedIcon style={{fontSize: '14px'}}/></button>
<button onClick={openFullscreen}><FullscreenSharpIcon style={{fontSize: '14px'}}/></button>
</div>
</div>
<button id="createItemBtn" onClick={this.onAddItem}>Add Item</button>
<button id="createChartBtn" onClick={this.onChartItem}>Add Chart</button>
<button onClick={this.clearAllItem}>Clear All</button>
<div className="widgetcontainer">
<WidgetThumbnail
className="chart"
/>
<WidgetThumbnail
className="textwidget"
/>
</div>
<div className='DetailLocationContainer' id="DetailLocationContainer" >
<ResponsiveReactGridLayout
cols={{ lg: 1, md: 10, sm: 6, xs: 4, xxs: 2 }}
rowHeight={100}
onDrop={this.onDrop}
isDroppable={true}
isBounded={true}
layouts={this.state.layouts}
onLayoutChange={(layout, layouts) =>
this.onLayoutChange(layout, layouts)
}
onBreakpointChange={this.onBreakpointChange}
{...this.props}
>
{_.map(this.state.items, (el) => this.createElement(el))}
{_.map(this.state.charts, (el) => this.createChart(el))}
</ResponsiveReactGridLayout>
</div>
</div>
);
}
}
export default MinMaxLayout;
const rootElement = document.getElementById("root");
ReactDOM.render(<MinMaxLayout />, rootElement);
This is my getFrinLS
export function getFromLS(key) {
let md = {};
if (global.localStorage) {
try {
md = JSON.parse(global.localStorage.getItem("rgl-8")) || {};
} catch (e) {
/*Ignore*/
}
// console.log("return value ", md[key]);
return md[key];
}
}
Looks like incremental keys are needed to apply updated layout. Change the key value from el.id to i
createElement(el) {
const removeStyle = {
position: "absolute",
left: "11px",
top: 0,
cursor: "pointer"
};
const i = el.i;
return (
<div key={i} data-grid={el} >
<span
className="remove"
style={removeStyle}
onClick={this.onRemoveItem.bind(this, i)}
>
x
</span>
</div>
);
}
Related
I am trying to create a stacked barchart with svg and html and not using any 3rd party library. Unfortunately, there is not a single document online which shows how to create a stacked bar chart using plain svg.
I have created a codepen and i am midway to achieving that stacked barchart. Can anyone please let me know what else is needed to make this a stacked barchart.
https://codepen.io/a166617/pen/qBXvzQd
Here is the code that i currently have
const ReleaseScopeCharts = () => {
const data = [
{
name: 'Transit',
passed: 2,
skipped: 5,
failed: 22,
},
{
name: 'Access',
passed: 7,
skipped: 2,
failed: 11,
},
];
const width = 500;
const colors = ['#30D158', '#005EA7', '#FF453A'];
const entries = data.map((d) => ({
name: d.name,
total: ['passed', 'skipped', 'failed'].reduce((acc, key) => acc + d[key], 0),
bars: ['passed', 'skipped', 'failed'].map((key, i) => ({
value: d[key],
color: colors[i],
}))
.filter((bar) => bar.value),
}));
const rows = (entry) => entry.bars.map((bar, index) => {
const height = (bar.value / entry.total) * 100;
return (
<g key={index}>
<rect
width={50}
height={`${height}%`}
fill={bar.color}
x={index * 60} // multiply with the width (50) + 10 for space
/>
</g>
);
});
return (
<div className="new-card">
<div />
{entries.map((entry) => (
<>
{entry.name}
<svg viewBox={`0, 0, ${width}, ${500}`}
height={500}
width={width}
style={{ transform: `rotateX(180deg)` }}
>
{rows(entry)}
</svg>
</>
))}
</div>
);
};
With stacked barchart, i mean showing one over the other.
To stack barchart, you need to calculate the current columns and space widths. Wrap the svg to div, also offset the text in to div and centered with display:flex.
Add the y key to the bars, where:
start point = passed = 0
middle point = skipped = passed value
end point = failed = passed value + skipped value
y: key === 'passed' ? 0 : key === 'skipped' ? d['passed'] : d['skipped'] + d['passed'],
// Basic style
const newCardStyle = {
display: 'flex',
};
const contentStyle = {
display: 'flex',
flexFlow: 'column',
alignItems: 'center',
};
// multiply 50 (width) * 3 (columns) + 10 (space width) * 2 ( space between columns)
const width = 50 * 3 + 10 * 3;
function App() {
const data = [
{
name: 'Transit',
passed: 2,
skipped: 5,
failed: 22,
},
{
name: 'Access',
passed: 7,
skipped: 2,
failed: 11,
},
];
// Basic style
const newCardStyle = {
display: 'flex',
};
const contentStyle = {
display: 'flex',
flexFlow: 'column',
alignItems: 'center',
};
// multiply 50 (width) * 3 (columns) + 10 (space width) * 2 ( space between columns)
const width = 50 * 3 + 10 * 3;
const colors = ['#30D158', '#005EA7', '#FF453A'];
const entries = data.map(d => ({
name: d.name,
total: ['passed', 'skipped', 'failed'].reduce(
(acc, key) => acc + d[key],
0
),
bars: ['passed', 'skipped', 'failed']
.map((key, i) => ({
value: d[key],
color: colors[i],
y:
key === 'passed'
? 0
: key === 'skipped'
? d['passed']
: d['skipped'] + d['passed'],
}))
.filter(bar => bar.value),
}));
const rows = entry => {
return entry.bars.map((bar, index) => {
const height = (bar.value / entry.total) * 100;
const y = (bar.y / entry.total) * 100;
return (
<g key={Math.random()}>
<rect
width={50}
height={`${height}%`}
fill={bar.color}
x={60} // multiply with the width (50) + 10 for space
y={`${y}%`}
/>
</g>
);
});
};
return (
<div className="new-card" style={newCardStyle}>
{entries.map(entry => (
<div style={contentStyle} key={Math.random()}>
<svg
viewBox={`0, 0, ${width}, ${500}`}
height={500}
width={width}
style={{ transform: `rotateX(180deg)` }}
>
{rows(entry)}
</svg>
{entry.name}
</div>
))}
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
<script src="https://unpkg.com/react#17/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#17/umd/react-dom.production.min.js" crossorigin></script>
<div id="root"></div>
I'm currently working on a Bumble-like swipe system so I can swipe horizontally (thanks to an Animated.View and a PanResponder so I can move my view wherever I want), and vertically (because my view is longer than the height of my screen).
After a long day of search, I finally found a solution which permits to know if the user is scrolling horizontally or vertically in the PanResponder, then choose if i block the move or not
The problem is that my canMove() function's console.log is printing null every time so only my vertical scroll is working currently. Otherwise, when i print my scrollType value in the onPanResponderMove, it changes well so I don't understand why my canMove() function gets null
here's my file so you can understand:
const story = useSelector((state) => state.entities.stories[storyId]);
const pan = useRef(new Animated.ValueXY(null, { useNativeDriver: true })).current;
const scrollType = useRef(null);
const checkSwipeDirection = (gestureState) => {
if (
(Math.abs(gestureState.dx) > Math.abs(gestureState.dy * 3))
&& (Math.abs(gestureState.vx) > Math.abs(gestureState.vy * 3))
) {
scrollType.current = 'horizontal';
} else {
scrollType.current = 'vertical';
}
};
const canMove = () => {
console.log('scrollType.current: ', scrollType.current);
if (scrollType.current === 'horizontal') {
return true;
}
return false;
};
const panResponder = useRef(
PanResponder.create({
onMoveShouldSetPanResponder: canMove,
onPanResponderGrant: () => {
pan.setValue({ x: 0, y: 0 });
},
onPanResponderMove: (evt, gestureState) => {
if (!scrollType.current) {
checkSwipeDirection(gestureState);
}
return Animated.event(
[null, { dx: pan.x, dy: pan.y }],
{ useNativeDriver: false },
);
},
onPanResponderRelease: () => {
Animated.spring(pan, {
toValue: 0,
useNativeDriver: false,
}).start();
scrollType.current = null;
},
}),
).current;
return (
<Animated.ScrollView
{...panResponder.panHandlers}
style={{
transform: [{ translateX: pan.x }, { translateY: pan.y },
{
rotate: pan.x.interpolate({
inputRange: [-200, 0, 200], outputRange: ['-20deg', '0deg', '20deg'],
}),
}],
}}
>
<TouchableOpacity activeOpacity={1} style={styles.card}>
<DiscoverCardHeader userId={story.recipient} />
<DiscoverStory
storyId={storyId}
navigation={navigation}
recipientId={story.recipient}
authorId={story.author}
/>
</TouchableOpacity>
</Animated.ScrollView>
);
};
if you need more informations i'm there to give you. hope we'll find a solution ! thanks
Try this, newbies <3
const pan = useRef(new Animated.ValueXY(null, {useNativeDriver: true})).current;
var [direction, setDirection] = useState(0)
const panResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => true,
onPanResponderGrant: (evt, gestureState) => {
setDirection(0)
pan.setValue({x: 0, y: 0});
},
onPanResponderMove: (evt, gestureState) => {
if ((direction === 0 || direction === 1) &&
(gestureState.dy > 20 || gestureState.dy < -20)) {
setDirection(1)
pan.setValue({x: 0, y: 0});
} else if ((direction === 0 || direction === 2) &&
(gestureState.dx > 20 || gestureState.dx < -20)) {
setDirection(2)
pan.setValue({x: gestureState.dx, y: 0});
}
},
onPanResponderRelease: () => {
setDirection(0)
pan.setValue({x: 0, y: 0});
},
})
const translate = {
transform: [
...[pan.getTranslateTransform()[0]]
]
}
return (
<Animated.ScrollView scrollEnabled={direction !== 2} >
<Animated.View
{...panResponder.panHandlers}
style={[translate]}
>
<View style={{
backgroundColor: "red",
marginTop: 100
}}>
<View>
<Text> Coucou</Text>
<Text style={{
marginTop: 1000
}}> Coucou juyin le chien</Text>
</View>
</View>
</Animated.View>
</Animated.ScrollView>
);
I want to get the effect of something like this:
And here is my best attempt as a combo graph:
The problem is I need to vastly ramp up the number of bars in this chart. However, when I try to do this the bars disappear.
Here is my code as a typescript reactjs setup:
import './App.css';
import React from 'react';
import { Bar, Line } from 'react-chartjs-2';
const createRandomFollowersData = () => {
const maxDate = new Date();
const minDate = new Date(maxDate.valueOf() - 5 * 365 * 24 * 60 * 60 * 1000);
const dataPoints = Array.from({ length: 500 }).map(() => ({
timestamp: new Date(
Math.floor(Math.random() * (maxDate.valueOf() - minDate.valueOf())) +
minDate.valueOf()
).toISOString(),
followers: Math.floor(Math.random() * 1000000) + 0,
}));
return dataPoints.sort(
(a, b) => new Date(a.timestamp).valueOf() - new Date(b.timestamp).valueOf()
);
};
const createRandomAssetData = () => {
const maxDate = new Date();
const minDate = new Date(maxDate.valueOf() - 5 * 365 * 24 * 60 * 60 * 1000);
const dataPoints = Array.from({ length: 500 }).map(() => ({
timestamp: new Date(
Math.floor(Math.random() * (maxDate.valueOf() - minDate.valueOf())) +
minDate.valueOf()
).toISOString(),
price: Math.floor(Math.random() * 45) + 1,
}));
return dataPoints.sort(
(a, b) => new Date(a.timestamp).valueOf() - new Date(b.timestamp).valueOf()
);
};
const followersData = createRandomFollowersData();
const yAxisFollowers = {
type: 'linear',
id: 'followers',
};
const yAxisDelta = {
type: 'linear',
position: 'right',
id: 'change',
};
const yAxisRank = {
type: 'linear',
id: 'rank',
ticks: {
reverse: true,
},
};
const yAxisAssets = {
type: 'linear',
position: 'right',
id: 'assets',
};
const selectChartAxes = (
containsFollowers: boolean,
containsRank: boolean,
showDelta: boolean,
showAssets: boolean
) => {
const yAxes = [];
if (containsFollowers) yAxes.push(yAxisFollowers);
if (containsRank) yAxes.push(yAxisRank);
if (showDelta) yAxes.push(yAxisDelta);
if (showAssets) yAxes.push(yAxisAssets);
return yAxes;
};
const decimateChart = (
data: {
t: Date;
y: number;
}[],
numBuckets: number,
startDate?: Date,
endDate?: Date
) => {
if (!startDate) {
startDate = data[0].t;
}
if (!endDate) {
endDate = data[data.length - 1].t;
}
// create evenly spaced dates
const dt = endDate.valueOf() - startDate.valueOf();
const startValue = startDate.valueOf();
const spacedDates = Array.from({ length: numBuckets + 1 }).map((_, idx) => {
return new Date(startValue + (idx * dt) / numBuckets);
});
// make buckets
const buckets = Array.from({ length: numBuckets + 2 }).map(() => []) as {
t: Date;
y: number;
}[][];
const filteredData = data.filter(
(e) => e.t >= spacedDates[0] && e.t <= spacedDates[spacedDates.length - 1]
);
// place data into buckets
let jdx = 0;
spacedDates.forEach((e, idx) => {
for (; jdx < filteredData.length; ) {
const e = filteredData[jdx];
const date = new Date(e.t);
if (date >= spacedDates[idx] && date <= spacedDates[idx + 1]) {
buckets[idx].push({
t: date,
y: e.y,
});
++jdx;
} else break;
}
});
// one plot per bucket
return buckets.map((bucket, idx) => {
const date = spacedDates[idx];
if (bucket.length === 0) {
return {
t: date,
y: NaN,
};
}
return bucket[bucket.length - 1];
});
};
const chartMappedFollowersData = followersData.map((followerData) => ({
t: new Date(followerData.timestamp),
y: followerData.followers,
}));
// const decimatedData = decimateChart(chartMappedFollowersData, 75);
const decimatedData = decimateChart(chartMappedFollowersData, 75).map(
(e, idx) => {
if (idx > 1 && idx < 10) {
return {
t: e.t,
y: NaN,
};
}
if (idx > 30 && idx < 45) {
return {
t: e.t,
y: NaN,
};
}
return e;
}
);
const decimatedDataToBars = (
data: {
t: Date;
y: number;
}[]
) => {
if (data.length < 2) {
return {
t: data[0].t,
y: data[0].y,
};
}
const bars = [];
const indexedData = data.map((e, idx) => ({
...e,
idx,
}));
const filteredIndexedData = indexedData.filter((e) => !isNaN(e.y));
for (let idx = 0; idx < filteredIndexedData.length - 1; ++idx) {
const dt = data[idx + 1].t.valueOf() - data[idx].t.valueOf();
for (
let idy = 0;
idy < filteredIndexedData[idx + 1].idx - filteredIndexedData[idx].idx;
++idy
) {
const t = new Date(filteredIndexedData[idx].t.valueOf() + idy * dt);
const deltaY =
(filteredIndexedData[idx + 1].y - filteredIndexedData[idx].y) /
(filteredIndexedData[idx + 1].idx - filteredIndexedData[idx].idx);
bars.push({
t,
y: deltaY,
});
}
}
return bars;
};
const chartOptionsLinear = {
scales: {
yAxes: selectChartAxes(true, false, true, true),
xAxes: [
{
type: 'time',
time: {
unit: 'day',
displayFormats: { day: 'MMM DD, Y' },
min: chartMappedFollowersData[0].t,
max: chartMappedFollowersData[chartMappedFollowersData.length - 1].t,
},
ticks: {
source: 'labels',
},
},
],
maintainAspectRatio: false,
},
};
const chartData = {
labels: decimatedData.map((e) => e.t).filter((_, idx) => idx % 3 === 0),
datasets: [
{
yAxisID: 'followers',
cubicInterpolationMode: 'monotone',
backgroundColor: 'rgb(54, 162, 235)',
borderColor: 'rgb(88, 88, 88)',
fill: false,
type: 'line',
label: 'followers',
spanGaps: true,
data: decimatedData,
},
{
yAxisID: 'change',
type: 'bar',
backgroundColor: 'rgb(235, 54, 162)',
label: 'delta',
data: decimatedDataToBars(decimatedData),
barThickness: 1,
},
],
};
function App(): JSX.Element {
return (
<div style={{ margin: '1em' }}>
<Bar data={chartData} options={chartOptionsLinear} />
</div>
);
}
export default App;
If you swap out data: decimatedDataToBars(decimatedData), to data: decimatedDataToBars(chartMappedFollowersData), you can see the effect; The bars disappear. Does anyone have any insight into this problem and how I can fix it?
So the issue was a bug in 2.8.0 that caused the bars to not show. Upgrading to 2.9.4 fixed the issue for me (but broke some other functionality of why I was using 2.8.0 in the first place.)
I am currently playing around with React pose. What I'm trying to do is animate different boxes in from the right, and exit them on the left. However, I can't seem to get the preEnterPose to work the way I want it. It always seems to default to the exit pose.
How can I get the boxes to animate in from the right, and exit on the left? Here is what I am working with
https://codesandbox.io/s/react-pose-enterexit-o2qqi?fontsize=14&hidenavigation=1&theme=dark
import React from "react";
import ReactDOM from "react-dom";
import posed, { PoseGroup } from "react-pose";
import "./styles.css";
const Card = posed.div({
enter: {
x: 0,
opacity: 1,
preEnterPose: {
x: 50
},
delay: 300,
transition: {
x: { type: "spring", stiffness: 1000, damping: 15 },
default: { duration: 300 }
}
},
exit: {
x: -50,
opacity: 0,
transition: { duration: 150 }
}
});
class Example extends React.Component {
state = { isVisible: false, index: 0, items: ["1", "2", "3", "4", "5"] };
componentDidMount() {}
next = () => {
if (this.state.index === this.state.items.length - 1) {
this.setState({
index: 0
});
} else {
this.setState({
index: this.state.index + 1
});
}
};
render() {
const { index, items } = this.state;
return (
<div>
<PoseGroup>
{items.map((id, idx) => {
if (idx === index) {
return (
<Card className="card" key={idx}>
{id}
</Card>
);
}
return null;
})}
</PoseGroup>
<button onClick={this.next}>next</button>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<Example />, rootElement);
First you update your posed.div as the following.
const Card = posed.div({
preEnterPose: {
x: 50,
opacity: 0,
transition: { duration: 150 }
},
enter: {
x: 0,
opacity: 1,
delay: 300,
transition: {
x: { type: "spring", stiffness: 1000, damping: 15 },
default: { duration: 300 }
}
},
exit: {
x: -50,
opacity: 0,
transition: { duration: 150 }
}
});
Then you set your <PoseGroup>'s preEnterPose props to your key of the pose preEnterPose. And it should work. preEnterPose's default props is set to exit. Read it here
<PoseGroup preEnterPose="preEnterPose">
{items.map((id, idx) => {
if (idx === index) {
return (
<Card className="card" key={idx}>
{id}
</Card>
);
}
return null;
})}
</PoseGroup>
In react-grid-layout i am displaying name,image and a checkbox. The checkbox will be checked by default. The thing i want to do is onClicking the grid I want to change the checkbox status, here onCellClick() function is not working.
Here is the code
var Student= React.createClass({
getDefaultProps:function() {
return {
className: "layout",
rowHeight: 16,
cols: 16,
width:1200,
isDraggable: false,
isResizable:false,
verticalCompact:false
};
},
onCellClick:function(){
if(document.getElementById("stdattendance").checked==false){
document.getElementById("stdattendance").checked=true;
}else{
document.getElementById("stdattendance").checked=false;
}
},
generateDOM:function() {
console.log(this.props.student+_.range(this.props.items)+new Array(this.props.student));
var clickfun=this.click;
return _.map(this.props.student, function(item, i) {
var keyint=item.id;
idval.push(item.id);
var checkid=item.id+"-id";
var divid=item.id+"-id";
console.log("key"+keyint+idval);
console.log("x after : " + i * 2 % 16);
console.log("y after : " + Math.floor(i / 8) * 8);
return (<div key={i} id={divid} onClick={this.onCellClick} data-grid={{x: i * 2 % 16, y: Math.floor(i / 8) * 8, w: 2, h: 6,static: true }}><span className="group-class1"> {item.name}</span>
<div id="check">
<input type="checkbox" id="stdattendance" name="stdattendance" checked/>
</div>
<Image src="../images/No_image.png"/>
</div>);
});
},
render: function() {
// This prints the correct data
console.log(this.props.student);
return (
<div>
{(this.props.student.length)?
<div>
<ReactGridLayout
{...this.props}>
{this.generateDOM()}
</ReactGridLayout>
</div>:""
}
</div>
);
}
});
Reason, why all grid is getting selected, is you are using a single state variable for all rows, use an array, each entry will attached to each row, Try this:
var Student= React.createClass({
getInitialState: function() {
return {
checked: []
}
},
getDefaultProps:function() {
return {
className: "layout",
rowHeight: 16,
cols: 16,
width:1200,
isDraggable: false,
isResizable:false,
verticalCompact:false
};
},
onCellClick:function(index){
let checked = this.state.checked;
checked[index] = !checked[index];
this.setState({checked: checked});
}
generateDOM:function() {
console.log(this.props.student+_.range(this.props.items)+new Array(this.props.student));
var clickfun=this.click;
return _.map(this.props.student, function(item, i) {
var keyint=item.id;
idval.push(item.id);
var checkid=item.id+"-id";
var divid=item.id+"-id";
console.log("key"+keyint+idval);
console.log("x after : " + i * 2 % 16);
console.log("y after : " + Math.floor(i / 8) * 8);
return (<div key={i} id={divid} onClick={this.onCellClick(i)} data-grid={{x: i * 2 % 16, y: Math.floor(i / 8) * 8, w: 2, h: 6,static: true }}><span className="group-class1"> {item.name}</span>
<div id="check">
<input type="checkbox" ref="stdattendance" name="stdattendance" checked={!this.state.checked[i]}/>
</div>
<Image src="../images/No_image.png"/>
</div>);
}.bind(this));
},
render: function() {
// This prints the correct data
console.log(this.props.student);
return (
<div>
{(this.props.student.length)?
<div>
<ReactGridLayout {...this.props}>
{this.generateDOM()}
</ReactGridLayout>
</div>:""
}
</div>);
}
});
Instead of using the Javascript DOM you should do it the react way and make use of refs
<input type="checkbox" ref="stdattendance" name="stdattendance" checked/>
onCellClick:function(){
if(React.findDOMNode(this.refs.stdattendance).checked == false){
React.findDOMNode(this.refs.stdattendance).checked=true;
}else{
React.findDOMNode(this.refs.stdattendance).checked=false;
}
}
Although the above approach is enough but I would suggest you to make use a controlled checkbox component
var Student= React.createClass({
getInitialState: function() {
return {
checked: true
}
},
getDefaultProps:function() {
return {
className: "layout",
rowHeight: 16,
cols: 16,
width:1200,
isDraggable: false,
isResizable:false,
verticalCompact:false
};
},
onCellClick:function(divid){
var val;
console.log("val"+divid);
var inputElements = document.getElementsByClassName('checkboxgrp');
for(var i=0; i<inputElements.length; i++){
console.log(document.getElementsByClassName('checkboxgrp')[i].value);
if(document.getElementsByClassName('checkboxgrp')[i].value==divid){
if(document.getElementsByClassName('checkboxgrp')[i].checked==true){
document.getElementsByClassName('checkboxgrp')[i].checked=false;
}else{
document.getElementsByClassName('checkboxgrp')[i].checked=true
}}}
},
generateDOM:function() {
console.log(this.props.student+_.range(this.props.items)+new Array(this.props.student));
var clickfun=this.click;
return _.map(this.props.student, function(item, i) {
var keyint=item.id;
idval.push(item.id);
var checkid=item.id+"-id";
var divid=item.id+"-id";
console.log("key"+keyint+idval);
console.log("x after : " + i * 2 % 16);
console.log("y after : " + Math.floor(i / 8) * 8);
return (<div key={i} id={divid} onClick={this.onCellClick.bind(this, divid)} data-grid={{x: i * 2 % 16, y: Math.floor(i / 8) * 8, w: 2, h: 6,static: true }}><span className="group-class1"> {item.name}</span>
<div id="check">
<input type="checkbox" ref="stdattendance" name="stdattendance" className="checkboxgrp" value={item.user} checked={this.state.checked}/>
</div>
<Image src="../images/No_image.png"/>
</div>);
}.bind(this));
},
render: function() {
// This prints the correct data
console.log(this.props.student);
return (
<div>
{(this.props.student.length)?
<div>
<ReactGridLayout
{...this.props}>
{this.generateDOM()}
</ReactGridLayout>
</div>:""
}
</div>
);
}
});