Recharts Line chart as imported functional component not rendering - reactjs

I have the following functional component that takes in some data and render a line chart. However depending on the type of data I would like to change the type of chart being used, i.e. (Line, Bar, etc).
As such I have a main component FieldCompareChart. This component determines what type of chart should be displayed based on the data graphs prop and determines if the yAxis should be on the left or right. It then renders the ResponsiveContainer and calls BuildYaxis as shown below.
I have the yAxis types is separate files as function components that return the type of chart being used.
Having it this way does not render the lines in the graph.
However if I pass the contents of dbVhChart directly into the return statement of the if clause of the BuildYAxis function, this works. I am trying to understand why importing doesn't but the other does.
import React from "react";
import {
LineChart,
XAxis,
CartesianGrid,
Legend,
ResponsiveContainer,
ReferenceArea,
YAxis,
Line,
} from "recharts";
import axisConfigs from "./yAxisConfig.json";
import DbVhChart from "./yAxisTypes/dbVh";
import DbVvChart from "./yAxisTypes/dbVv";
import NdviChart from "./yAxisTypes/ndvi";
function BuildYaxis(props) {
const { data, graphs, activeCrop, hideCrops } = props;
return Object.keys(data[0])
.filter((n) => ["date", "timestamp"].indexOf(n) === -1)
.map((c, index) => {
const sub = c.split("_").pop();
const idx = graphs.findIndex((val) => val === sub);
const chartProps = {
idx,
axisConfig: axisConfigs[sub],
activeCrop,
hideCrops,
dataKey: c,
};
if (sub === "dbVv") {
return <DbVvChart key={`dbVv-${index}`} {...chartProps} />;
}
return null;
});
}
const FieldCompareChart = (props) => {
const {
data,
activeCrop,
setActiveCrop,
hideCrops,
toggleCrop,
syncId,
showLegend,
left,
right,
refAreaLeft,
refAreaRight,
setRefAreaLeft,
setRefAreaRight,
zoom,
zoomOut,
graphs,
top,
bottom,
top2,
bottom2,
} = props;
if (data && data.length) {
return (
<div
className="highlight-bar-charts"
style={{ userSelect: "none", height: "calc(100vh - 100px)" }}
>
<button type="button" className="btn update" onClick={zoomOut}>
Zoom Out
</button>
<ResponsiveContainer width="100%" height="92%">
<LineChart
data={data}
onMouseLeave={() => setActiveCrop(null)}
onMouseDown={(e) => {
// this prevents an error from being thrown when the legend is clicked in the graphs
if (!e) return;
setRefAreaLeft(e);
}}
onMouseMove={(e) => {
if (!e) return;
refAreaLeft && setRefAreaRight(e);
}}
// eslint-disable-next-line react/jsx-no-bind
onMouseUp={(e) => {
// this prevents an error from being thrown when the legend is clicked in the graphs
if (!e) return;
if (!refAreaRight) {
return setRefAreaLeft("");
}
zoom();
}}
syncId={syncId}
width={500}
height={300}
margin={{
top: 5,
right: 30,
left: 20,
bottom: 5,
}}
>
<CartesianGrid strokeDasharray="3 3" />
<XAxis
domain={[left, right]}
allowDataOverflow
dataKey="date"
type="category"
tickFormatter={(a) => {
if (a === "auto") {
return a;
}
return new Date(a).toLocaleDateString();
}}
/>
{Object.keys(data[0])
.filter((n) => ["date", "timestamp"].indexOf(n) === -1)
.map((c, index) => {
const sub = c.split("_").pop();
const idx = graphs.findIndex((val) => val === sub);
return (
<YAxis
key={`yAxis-key-${index}`}
allowDataOverflow
domain={idx === 0 ? [bottom, top] : [bottom2, top2]}
type="number"
yAxisId={idx}
tickFormatter={(a) => parseFloat(a).toFixed(1)}
orientation={idx === 0 ? "left" : "right"}
/>
);
})}
{showLegend && (
<Legend
onClick={toggleCrop}
onMouseOver={(e) => setActiveCrop(e.dataKey)}
/>
)}
{BuildYaxis({ data, graphs, activeCrop, hideCrops })}
{refAreaLeft && refAreaRight ? (
<ReferenceArea
yAxisId="1"
x1={refAreaLeft}
x2={refAreaRight}
strokeOpacity={0.3}
/>
) : null}
</LineChart>
</ResponsiveContainer>
</div>
);
}
return null;
};
export default FieldCompareChart;
import React from "react";
import { Line } from "recharts";
import randomcolor from "randomcolor";
function DbVhChart(props) {
console.log(props);
const { idx, axisConfig, activeCrop, hideCrops, dataKey } = props;
return (
<Line
key={`comparison-chart-${dataKey}`}
yAxisId={idx}
type="natural"
animationDuration={300}
connectNulls
strokeDasharray={""}
dataKey={dataKey}
strokeWidth={activeCrop === null ? 1 : activeCrop === dataKey ? 3 : 1}
stroke={randomcolor({
luminosity: "bright",
seed: axisConfig.seed,
format: "rgba",
alpha: activeCrop === null || activeCrop === dataKey ? 1 : 0.2,
})}
hide={hideCrops.indexOf(dataKey) >= 0}
/>
);
}
export default DbVhChart;
Not working
...
function BuildYaxis(props) {
const { data, graphs, activeCrop, hideCrops } = props;
return Object.keys(data[0])
.filter((n) => ["date", "timestamp"].indexOf(n) === -1)
.map((c, index) => {
const sub = c.split("_").pop();
const idx = graphs.findIndex((val) => val === sub);
const chartProps = {
idx,
axisConfig: axisConfigs[sub],
activeCrop,
hideCrops,
dataKey: c,
};
console.log(`dbVv-${index}`);
if (sub === "dbVv") {
return <DbVvChart key={`dbVv-${index}`} {...chartProps} />;
}
return null;
});
}
...
Working:
...
function BuildYaxis(props) {
const { data, graphs, activeCrop, hideCrops } = props;
return Object.keys(data[0])
.filter((n) => ["date", "timestamp"].indexOf(n) === -1)
.map((c, index) => {
const sub = c.split("_").pop();
const idx = graphs.findIndex((val) => val === sub);
const chartProps = {
idx,
axisConfig: axisConfigs[sub],
activeCrop,
hideCrops,
dataKey: c,
};
if (sub === "dbVv") {
return (
<Line
key={`comparison-chart-${c}`}
yAxisId={idx}
type="natural"
animationDuration={300}
connectNulls
strokeDasharray={""}
dataKey={c}
strokeWidth={activeCrop === null ? 1 : activeCrop === c ? 3 : 1}
stroke={randomcolor({
luminosity: "bright",
seed: axisConfigs[sub].seed,
format: "rgba",
alpha: activeCrop === null || activeCrop === c ? 1 : 0.2,
})}
hide={hideCrops.indexOf(c) >= 0}
/>
);
}
return null;
});
}
...

Related

why dropdown in tables cell closes when the dropdowns page changes (kendoreact)

i have a grid with kendoreact that has a dropdown in its cell. i add a pager to the dropdown. but when i click on the pages, the dropdown close.
i have the same combobox in the form and it works good.
i tried a lot and worked on the pager and combobox props. but it was useless. perhaps its a behaviour from the grid. please help
import React, { useRef } from "react";
import { ComboBox } from "#progress/kendo-react-dropdowns";
import { filterBy } from "#progress/kendo-data-query";
import { Pager } from "#progress/kendo-react-data-tools";
import {
IntlProvider,
load,
LocalizationProvider,
loadMessages,
} from "#progress/kendo-react-intl";
import faMessages from "../../../../common/fa.json";
import persianJs from "persianjs";
// import Combobox from "../../../RPKCustomComponent/Combobox";
loadMessages(faMessages, "fa-IR");
const selectField = "selected";
const expandField = "expanded";
const dataItemKey = "value";
const textField = "label";
const subItemsField = "items";
const fields = {
selectField,
expandField,
dataItemKey,
subItemsField,
};
const initialType = "numeric";
const initialPageState = {
skip: 0,
take: 10,
total: 0,
buttonCount: 5,
type: initialType,
info: true,
// pageSizes: true,
previousNext: true,
responsive: true,
};
export default class ComboBoxCell extends React.Component {
state = {
data: [],
pageState: initialPageState,
take: 10,
skip: 0,
mammad: false,
};
handlepageChange = async (event) => {
// event.syntheticEvent.isDefaultPrevented();
// await this.setState({ skip: event.skip, take: event.take, mammad: true });
await this.props.getCombo({
id: this.props.dataItem.Id,
pageIndex: event.skip/10,
pageSize: 10,
search: "",
});
this.setState({mammad:true})
};
handleChange = (e) => {
this.props.onChange({
dataItem: this.props.dataItem,
field: this.props.field,
syntheticEvent: e.syntheticEvent,
value: e.target.value,
});
this.setState({mammad:true})
};
handleOnClick = async (e) => {
setTimeout(async () => {
if (!this.props.data && this.props.getCombo) {
await this.props.getCombo(true, this.state.skip / 10, 10, "");
}
}, 0);
this.setState({mammad:true})
};
componentDidMount() {
let dropdowntree = document.getElementById(`${this.props.id}`);
if (dropdowntree) {
dropdowntree.setAttribute("name", this.props.field);
}
this.textInput = React.createRef();
if (this.props.data?.List) {
let badData = this.props.data?.List.find((item) => {
if (item.value < 0 || item.label == null || item.label == undefined) {
return item;
}
});
if (badData) {
this.props.data.List.map((item) => {
if (item.label == null || item.label == undefined) {
item.label = "";
}
});
console.log("دیتای کمبو از سمت بک مشکل داره");
}
}
if (this.props.data?.List) {
let badData = this.props.data.List.find((item) => {
if (item.value < 0 || item.label == null || item.label == undefined) {
return item;
}
});
if (badData) {
this.props.data.List.map((item) => {
if (
item.label == null ||
item.label == undefined ||
item.label == false
) {
item.label = " ";
}
});
console.log("دیتای کمبو از سمت بک مشکل داره");
}
this.props.data.List.length > 0 &&
this.props.data.List.map(
(item) =>
(item.label =
item.label.length > 0 &&
persianJs(item.label)?.arabicChar()?._str)
);
}
this.setState({
data: this.props.data?.List,
pageState: {
...this.state.pageState,
total: this.props.data?.RecordCount ?? 0,
},
});
}
filterChange = (event) => {
this.setState({
data: this.filterData(event.filter),
});
};
filterData(filter) {
if (this.props.data?.List) {
const data = this.props.data?.List?.slice();
return filterBy(data, filter);
}
}
render() {
// let test=document.getElementsByClassName("comboFooterPageNumber")[0]
// console.log(test);
// document.getElementsByClassName("comboFooterPageNumber")[0]
// .addEventListener("click",(e)=>{
// console.log(e);
// });
// document
// .getElementsByClassName(this.props?.realurl)[0]
// .addEventListener("dblclick", this.AddInCell);
// console.log(this.state.skip);
console.log(this.state.mammad);
const { dataItem, field } = this.props;
const dataValue = dataItem[field] === null ? "" : dataItem[field];
const dataLableValue =
dataItem[field] === null ? "" : dataItem[field]?.label;
let dropValue = this.props.data?.List
? this.props.data?.List.find((c) => c.value == dataValue)
: null;
let dropLabel = this.props.data?.List
? this.props.data?.List.find((c) => c.value == dataValue)?.label
: null;
const listNoDataRender = (element) => {
const noData = (
<h4
style={{
fontSize: "1em",
}}
>
<span
className="k-icon k-i-warning"
style={{
fontSize: "1.5em",
}}
/>
<br />
<br />
موردی یافت نشد!
</h4>
);
return React.cloneElement(element, { ...element.props }, noData);
};
return (
<td className="cell-input">
{dataItem.inEdit && this.props.editable ? (
<ComboBox
{...this.props}
data={this.state.data ?? []}
onChange={this.handleChange}
textField={textField}
dataItemKey={dataItemKey}
filterable={true}
opened={this.state.mammad}
closed={!this.state.mammad}
onFilterChange={this.filterChange}
required={this.props.required}
onOpen={this.handleOnClick}
value={dropValue ?? dataValue}
listNoDataRender={listNoDataRender}
ariaLabelledBy={this.props.ariaLabelledBy ?? ""}
name={this.props.field}
footer={
// (!this.props.clientSide || this.props.allowNewForm) && (
<div>
{/* {this.props.allowNewForm && (
<>
<span className="comboFooter"></span>
<p onClick={others.setshowmodal}>افزودن گزینه جدید</p>
</>
)} */}
{/* {!this.props.clientSide && ( */}
<div className="comboFooterPageNumber">
<LocalizationProvider language="fa">
<Pager
skip={this.state.skip}
take={this.state.take}
total={this.state.pageState.total}
buttonCount={this.state.pageState.buttonCount}
info={this.state.pageState.info}
type={this.state.pageState.type}
previousNext={this.state.pageState.previousNext}
onPageChange={this.handlepageChange}
ref={this.textInput}
/>
</LocalizationProvider>
</div>
{/* )} */}
</div>
// )
}
/>
) : (
dropLabel ?? dataLableValue
)}
</td>
);
}
}

Using reactPrime library in DataView components how update dynamic values (react hook)?

how I can update price value when update quantity value automatically ??
page design
interface ui
print values on the console:
print values on the console:
This sentence needs to be modified
{quantity[initQ] == 1 ? data.price : initP[initQ]}
i use setState to save multiple values
export default function Contaner({ setPressed, getPressed }) {
const [products, setProducts] = useState([]);
const [layout, setLayout] = useState('list');
let initQ = 1;
const [initP,setInitP] = useState({ [initQ]: 1 }) ;
const [quantity, setQuantity] = useState({ [initQ]: 1 });
function checkQuantity(e, data) {
if (e.value <= data.quantity) {
initQ = data.name;
setQuantity({ ...quantity, [data.name]: e.value});
setInitP( { ...quantity, [data.name]: data.price * e.value});
console.log(initP );
setCart(current => [...current, data.name]);
}
else {
showError();
}
}
const renderListItem = (data) => {
return (
<div style={{ display: "flex" }}>
<button className="button_color" onClick={() => removeItem(data)}>
<i className="pi pi-trash"></i>
</button>
<h6>{quantity[initQ] == 1 ? data.price : initP[initQ] }</h6>
<InputNumber id="stacked" showButtons min={1} value={quantity[initQ]}
onValueChange={(e) => checkQuantity(e, data)} />
<InputText disabled={true} value={"₪ " + data.price} />
<h6>{data.name}</h6>
</div>
);
}
const itemTemplate = (product, layout) => {
if (!product) {
return <></>;
}
if (layout === 'list') {
return renderListItem(product);
}
}
return(
<DataView value={products} layout={layout} itemTemplate={itemTemplate} rows={1} />
);
}

React dnd broad not working on the typescript

I tried to using this react dnd on the react typescript. sample not working on the type script project , any one know how to do that correctly on the react typescript
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';
// fake data generator
const getItems = (count, offset = 0) =>
Array.from({ length: count }, (v, k) => k).map(k => ({
id: `item-${k + offset}`,
content: `Item: ${k + offset}, Random value: ${Math.round(Math.random() * 100)}`,
color: Math.random () > 0.66 ? 'pink': Math.random() > 0.5 ? 'lightgreen' : 'beige'
}))
// a little function to help us with reordering the result
const reorder = (list, startIndex, endIndex) => {
const result = Array.from(list)
const [removed] = result.splice(startIndex, 1)
result.splice(endIndex, 0, removed)
return result
}
/**
* Moves an item from one list to another list.
*/
const move = (source, destination, droppableSource, droppableDestination) => {
const sourceClone = Array.from(source)
const destClone = Array.from(destination)
const [removed] = sourceClone.splice(droppableSource.index, 1)
destClone.splice(droppableDestination.index, 0, removed)
const result = {}
result[droppableSource.droppableId] = sourceClone
result[droppableDestination.droppableId] = destClone
return result
}
const grid = 4
const getItemStyle = (isDragging, draggableStyle) => ({
// some basic styles to make the items look a bit nicer
userSelect: 'none',
padding: grid * 2,
margin: `0 0 ${grid}px 0`,
// change background colour if dragging
background: isDragging ? 'lightgreen' : 'lightgrey',
// styles we need to apply on draggables
...draggableStyle
})
const getListStyle = isDraggingOver => ({
background: isDraggingOver ? 'lightblue' : '#eee',
padding: grid,
margin: '3px',
width: 250
})
class App extends Component {
state = {
list1: getItems(5,1),
list2: getItems(4, 6),
list3: getItems(6, 10)
}
/**
* A semi-generic way to handle multiple lists. Matches
* the IDs of the droppable container to the names of the
* source arrays stored in the state.
*/
droppableIds = {
droppable1: 'list1',
droppable2: 'list2',
droppable3: 'list3'
}
getList = id => this.state[this.droppableIds[id]]
onDragEnd = result => {
const { source, destination } = result
// dropped outside the list
if (!destination) { return }
if (source.droppableId === destination.droppableId) {
const items = reorder(
this.getList(source.droppableId),
source.index,
destination.index
)
let copiedState = Object.assign({}, this.state)
if (source.droppableId === 'droppable1') {
copiedState.list1 = items
} else if (source.droppableId === 'droppable2') {
copiedState.list2 = items
} else if (source.droppableId === 'droppable3') {
copiedState.list3 = items
}
this.setState(copiedState)
} else {
const result = move(
this.getList(source.droppableId),
this.getList(destination.droppableId),
source,
destination
)
console.warn('result', result)
this.setState({
list1: result.droppable1 ? result.droppable1 : this.state.list1,
list2: result.droppable2 ? result.droppable2 : this.state.list2,
list3: result.droppable3 ? result.droppable3 : this.state.list3
})
}
}
// Normally you would want to split things out into separate components.
// But in this example everything is just done in one place for simplicity
render() {
const lists = [
{
droppableId: 'droppable1',
listId: 'list1',
title: 'List A'
},
{
droppableId: 'droppable2',
listId: 'list2',
title: 'List B'
},
{
droppableId: 'droppable3',
listId: 'list3',
title: 'List C'
},
]
return (
<div style={{ display: 'flex' }}>
<DragDropContext onDragEnd={this.onDragEnd}>
{lists.map((list, listIndex) =>
<Droppable key={'list-droppable-' + listIndex} droppableId={list.droppableId}>
{(provided, snapshot) => (
<div
ref={provided.innerRef}
style={getListStyle(snapshot.isDraggingOver)}>
<h4>
{list.title}
</h4>
{this.state[list.listId] && this.state[list.listId].map((item, index) => (
<Draggable
key={item.id}
draggableId={item.id}
index={index}>
{(provided, snapshot) => (
<div
ref={provided.innerRef}
{ ...provided.draggableProps }
{ ...provided.dragHandleProps }
style={getItemStyle(
snapshot.isDragging,
provided.draggableProps.style
)}>
<div style={{ background: item.color }}>
{item.content}
</div>
</div>
)}
</Draggable>
))}
{provided.placeholder}
</div>
)}
</Droppable>
)}
</DragDropContext>
</div>
)
}
}
// Put the things into the DOM!
ReactDOM.render(<App />, document.getElementById('root'));
Try something like this.
import React, { Component } from "react";
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
// fake data generator
const getItems = (count: number, offset: number): object =>
Array.from({ length: count }, (v, k): number => k).map(
(k: number): {} => ({
id: `item-${k + offset}`,
content: `Item: ${k + offset}, Random value: ${Math.round(
Math.random() * 100
)}`,
color:
Math.random() > 0.66
? "pink"
: Math.random() > 0.5
? "lightgreen"
: "beige"
})
);
// a little function to help us with reordering the result
const reorder = (list: [], startIndex: number, endIndex: number): object => {
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
return result;
};
/**
* Moves an item from one list to another list.
*/
const move = (
source: any,
destination: any,
droppableSource: any,
droppableDestination: any
): {} => {
const sourceClone = Array.from(source);
const destClone = Array.from(destination);
const [removed] = sourceClone.splice(droppableSource.index, 1);
destClone.splice(droppableDestination.index, 0, removed);
let result: any = {};
result[droppableSource.droppableId] = sourceClone;
result[droppableDestination.droppableId] = destClone;
return result;
};
const grid = 4;
const getItemStyle = (isDragging: boolean, draggableStyle: any): object => ({
// some basic styles to make the items look a bit nicer
userSelect: "none",
padding: grid * 2,
margin: `0 0 ${grid}px 0`,
// change background colour if dragging
background: isDragging ? "lightgreen" : "lightgrey",
// styles we need to apply on draggables
...draggableStyle
});
const getListStyle = (isDraggingOver: boolean): object => ({
background: isDraggingOver ? "lightblue" : "#eee",
padding: grid,
margin: "3px",
width: 250
});
interface State {
list1: object;
list2: object;
list3: object;
}
class App extends Component<State> {
state: State = {
list1: getItems(5, 1),
list2: getItems(4, 6),
list3: getItems(6, 10)
};
/**
* A semi-generic way to handle multiple lists. Matches
* the IDs of the droppable container to the names of the
* source arrays stored in the state.
*/
droppableIds = {
droppable1: "list1",
droppable2: "list2",
droppable3: "list3"
};
getList = (id: string): any => this.state[this.droppableIds[id]];
onDragEnd = (result: any) => {
const { source, destination } = result;
// dropped outside the list
if (!destination) {
return;
}
if (source.droppableId === destination.droppableId) {
const items: object = reorder(
this.getList(source.droppableId),
source.index,
destination.index
);
let copiedState: any = Object.assign({}, this.state);
if (source.droppableId === "droppable1") {
copiedState.list1 = items;
} else if (source.droppableId === "droppable2") {
copiedState.list2 = items;
} else if (source.droppableId === "droppable3") {
copiedState.list3 = items;
}
this.setState(copiedState);
} else {
const result: any = move(
this.getList(source.droppableId),
this.getList(destination.droppableId),
source,
destination
);
this.setState({
list1: result.droppable1 ? result.droppable1 : this.state.list1,
list2: result.droppable2 ? result.droppable2 : this.state.list2,
list3: result.droppable3 ? result.droppable3 : this.state.list3
});
}
};
render() {
const lists = [
{
droppableId: "droppable1",
listId: "list1",
title: "List A"
},
{
droppableId: "droppable2",
listId: "list2",
title: "List B"
},
{
droppableId: "droppable3",
listId: "list3",
title: "List C"
}
];
return (
<div style={{ display: "flex" }}>
<DragDropContext onDragEnd={this.onDragEnd}>
{lists.map((list, listIndex) => (
<Droppable
key={"list-droppable-" + listIndex}
droppableId={list.droppableId}
>
{(provided: any, snapshot: any) => (
<div
ref={provided.innerRef}
style={getListStyle(snapshot.isDraggingOver)}
>
<h4>{list.title}</h4>
{this.state[list.listId] &&
this.state[list.listId].map((item: any, index: number) => (
<Draggable
key={item.id}
draggableId={item.id}
index={index}
>
{(provided: any, snapshot: any) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={getItemStyle(
snapshot.isDragging,
provided.draggableProps.style
)}
>
<div style={{ background: item.color }}>
{item.content}
</div>
</div>
)}
</Draggable>
))}
{provided.placeholder}
</div>
)}
</Droppable>
))}
</DragDropContext>
</div>
);
}
}
export default App;
And here is a working example codesandox

React parsing function inside component as React Element

I have a React component which is trying to render another component that has function inside it as a child. When I try to render that component it returns an [Object]. I am trying to find another way to render that child component.
Right now, I tried to render it with React.createElement(), yet it also returned an object. I am using react-beautiful-dnd library to use Drag and Drop feature. This library has Droppable component and it takes a function inside which has two parameters, provided, snapshot.
Since it takes a function, when I try to render Droppable component, it returns an object instead of react element.
DroppableContent.js
const DroppableContent = ({ droppedBlank, label, id }) => (
<Droppable droppableId={id || _.uniqueId('droppable_')}>
{(provided, snapshot) => (
<span ref={provided.innerRef} style={{ display: 'inline' }} {...provided.droppableProps}>
{/* blank placeholder */}
<span className={droppedBlank ? styles.dropped : styles.placeholder}
style={{ backgroundColor: !droppedBlank && snapshot.isDraggingOver ? '#88d2ee' : '#fff' }}
>
{droppedBlank ? <BlankItem label={label} index={id} /> : null}
</span>
</span>
)}
</Droppable>
);
DragAndDrop.js where I call QuestionPreview component.
import React from 'react';
import PropTypes from 'prop-types';
import { withTranslation } from 'react-i18next';
import { DragDropContext, Droppable } from 'react-beautiful-dnd';
import _ from 'lodash';
import * as questionStyles from '../Questions.less';
import BlankList from './BlankList';
import BlankItem from './BlankItem';
import QuestionPreview from './QuestionPreview';
const DragAndDrop = ({
question, onAnswer, answer, hideTitle, className, t, readOnly,
}) => {
const handleDragEnd = (result) => {
const { destination, source, draggableId } = result;
if (!destination) {
return;
}
if (destination.droppableId === source.droppableId && destination.index === source.index) {
return;
}
const destinationId = destination.droppableId;
const sourceId = draggableId;
const blank = {
textIndex: destinationId,
id: sourceId,
// answer: _.find(questionBlanks, b => b.id === sourceId).answer,
};
let updatedBlanks;
if (destinationId === 'answerBlanks') {
updatedBlanks = _.filter(answer.blanks, item => item.id !== blank.id);
} else {
updatedBlanks = _.filter(answer.blanks, item => item.textIndex !== blank.textIndex);
updatedBlanks.push(blank);
}
onAnswer(question, { blanks: updatedBlanks });
};
const blankLabels = currentLabels => _.filter(currentLabels, l => !_.includes(_.map(answer.blanks, ab => ab.id), l.id)).map((label, index) => (
<BlankItem key={label.id} label={label} index={index} />
));
const blankItems = currentBlanks => _.map(currentBlanks, (currentBlank, index) => (
<BlankItem key={currentBlank.id} label={currentBlank} index={index} readOnly />
));
const { text } = question;
const shuffledLabels = question.labels && _.shuffle(question.labels);
// filtering answers from blank items so that whenever we drag an item to a blank,
// answer will be removed.
const filteredLabels = shuffledLabels && blankLabels(shuffledLabels);
const filteredBlanks = blankItems(question.blanks);
return (
<DragDropContext onDragEnd={handleDragEnd}>
<div>
<p style={{ fontWeight: 600 }}>
{t('defaultDndText', { numberOfBlanks: question.blanks.length })}
</p>
<Droppable droppableId="answerBlanks">
{provided => (
<div>
<BlankList innerRef={provided.innerRef} {...provided.droppableProps}>
{readOnly ? filteredBlanks : filteredLabels}
</BlankList>
</div>
)}
</Droppable>
{!hideTitle && (
<QuestionPreview blanks={_.filter(question.blanks, blank => blank.textIndex < 100)}
labels={question.labels}
selectedBlanks={answer.blanks}
text={text}
className={[questionStyles.title, className].join(' ')}
/>
)}
</div>
</DragDropContext>
);
};
DragAndDrop.propTypes = {
question: PropTypes.shape({
text: PropTypes.string,
}).isRequired,
answer: PropTypes.shape({
blanks: PropTypes.arrayOf(PropTypes.shape({})),
}),
readOnly: PropTypes.bool,
disabled: PropTypes.bool,
hideTitle: PropTypes.bool,
onAnswer: PropTypes.func,
className: PropTypes.string,
};
DragAndDrop.defaultProps = {
onAnswer: () => {},
disabled: false,
hideTitle: false,
className: '',
answer: { blanks: [] },
readOnly: false,
};
export default withTranslation('question')(DragAndDrop);
QuestionPreview.js where I try to render DroppableContent component.
const QuestionPreview = ({
text, labels, selectedBlanks, readOnly,
}) => {
const readOnlyContent = (id) => {
const droppedBlank = selectedBlanks && _.find(selectedBlanks, blank => blank.textIndex === id);
const label = droppedBlank && _.find(labels, l => l.id === droppedBlank.id);
return (
<span className={droppedBlank ? styles.dropped : styles.placeholder}>
{droppedBlank && <BlankItem label={label} readOnly />}
</span>
);
};
const splittedText = splitTextWithBlanks(text);
const blankIndices = getBlankIndices(text);
const getContentId = index => blankIndices[index];
const tempArray = [];
const html = () => {
_.map(splittedText, (element, index) => {
const contentId = getContentId(index);
const droppedBlank = selectedBlanks && _.find(selectedBlanks, blank => blank.textIndex === contentId);
const label = droppedBlank && _.find(labels, l => l.id === droppedBlank.id);
const blankContent = readOnly ? readOnlyContent(contentId) : <DroppableContent id={contentId} droppedBlank={droppedBlank} label={label} />;
const htmlContent = <span dangerouslySetInnerHTML={{ __html: toHTML(element) }} />;
tempArray.push(htmlContent);
if (index !== splittedText.length - 1) {
tempArray[index] = tempArray[index] + blankContent;
}
});
return tempArray;
};
const createdElement = React.createElement('div', null, html());
return createdElement;
};
This does not return any error but what I want to achieve is that combining htmlContent variable with blankContent. When I do that, it does render blankContent as an Object. In the end, I just want to find a way to parse Droppable component.
You might have error in the following line
const blankContent = readOnly ? readOnlyContent : <DroppableContent id={contentId} droppedBlank={droppedBlank} label={label} />;
You are passing reference of readOnlyContent, May be you want to call
readOnlyContent (contentId) .BTW your code is complex and hard to maintain/read. try to refactor it
Edit 1 Try this QuestionPreview.js
const QuestionPreview = ({
text, labels, selectedBlanks, readOnly,
}) => {
const readOnlyContent = (id) => {
const droppedBlank = selectedBlanks && _.find(selectedBlanks, blank =>
blank.textIndex === id);
const label = droppedBlank && _.find(labels, l => l.id ===
droppedBlank.id);
return (
<span className={droppedBlank ? styles.dropped : styles.placeholder}>
{droppedBlank && <BlankItem label={label} readOnly />}
</span>
);
};
const splittedText = splitTextWithBlanks(text);
const blankIndices = getBlankIndices(text);
const getContentId = index => blankIndices[index];
const tempArray = [];
const html = () => {
return _.map(splittedText, (element, index) => {
const contentId = getContentId(index);
const droppedBlank = selectedBlanks && _.find(selectedBlanks, blank =>
blank.textIndex === contentId);
const label = droppedBlank && _.find(labels, l => l.id ===
droppedBlank.id);
const blankContent = readOnly ? readOnlyContent(contentId) :
<DroppableContent id={contentId} droppedBlank={droppedBlank} label=
{label}
/>;
let htmlContent = <span dangerouslySetInnerHTML={{ __html:
toHTML(element) }} />;
if (index !== splittedText.length - 1) {
return (
<Fragment>
{htmlContent}
{blankContent}
</Fragment>
)
}
return htmlContent
});
};
return (
{html()}
)
};

React Leaflet: setting a polygon's style dynamically

How do I change a polygon's color programatically?
The solution I was using for GeoJSONs here doesn't work. Though when I inspect the element, I can see
style:{color: "red"}
nonetheless, the map shows a blue polygon.
Here's the relevant part of my component:
render() {
const {
id,
name,
geoJSON,
zoomLevel,
selectedPlot,
plotBeingEdited
} = this.props;
const markerPosition = position(geoJSON);
let style = () => {
return {
color: 'blue'
};
};
if (selectedPlot === id) {
style = () => {
return {
color: 'red'
};
};
}
if (zoomLevel > 14 && plotBeingEdited === id) {
return <PlotPolygon id={id} geoJSON={geoJSON} />;
} else if (zoomLevel > 14) {
return (
<Polygon
ref="plot"
style={style()}
id={id}
positions={[positions(this.props)]}
onClick={() => {
this.props.selectPlot(id);
}}
/>
);
}
Pass on color prop as an object:
<Polygon
...
color={selectedPlot === id ? 'red' : 'blue'}
/>

Resources