Add Node in React Sort-able Tree Package - javascript

I'm starting to use React, and I want to add a react-tree component in my project. I am trying to a new node with the help of input and pass those data into the JSON array. But React Sortable tree not working.
I got the output in my console window. I have added the sample functionality here. would any please help me with this? Thanks for the response!!
I have One Parent Component named APP.js with two more child component with the names are Add.js & Drag.js
App Javascript file Sample code as below
import React, {
useState,
Component,
useEffect
} from "react";
import 'react-sortable-tree/style.css';
import TreeView from "./Drag&Drop";
// import Test from "./Testing";
import AddEdit from "./Add";
import './styles.css'
const Tree = (props) => {
const [info, setInfo] = useState('');
const data = (item) => {
let value = item.title;
setInfo(value);
}
console.log('data', info)
return ( <
div >
<
div className = "add-dt" >
<
div className = "left-side" >
<
AddEdit callback = {
data
}
/> <
/div> <
div className = "right-side" >
<
TreeView info = {
info
}
/> <
/div> <
/div> {
/* <Test /> */ }
<
/div>
);
}
export default Tree;
Two other component code are below followed with add.js & drag.js
ADD component js file
import React, {
useState
} from 'react';
import {
TextField
} from '#fluentui/react/lib/TextField';
import {
DefaultButton,
PrimaryButton,
Stack,
IStackTokens
} from '#fluentui/react';
import './styles.css'
const TextFieldBasicExample = (props) => {
const [newItem, setNewItem] = useState({
title: ''
});
console.log('onchange', newItem);
const handleChange = (e) => {
setNewItem({
[e.target.name]: e.target.value
});
}
const addData = (event) => {
console.log('onclick', newItem);
props.callback(newItem);
}
return ( <
Stack horizontal >
<
Stack className = "add-inp" >
<
TextField label = "Add Item"
placeholder = "enter text"
name = "title"
onChange = {
handleChange
}
/> <
span id = "error_name" > < /span> <
PrimaryButton text = "Add"
className = "add-btn"
onClick = {
addData
}
/>
<
/Stack> <
/Stack>
);
};
export default TextFieldBasicExample
Drag Component JS file
import React, {
useState,
Component,
useEffect
} from "react";
import 'react-sortable-tree/style.css';
import {
removeNodeAtPath
} from 'react-sortable-tree';
import SortableTree from 'react-sortable-tree';
import {
toggleExpandedForAll
} from 'react-sortable-tree';
import './styles.css'
const Treeview = (props, reset) => {
console.log('props', props)
const initTreeData = [{
title: 'Data_1',
children: [{
title: "Data_2"
}]
},
{
title: 'Data_1'
},
{
title: 'Data_2'
}
]
console.log('test', initTreeData.length)
var test = {
index: initTreeData.length + 1,
title: props.info
}
useEffect(() => {
_fetchGeneral();
}, [])
const [treeData, setTreeData] = useState(initTreeData);
console.log(treeData, "*******")
if (test.title != '') {
var m = treeData.push(test)
// setTreeData(m);
}
const _fetchGeneral = async () => {
setTreeData(initTreeData);
}
const updateTreeData = (e) => {
setTreeData(e);
}
// Expand and collapse code
const expand = (expanded) => {
setTreeData(toggleExpandedForAll({
treeData: treeData,
expanded,
}), );
}
const expandAll = () => {
expand(true);
}
const collapseAll = () => {
expand(false);
}
// Expand and collapse code end
// remove node
const removeNode = (rowInfo) => {
let {
node,
treeIndex,
path
} = rowInfo;
setTreeData(removeNodeAtPath({
treeData: treeData,
path: path, // You can use path from here
getNodeKey: ({
node: TreeNode,
treeIndex: number
}) => {
console.log(number, 'event');
return (number);
},
ignoreCollapsed: false,
}))
}
// remove node end
return ( <
div style = {
{
display: 'flex',
flexDirection: 'column',
height: '100vh'
}
} >
<
div style = {
{
flex: '0 0 auto',
padding: '0 15px'
}
} >
<
h3 > Full Node Drag Theme < /h3> <
button onClick = {
expandAll
} > Expand All < /button> <
button onClick = {
collapseAll
} > Collapse All < /button> &
nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp; & nbsp;
<
/div>
<
div style = {
{
flex: '1 0 50%',
padding: '0 0 0 15px'
}
} >
<
SortableTree className = "tree-dt"
id = "add_name"
treeData = {
treeData
}
onChange = {
updateTreeData
}
generateNodeProps = {
rowInfo => ({
buttons: [ <
div >
<
button label = 'Delete'
onClick = {
() => removeNode(rowInfo)
} > X < /button> <
/div>,
],
style: {
height: '50px',
}
})
}
canDrag = {
({
node
}) => !node.dragDisabled
}
/> <
/div> <
/div>
);
}
export default Treeview;
I have attached the output screen as well.

Related

Antd Select - how to reset the position of the dropdown when re-opening the select

Step to reproduce
1.Click and Open the Select
2.Scroll to the bottom
3.Close the Select by clicking outside
4.Reopen the Select
5.The Select is still on the position as Step 2
Expected Behaviour
5.The Select should be the same as the one in Step 1
Is it possible to do it?
App.tsx
import React from 'react';
import './index.css';
import { Select } from 'antd';
import type { SelectProps } from 'antd';
const options: SelectProps['options'] = [];
for (let i = 10; i < 36; i++) {
options.push({
value: i.toString(36) + i,
label: i.toString(36) + i,
});
}
const handleChange = (value: string) => {
console.log(`selected ${value}`);
};
const App: React.FC = () => (
<Select
mode="tags"
style={{ width: '100%' }}
onChange={handleChange}
tokenSeparators={[',']}
options={options}
/>
);
export default App;
Codesandbox
https://codesandbox.io/s/15lgd3?file=/demo.tsx
You can reset the scroll the position by passing a ref to Select Component & listen for dropdown visible change using onDropdownVisibleChange prop. When it's visible, you can move the scroll position to first element by passing index: 0 in scrollTo method.
import { MutableRefObject, useRef } from 'react';
import { Select } from 'antd';
import type { SelectProps } from 'antd';
import type { BaseSelectRef } from 'rc-select';
const options: SelectProps['options'] = [];
for (let i = 10; i < 36; i++) {
options.push({
value: i.toString(36) + i,
label: i.toString(36) + i
});
}
const handleChange = (value: string) => {
console.log(`selected ${value}`);
};
const App: React.FC = () => {
const ref = useRef() as MutableRefObject<BaseSelectRef>;
const onDropdownVisibleChange = (open: boolean) => {
if (open && ref.current) {
ref.current.scrollTo({ index: 0 });
}
};
return (
<Select
mode='tags'
style={{ width: '100%' }}
onChange={handleChange}
tokenSeparators={[',']}
options={options}
ref={ref}
onDropdownVisibleChange={onDropdownVisibleChange}
/>
);
};
export default App;

Trying to delete a key and values from an object, but when I try to delete it breaks some functionality

I am trying to create an add div button and a delete div button. When you select a certain div and click delete, I want to delete only that key from the object. The issue is when I delete and then try to create a new div, it doesn't create the new divs anymore...Not sure what i'm doing wrong or why it only kind of works.
import "./styles.css";
import {
useEffect,
useState
} from "react";
// The parent component
const App = () => {
const [textBoxDivs, setTextBoxDivs] = useState({});
const addNewTextBox = () => {
const numOfTextBoxDivs = Object.keys(textBoxDivs).length;
console.log(numOfTextBoxDivs, "num");
setTextBoxDivs({
...textBoxDivs,
[`div${numOfTextBoxDivs + 1}`]: {
isSelected: false,
innerText: "text"
}
});
};
const selectItem = (e) => {
const nextState = { ...textBoxDivs
};
Object.keys(nextState).forEach((k) => {
nextState[k].isSelected = false;
});
nextState[e.target.id].isSelected = true;
setTextBoxDivs(nextState);
};
const removeSelectedItem = () => {
const nextState = { ...textBoxDivs
};
if (Object.keys(textBoxDivs).length > 0) {
Object.keys(textBoxDivs).map((key) => {
if (textBoxDivs[key].isSelected) {
delete nextState[key];
return setTextBoxDivs(nextState);
}
return null;
});
}
};
return ( <
div >
<
button onClick = {
() => addNewTextBox()
} >
Click me to create a selectable div <
/button> <
button onClick = {
(e) => removeSelectedItem(e)
} >
Click me to delete a selectable div <
/button> {
Object.keys(textBoxDivs).length > 0 &&
Object.keys(textBoxDivs).map((key, index) => {
return ( <
div style = {
{
border: textBoxDivs[key].isSelected ?
"2px solid green" :
"unset"
}
}
onClick = {
(e) => selectItem(e)
}
key = {
index
}
id = {
key
} >
{
textBoxDivs[key].innerText
} <
/div>
);
})
} <
/div>
);
};
export default App;
<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>
The problem in your code in the function addNewTextBox, specifically in the line
[`div${numOfTextBoxDivs + 1}`]: {
Because it does not necessarily mean that your are adding a new line. In this case, you are assigning a value to (div + number), but sometimes that already exists. For example, of you change that line for a truly unique number, such as date, it works:
const addNewTextBox = () => {
const numOfTextBoxDivs = Object.keys(textBoxDivs).length;
console.log(numOfTextBoxDivs, "num");
setTextBoxDivs({
...textBoxDivs,
[`div${new Date().getTime()}`]: {
isSelected: false,
innerText: "text"
}
});
};
Update selectItem() then it works:
const selectItem = (e) => {
const nextState = { ...textBoxDivs, setTextBoxDivs }; // setTextBoxDivs was missing
Object.keys(nextState).forEach((k) => {
nextState[k].isSelected = false;
});
nextState[e.target.id].isSelected = true;
setTextBoxDivs(nextState);
};

React passes wrong parameter along function

I'm using a for loop to create some svg paths but have some trouble passing a parameter alongside the function. Everything added with the props uses the correct i value, except selectRegion(i). This gets 2 as value, which I think is the final value of i after finishing the loop. How do I pass the correct i value?
componentDidMount() {
var regions = []
for (var i = 0; i < this.state.regionNames.length; i++) {
var region = <Region id={i} border={this.state.regionBorders[i]} color={this.state.regionColors[i]} selectRegion={() => this.selectRegion(i)}/>;
regions.push(region);
}
this.setState({regions: regions});
}
// Select region.
selectRegion(id) {
alert(id);
this.setState({selRegion: id});
}
Region component
import React, { Component } from 'react'
export default class Region extends Component {
constructor (props) {
super(props);
this.state = {
id: props.id,
color: props.color,
border: props.border,
opacity: "0.3",
is_selected: false
}
}
mouseEnter = (is_enter) => {
if(is_enter) {
this.setState({opacity: "0.5"});
alert(this.state.id);
this.props.selectRegion();
} else if (!this.state.is_selected) {
this.setState({opacity: "0.3"});
}
}
mouseClick = () => {
this.setState({is_selected: !this.state.is_selected})
}
render() {
return (
<path d={this.state.border}
fill={this.state.color}
fill-opacity={this.state.opacity}
onClick={() => this.mouseClick()}
onMouseEnter={() => this.mouseEnter(true)}
onMouseLeave={() => this.mouseEnter(false)}/>
)
}
}
#Norse was correct I've fixed it by doing the following:
// Generate map regions.
componentDidMount() {
var regions = []
for (let i = 0; i < this.state.regionNames.length; i++) {
var region = <Region id={i} border={this.state.regionBorders[i]} color={this.state.regionColors[i]} selectRegion={() => this.selectRegion(i)}/>;
regions.push(region);
}
this.setState({regions: regions});
}

Deleting an item from a list in React updates the state, but component doesn't re-render?

When deleting from a list in React the item successfully is deleted from the tags state, but the Tag doesn't update? I fixed this by using { props.name } in the place of { name } in Tag.js but I don't understand why that change is necessary. Doesn't React re-render the Tags automatically?
Thanks!!
//TagManager.js component
import React, { useState } from 'react';
import Tag from './Tag.js';
export default function TagManager() {
let [tags, setTags] = useState(["one", "two", "three", "four"]);
function deleteTag(tagToDelete) {
let filteredTags = [];
for (let index = 0; index < tags.length; index = index + 1) {
if (tags[index] !== tagToDelete) {
filteredTags.push(tags[index]);
}
}
setTags(filteredTags);
}
function renderTags() {
let tagsToRender = [];
for (let index = 0; index < tags.length; index = index + 1) {
tagsToRender.push(<Tag key = { index } name = { tags[index] } handleClick = { deleteTag }/>);
}
return tagsToRender;
}
return (
<div className = "tag-manager">
{ renderTags() }
</div>
)
}
///////////////////////////////////
//Tag.js component
import React, { useState } from 'react';
export default function Tag(props) {
const [name, setName] = useState(props.name)
return (
<div className = "tag" id = {props.id} onClick = {() => props.handleClick(props.name)} >{ name }</div>
)
}

React and material-ui - Raised Button - how to achieve always disabling the clicked buttons?

This is my Buttons component code:
import React from 'react';
import RaisedButton from 'material-ui/RaisedButton';
const style = {
button: {
margin: 2,
padding: 0,
minWidth: 1,
},
};
const Buttons = props => {
const arrayFromInput = props.array;
const buttonsArray = [];
for (let i = 1; i <= arrayFromInput; i++) {
buttonsArray.push(i);
}
const handleButtonSelectZero = props.handleButtonSelectOne;
const allButtons = buttonsArray.map(el => (
<RaisedButton
key={el}
label={el}
style={style.button}
onClick={() => handleButtonSelectZero(el)}
/>
));
if (arrayFromInput > 0) {
return <div>{allButtons}</div>;
}
return <div />;
};
export default Buttons;
In material-ui docs is info that to achieve Raised Button disabled state we should add disabled={true} to it.
My coding problem/question:
What should I add to this component code to have particular Rasied Button get disabled after that particular button is clicked?
EDIT:
SOLUTION:
import React from 'react';
import RaisedButton from 'material-ui/RaisedButton';
const style = {
button: {
margin: 2,
padding: 0,
minWidth: 1,
},
};
const Buttons = props => {
const arrayFromInput = props.array;
const buttonsArray = [];
for (let i = 1; i <= arrayFromInput; i++) {
buttonsArray.push(i);
}
const handleButtonSelectZero = props.handleButtonSelectOne;
const allButtons = buttonsArray.map(el => (
<MyButton key={el} onClick={handleButtonSelectZero} el={el} />
));
if (arrayFromInput > 0) {
return <div>{allButtons}</div>;
}
return <div />;
};
class MyButton extends React.Component {
constructor() {
super();
this.state = { disabled: false };
}
handleClick = () => {
this.setState({ disabled: !this.state.disabled });
this.props.onClick(this.props.el);
};
render() {
return (
<RaisedButton
disabled={this.state.disabled}
key={this.props.el}
label={this.props.el}
style={style.button}
onClick={() => this.handleClick()}
/>
);
}
}
export default Buttons;
You need to use state somehow, i think i would do something like this:
import React from 'react';
import RaisedButton from 'material-ui/RaisedButton';
const style = {
button: {
margin: 2,
padding: 0,
minWidth: 1,
},
};
const Buttons = props => {
const arrayFromInput = props.array;
const buttonsArray = [];
for (let i = 1; i <= arrayFromInput; i++) {
buttonsArray.push(i);
}
const handleButtonSelectZero = props.handleButtonSelectOne;
const allButtons = buttonsArray.map(el => (
<MyButton onClick={handleButtonSelectZero} el={el} />
));
if (arrayFromInput > 0) {
return <div>{allButtons}</div>;
}
return <div />;
};
class MyButton extends React.Component {
constructor() {
super()
this.state = { disabled: false }
}
handleClick = () => {
this.setState({ disabled: !this.state.disabled })
this.props.onClick(this.props.el)
}
render() {
return (
<RaisedButton
disabled={this.state.disabled}
key={this.props.el}
label={this.props.el}
style={style.button}
onClick={() => handleButtonSelectZero(el)}
/>
)
}
}
export default Buttons;
I have not tested it, but hopefully it can guide you in the correct direction.
If you just need to disable it you can expand the
onClick={() => handleButtonSelectZero(el)}
like this onClick={() => {handleButtonSelectZero(el);this.disabled=true}};
EDIT: fixed missing {}

Categories

Resources