Adding a Modal Instead of "prompt" in react app - reactjs

Adding a Modal Instead of "prompt" in react app
Hi Iam creating a menu builder with react-sortable-tree. I want to add a Modal when clicked on Add or Edit Task. prompt is working fine here but i want Modal to be opened. I have created state and finctions for modal but unable to render on UI when clicked. anybody help
import React, { Component } from "react";
import "bootstrap/dist/css/bootstrap.css";
import "react-sortable-tree/style.css";
import { Button } from "react-bootstrap";
import "./MenuBuilder.css";
import { Modal } from "react-responsive-modal";
import "react-responsive-modal/styles.css";
import treeData from "./MenuBuilderData";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faTrashAlt, faPlus, faPen } from "#fortawesome/free-solid-svg-icons";
import SortableTree, {
toggleExpandedForAll,
getNodeAtPath,
addNodeUnderParent,
removeNode,
changeNodeAtPath,
} from "react-sortable-tree";
const maxDepth = 5;
export default class MenuBuilder extends Component {
constructor(props) {
super(props);
this.state = {
treeData: treeData,
searchString: "",
searchFocusIndex: 0,
searchFoundCount: null,
openModal: false,
};
}
onOpenModal = (e) => {
e.preventDefault();
this.setState({ openModal: true });
};
onCloseModal = () => {
this.setState({ openModal: false });
};
handleTreeOnChange = (treeData) => {
this.setState({ treeData });
};
selectPrevMatch = () => {
const { searchFocusIndex, searchFoundCount } = this.state;
this.setState({
searchFocusIndex:
searchFocusIndex !== null
? (searchFoundCount + searchFocusIndex - 1) % searchFoundCount
: searchFoundCount - 1,
});
};
selectNextMatch = () => {
const { searchFocusIndex, searchFoundCount } = this.state;
this.setState({
searchFocusIndex:
searchFocusIndex !== null
? (searchFocusIndex + 1) % searchFoundCount
: 0,
});
};
toggleNodeExpansion = (expanded) => {
this.setState((prevState) => ({
treeData: toggleExpandedForAll({
treeData: prevState.treeData,
expanded,
}),
}));
};
getNodeKey = ({ treeIndex: number }) => {
if (number === -1) {
number = null;
}
return number;
};
handleSave = () => {
console.log(JSON.stringify(this.state.treeData));
};
editTask = (path) => {
let editedNode = getNodeAtPath({
treeData: this.state.treeData,
path: path,
getNodeKey: ({ treeIndex }) => treeIndex,
ignoreCollapsed: true,
});
let newTaskTitle = prompt("Task new name:", editedNode.node.title);
if (newTaskTitle === null) return false;
editedNode.node.title = newTaskTitle;
let newTree = changeNodeAtPath({
treeData: this.state.treeData,
path: path,
newNode: editedNode.node,
getNodeKey: ({ treeIndex }) => treeIndex,
ignoreCollapsed: true,
});
// console.log(newTree);
this.setState({ treeData: newTree });
};
addTask = (path) => {
let parentNode = getNodeAtPath({
treeData: this.state.treeData,
path: path,
getNodeKey: ({ treeIndex }) => treeIndex,
ignoreCollapsed: true,
});
let newTaskTitle = parentNode.node.children ? prompt("Task name:", "default") && prompt("form ID:", "default") : prompt("Task name:", "default") // let newFormId = prompt("Form Id:", "");
if (newTaskTitle === null) return false;
let NEW_NODE = { title: newTaskTitle };
// let NEW_ID = { id: newFormId };
let parentKey = this.getNodeKey(parentNode);
let newTree = addNodeUnderParent({
treeData: this.state.treeData,
newNode: NEW_NODE,
// newId: NEW_ID,
expandParent: true,
parentKey: parentKey,
getNodeKey: ({ treeIndex }) => treeIndex,
});
this.setState({ treeData: newTree.treeData });
};
removeTask = (path) => {
let newTree = removeNode({
treeData: this.state.treeData,
path: path,
ignoreCollapsed: true,
getNodeKey: ({ treeIndex }) => treeIndex,
});
this.setState({ treeData: newTree.treeData });
};
renderTasks = () => {
const { treeData, searchString, searchFocusIndex } = this.state;
return (
<>
<SortableTree
treeData={treeData}
onChange={this.handleTreeOnChange}
maxDepth={maxDepth}
searchQuery={searchString}
searchFocusOffset={searchFocusIndex}
canDrag={({ node }) => !node.noDragging}
canDrop={({ nextParent }) => !nextParent || !nextParent.noChildren}
searchFinishCallback={(matches) =>
this.setState({
searchFoundCount: matches.length,
searchFocusIndex:
matches.length > 0 ? searchFocusIndex % matches.length : 0,
})
}
isVirtualized={true}
generateNodeProps={(taskInfo) => ({
buttons: [
<Button
variant="link"
onClick={() => this.editTask(taskInfo.path)}
>
<FontAwesomeIcon icon={faPen} color="#28a745" />
</Button>,
<Button
variant="link"
onClick={() => this.addTask(taskInfo.path)}
>
<FontAwesomeIcon icon={faPlus} color="#007bff" />
</Button>,
<Button
variant="link"
onClick={() => this.removeTask(taskInfo.path)}
>
<FontAwesomeIcon icon={faTrashAlt} color="#dc3545" />
</Button>,
],
})}
/>
<Button style={{ width: "100px" }} onClick={this.handleSave}>
save
</Button>
</>
);
};
render() {
return (
<>
<div className="wrapper">{this.renderTasks()}</div>
{/* <div>
<button onClick={this.onOpenModal}>Click Me</button>
<Modal open={this.state.openModal} onClose={this.onCloseModal}>
<input type="text" />
</Modal>
</div> */}
</>
);
}
}
treeData.js
const treeData = [
{
expanded: true,
title: "Contact HR",
children: [
{
expanded: true,
title: "Build relationships"
},
{
expanded: true,
title: "Take a test assignment"
}
]
},
{
expanded: true,
title: "Complete a test assignment",
children: [
{
expanded: true,
title: "Send link to this doc through LinkedIn"
}
]
},
{
expanded: true,
title: "Discuss Proposal details",
children: [
{
expanded: true,
title: "Prepare list of questions."
},
{
expanded: true,
title: "Other coming soon..."
}
]
},
{
expanded: true,
title: "Make an appointment for a technical interview",
children: [
{
expanded: true,
title: "Discuss details of the technical interview"
},
{
expanded: true,
title: "Prepare to Technival Interview"
}
]
},
{
expanded: true,
title: "Accept or Decline Offer"
}
];
export default treeData;

Related

calling setState from onClick JavaScript function not working

I am trying to create a button that will make visible a form to edit any contact on my list. However, when I press the button, nothing happens.
I have the initial state set to
this.state = {
contacts: [],
showEditWindow: false,
EditContactId: ''
};
I added a function:
editContact = (id) => {
this.setState({
showEditWindow: true, EditContactId: {id}
});
};
and a column:
{
title: "",
key: "action",
render: (record) => (
<button onClick={() => this.editContact(record.id)}
>
Edit
</button>
)
},
I imported EditContactModal and call it as
<EditContactModal reloadContacts={this.reloadContacts}
showEditWindow={this.state.showEditWindow}
EditContactId={this.state.EditContactId}/>
If I manually set this.state to showEditWindow:true, the window appears; however, either this.editContact(id) is not being called or it is not changing the state.
Calling this.deleteContact(id) works fine, as does setState in loadContacts() and reloadContacts()
What I am doing wrong?
Below are the full components.
Contacts.jsx
import { Table, message, Popconfirm } from "antd";
import React from "react";
import AddContactModal from "./AddContactModal";
import EditContactModal from "./EditContactModal";
class Contacts extends React.Component {
constructor(props) {
super(props);
this.state = {
contacts: [],
showEditWindow: false,
EditContactId: ''
};
this.editContact = this.editContact.bind(this);
};
columns = [
{
title: "First Name",
dataIndex: "firstname",
key: "firstname"
},
{
title: "Last Name",
dataIndex: "lastname",
key: "lastname"
},{
title: "Hebrew Name",
dataIndex: "hebrewname",
key: "hebrewname"
},{
title: "Kohen / Levi / Yisroel",
dataIndex: "kohenleviyisroel",
key: "kohenleviyisroel"
},{
title: "Frequent",
dataIndex: "frequent",
key: "frequent",
},{
title: "Do Not Bill",
dataIndex: "donotbill",
key: "donotbill"
},
{
title: "",
key: "action",
render: (record) => (
<button onClick={() => this.editContact(record.id)}
>
Edit
</button>
)
},
{
title: "",
key: "action",
render: (_text, record) => (
<Popconfirm
title="Are you sure you want to delete this contact?"
onConfirm={() => this.deleteContact(record.id)}
okText="Yes"
cancelText="No"
>
<a type="danger">
Delete{" "}
</a>
</Popconfirm>
),
},
];
componentDidMount = () => {
this.loadContacts();
}
loadContacts = () => {
const url = "http://localhost:3000/contacts";
fetch(url)
.then((data) => {
if (data.ok) {
return data.json();
}
throw new Error("Network error.");
})
.then((data) => {
data.forEach((contact) => {
const newEl = {
key: contact.id,
id: contact.id,
firstname: contact.firstname,
lastname: contact.lastname,
hebrewname: contact.hebrewname,
kohenleviyisroel: contact.kohenleviyisroel,
frequent: contact.frequent.toString(),
donotbill: contact.donotbill.toString(),
};
this.setState((prevState) => ({
contacts: [...prevState.contacts, newEl],
}));
});
})
.catch((err) => message.error("Error: " + err));
};
reloadContacts = () => {
this.setState({ contacts: [] });
this.loadContacts();
};
deleteContact = (id) => {
const url = `http://localhost:3000/contacts/${id}`;
fetch(url, {
method: "delete",
})
.then((data) => {
if (data.ok) {
this.reloadContacts();
return data.json();
}
throw new Error("Network error.");
})
.catch((err) => message.error("Error: " + err));
};
editContact = (id) => {
this.setState({
showEditWindow: true, EditContactId: {id}
});
};
render = () => {
return (
<>
<Table
className="table-striped-rows"
dataSource={this.state.contacts}
columns={this.columns}
pagination={{ pageSize: this.pageSize }}
/>
<AddContactModal reloadContacts={this.reloadContacts} />
<EditContactModal reloadContacts={this.reloadContacts}
showEditWindow={this.state.showEditWindow}
EditContactId={this.state.EditContactId}/>
</>
);
}
}
export default Contacts;
EditContactModal.jsx
import { Button, Form, Input, Modal, Select } from "antd";
import React from "react";
import ContactForm from './ContactForm';
const { Option } = Select;
class EditContactModal extends React.Component {
formRef = React.createRef();
state = {
visible: this.props.showEditWindow,
};
onFinish = (values) => {
const url = `http://localhost:3000/contacts/${this.props.EditContactId}`;
fetch(url, {
method: "put",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(values),
})
.then((data) => {
if(data.ok) {
this.handleCancel();
return data.json();
}
throw new Error("Network error.");
})
.then(() => {
this.props.reloadContacts();
})
.catch((err) => console.error("Error: " + err))
};
showModal = () => {
this.setState({
visible: true,
});
};
handleCancel = () => {
this.setState({
visible: false,
});
};
render() {
return (
<>
{/*<Button type="primary" onClick={this.showModal}>
Create New +
</Button>*/}
<Modal
title="Edit Contact"
visible={this.state.visible}
onCancel={this.handleCancel}
footer={null}
>
<ContactForm />
</Modal>
</>
);
}
}
export default EditContactModal;
if your aim is to perform an update to the state object, you must not pass mutable data, but copy it instead into a new object.
this will allow the state changes to be picked up.
so, prefer setState({ ...state, ...someObject }) over setState(someObject).

React MenuItem event.target.value not working in one, but works for the other MenuItem

I have two MenuItem drop down menus. The first is for selecting between two items (not working) and the second drop down menu has a list of years, which is working.
The following are the functions that I have created to capture the event.target.value for each of them:
handleYrChange = (event) => {
console.log('handleYrChange: ' + event.target.value);
this.setState({ data: [] });
getPartIdUpperSa(event.target.value).subscribe((res) => {
this.setState({ data: res });
this.setState({ isLoading: false });
});
this.props.isLoading ? this.setState({ isLoading: false }) : this.setState({ isLoading: true });
this.setState({ yrValue: event.target.value });
this.onCloseYr();
}
handleSaChange = (event) => {
console.log('handleSaChange: ' + event.target.value);
if(event.target.value === 'notSa') {
this.setState({ isPartIdUpperSa: false });
} else {
this.setState({ isPartIdUpperSa: true });
}
setBaseUrl(event.target.value);
this.setState({ saValue: event.target.value });
this.onCloseSa();
}
handleYrClick = (event) => {
this.setState({ yrAnchorEl: event.target })
this.setState({ yrOpen: true });
}
handleSaClick = (event) => {
this.setState({ saAnchorEl: event.target })
this.setState({ saOpen: true });
}
The following is a screen shot of when I have tried to click on the items. As you can see, the drop down for years is working as expected, yet the other is capturing "0"
The following is the full component, along with the service that it is subscribed:
First the component:
import React from "react";
import { FormGroup, FormControl, Button, Menu, MenuItem } from '#material-ui/core';
import MUIDataTable from "mui-datatables";
import { MuiThemeProvider } from '#material-ui/core/styles';
import { getPartIdUpperSa } from '../services/part-id-upper-sa-service';
import { setBaseUrl } from '../services/part-id-upper-sa-service'
import theme from '../theme';
export default class ParIdUpperSaComponent extends React.Component {
state = {
data: [],
Header: [],
totalCount: 10,
options: {
pageSize: 16,
page: 0,
filterType: "dropdown",
selectableRows: false,
responsive: "scroll",
resizableColumns: true,
className: this.name,
textLabels: {
body: {
noMatch: this.props.isLoading ?
'' :
'Please wait while processing...',
},
},
},
divAnchorEl: null,
yrValue: '2020',
yrOpen: false,
yrAnchorEl: null,
yrs: [],
saValue: 'sa',
saOpen: false,
saAnchorEl: null,
sa: ["sa","notSa"],
isLoading: true,
isPartIdUpperSa: true
}
componentDidMount() {
// create array of years for the past 18 years
const currentYr = new Date().getFullYear();
for(let x = 0; x < 18; x++) {
this.state.yrs.push(currentYr - x );
}
this.subscription = getPartIdUpperSa().subscribe((res) => {
this.setState({ data: res });
this.props.isLoading ? this.setState({ textLabels: '' }) : this.setState({ textLabels: 'Please wait while processing...' });
this.setState({ isLoading: false });
this.setState({ Header: [
{
label: "Part ID",
name: 'part_id_upper',
options: {
className: 'first-col'
}
},
{
label: "Seq",
name: 'sequence',
options: {
className: 'sec-col'
}
},
{
label: "Qty",
name: 'quantity',
options: {
className: 'sm-col'
}
},
{
label: "Dt Orig",
name: 'date_originated',
options: {
className: 'mid-col'
}
},
{
label: "Div",
name: 'code_division',
options: {
className: 'sm-col'
}
},
]});
this.setState({
totalCount: Math.ceil(this.state.data.length / this.state.pageSize)
});
})
}
componentWillUnmount() {
// unsubscribe to ensure no memory leaks
this.subscription.unsubscribe();
}
handleYrChange = (event) => {
console.log('handleYrChange: ' + event.target.value);
// this.setState({value: event.target.value ? event.target.value : ''});
this.setState({ data: [] });
getPartIdUpperSa(event.target.value).subscribe((res) => {
this.setState({ data: res });
this.setState({ isLoading: false });
});
this.props.isLoading ? this.setState({ isLoading: false }) : this.setState({ isLoading: true });
this.setState({ yrValue: event.target.value });
this.onCloseYr();
}
handleSaChange = (event) => {
console.log('handleSaChange: ' + event.target.value);
if(event.target.value === 'notSa') {
this.setState({ isPartIdUpperSa: false });
} else {
this.setState({ isPartIdUpperSa: true });
}
setBaseUrl(event.target.value);
this.setState({ saValue: event.target.value });
this.onCloseSa();
}
handleYrClick = (event) => {
this.setState({ yrAnchorEl: event.target })
this.setState({ yrOpen: true });
}
handleSaClick = (event) => {
this.setState({ saAnchorEl: event.target })
this.setState({ saOpen: true });
}
onCloseYr = () => {
this.setState({ yrOpen: false });
}
onCloseSa = () => {
this.setState({ saOpen: false });
}
render() {
let arrayofSa = this.state.sa;
let saDropDown = arrayofSa.map((sa) =>
<MenuItem onClick={(event) => this.handleSaChange(event)} value={sa} key={sa}>
{sa}
</MenuItem>
);
let arrayOfYrs = this.state.yrs;
let yrDropDown = arrayOfYrs.map((yrs) =>
<MenuItem onClick={(event) => this.handleYrChange(event)} value={yrs} key={yrs}>
{yrs}
</MenuItem>
);
return (
<div>
<MuiThemeProvider theme={theme}>
<FormGroup column='true'>
<FormControl>
<Button aria-controls="simple-menu" aria-haspopup="true" onClick={this.handleSaClick}>
Select Sa or NotToSa
</Button>
<Menu id="sa-menu" open={this.state.saOpen}
anchorEl={this.state.saAnchorEl} onClose={this.onCloseSa}
defaultValue={this.state.saValue ? this.state.saValue : ''} >
{saDropDown}
</Menu>
<Button aria-controls="simple-menu" aria-haspopup="true" onClick={this.handleYrClick}>
Select Year
</Button>
<Menu id="yrs-menu" open={this.state.yrOpen}
anchorEl={this.state.yrAnchorEl} onClose={this.onCloseYr}
defaultValue={this.state.yrValue ? this.state.yrValue : ''} >
{yrDropDown}
</Menu>
</FormControl>
</FormGroup>
</MuiThemeProvider>
{this.state.isLoading ? <img src="ajax-loader.gif" alt="loading gif" /> : ''}
<MUIDataTable
title="Part ID Upper Sa / Not Sa Report"
data={ this.state.data }
columns={ this.state.Header }
options={ this.state.options }
/>
</div>
);
}
}
The following is the service:
import { ajax } from "rxjs/ajax";
import { Observable } from "rxjs";
let base_url = 'https://localhost:5001/PartIdUpperSa';
export const getBaseUrl = () => {
return base_url;
}
export const setBaseUrl = (param) => {
console.log("from within setBaseUrl: " + param);
if(param === 'notSa') {
base_url = 'https://localhost:5001/PartIdUpperNotSa';
} else {
base_url = 'https://localhost:5001/PartIdUpperSa';
}
}
let state = {
data: []
}
export const getPartIdUpperSa = (yr) => {
return new Observable(observe => {
let mYr = new Date().getFullYear();
let tempYr = (yr)? yr : mYr;
state.data = ajax
.get(base_url + "/" + tempYr)
.subscribe(resu => {
state.data = resu.response ;
// console.log("from within getPartIdUpperSa: " + JSON.stringify(resu.response));
observe.next(resu.response);
});
});
}
As usual, thanks in advance
I was able to find a work around. If someone could explain why this works, then I would appreciate it.
The component now uses numbers instead of characters in the array called "sa," which made it function as expected.
I used this:
sa: ["1","2"],
instead of this:
sa: ["sa","notSa"],
And it worked, the following is the complete component:
import React from "react";
import { FormGroup, FormControl, Button, Menu, MenuItem } from '#material-ui/core';
import MUIDataTable from "mui-datatables";
import { MuiThemeProvider } from '#material-ui/core/styles';
import { getPartIdUpperSa } from '../services/part-id-upper-sa-service';
import { setBaseUrl } from '../services/part-id-upper-sa-service'
import theme from '../theme';
export default class ParIdUpperSaComponent extends React.Component {
state = {
data: [],
Header: [],
totalCount: 10,
options: {
pageSize: 16,
page: 0,
filterType: "dropdown",
selectableRows: false,
responsive: "scroll",
resizableColumns: true,
className: this.name,
textLabels: {
body: {
noMatch: this.props.isLoading ?
'' :
'Please wait while processing...',
},
},
},
divAnchorEl: null,
yrValue: '2020',
yrOpen: false,
yrAnchorEl: null,
yrs: [],
saValue: '1',
saOpen: false,
saAnchorEl: null,
sa: ["1","2"],
isLoading: true,
isPartIdUpperSa: true
}
componentDidMount() {
// create array of years for the past 18 years
const currentYr = new Date().getFullYear();
for(let x = 0; x < 18; x++) {
this.state.yrs.push(currentYr - x );
}
this.subscription = getPartIdUpperSa().subscribe((res) => {
this.setState({ data: res });
this.props.isLoading ? this.setState({ textLabels: '' }) : this.setState({ textLabels: 'Please wait while processing...' });
this.setState({ isLoading: false });
this.setState({ Header: [
{
label: "Part ID",
name: 'part_id_upper',
options: {
className: 'first-col'
}
},
{
label: "Seq",
name: 'sequence',
options: {
className: 'sec-col'
}
},
{
label: "Qty",
name: 'quantity',
options: {
className: 'sm-col'
}
},
{
label: "Dt Orig",
name: 'date_originated',
options: {
className: 'mid-col'
}
},
{
label: "Div",
name: 'code_division',
options: {
className: 'sm-col'
}
},
]});
this.setState({
totalCount: Math.ceil(this.state.data.length / this.state.pageSize)
});
})
}
componentWillUnmount() {
// unsubscribe to ensure no memory leaks
this.subscription.unsubscribe();
}
handleYrChange = (event) => {
console.log('handleYrChange: ' + event.target.value);
this.setState({ data: [] });
getPartIdUpperSa(event.target.value).subscribe((res) => {
this.setState({ data: res });
this.setState({ isLoading: false });
});
this.props.isLoading ? this.setState({ isLoading: false }) : this.setState({ isLoading: true });
this.setState({ yrValue: event.target.value });
this.onCloseYr();
}
handleSaChange = (event) => {
console.log('handleSaChange: ' + event.target.value);
if(event.target.value === '2') {
this.setState({ isPartIdUpperSa: false });
} else {
this.setState({ isPartIdUpperSa: true });
}
setBaseUrl(event.target.value);
this.setState({ saValue: event.target.value });
this.onCloseSa();
}
handleYrClick = (event) => {
this.setState({ yrAnchorEl: event.target })
this.setState({ yrOpen: true });
}
handleSaClick = (event) => {
this.setState({ saAnchorEl: event.target })
this.setState({ saOpen: true });
}
onCloseYr = () => {
this.setState({ yrOpen: false });
}
onCloseSa = () => {
this.setState({ saOpen: false });
}
render() {
let arrayofSa = this.state.sa;
let saDropDown = arrayofSa.map((sa) =>
<MenuItem onClick={(event) => this.handleSaChange(event)} value={sa} key={sa}>
{sa}
</MenuItem>
);
let arrayOfYrs = this.state.yrs;
let yrDropDown = arrayOfYrs.map((yrs) =>
<MenuItem onClick={(event) => this.handleYrChange(event)} value={yrs} key={yrs}>
{yrs}
</MenuItem>
);
return (
<div>
<MuiThemeProvider theme={theme}>
<FormGroup column='true'>
<FormControl>
<Button aria-controls="simple-menu" aria-haspopup="true" onClick={this.handleSaClick}>
Select Sa or NotToSa
</Button>
<Menu id="sa-menu" open={this.state.saOpen}
anchorEl={this.state.saAnchorEl} onClose={this.onCloseSa}
defaultValue={this.state.saValue ? this.state.saValue : ''} >
{saDropDown}
</Menu>
<Button aria-controls="simple-menu" aria-haspopup="true" onClick={this.handleYrClick}>
Select Year
</Button>
<Menu id="yrs-menu" open={this.state.yrOpen}
anchorEl={this.state.yrAnchorEl} onClose={this.onCloseYr}
defaultValue={this.state.yrValue ? this.state.yrValue : ''} >
{yrDropDown}
</Menu>
</FormControl>
</FormGroup>
</MuiThemeProvider>
{this.state.isLoading ? <img src="ajax-loader.gif" alt="loading gif" /> : ''}
<MUIDataTable
title="Part ID Upper Sa / Not Sa Report"
data={ this.state.data }
columns={ this.state.Header }
options={ this.state.options }
/>
</div>
);
}
}
The following is the service that the component is subscribed to it:
import { ajax } from "rxjs/ajax";
import { Observable } from "rxjs";
let base_url = 'https://localhost:5001/PartIdUpperSa';
export const getBaseUrl = () => {
return base_url;
}
export const setBaseUrl = (param) => {
console.log("from within setBaseUrl: " + param);
if(param == '1') {
base_url = 'https://localhost:5001/PartIdUpperSa';
} else {
base_url = 'https://localhost:5001/PartIdUpperNotSa';
}
}
let state = {
data: []
}
export const getPartIdUpperSa = (yr) => {
return new Observable(observe => {
let mYr = new Date().getFullYear();
let tempYr = (yr)? yr : mYr;
state.data = ajax
.get(base_url + "/" + tempYr)
.subscribe(resu => {
state.data = resu.response ;
observe.next(resu.response);
});
});
}
Once more, if someone could explain why numbers work with event.target.value and characters do not, then I would appreciate it.

How i can reload current page in react?

Here I'm fetching data with ApiClient and after that I make operation to confirm to delete the current item. My question here is how i can reload the page after I click Yes ?
type Props = {
resourceName: string,
label: string,
accessor: string,
row: Object,
}
#withRouter
#connectAPI((apiClient: ApiClient, props: Props) => ({
deleteObject: {
send: (id: any) => apiClient.resources[props.resourceName].delete(id),
success: () => {
// TODO: ?
},
},
}))
class DeleteComponent extends React.Component<Props> {
state = {
open: false,
};
handleOpen = () => {
this.setState({ open: true });
};
handleConfirm = (props: Props) => {
const { accessor, row, deleteObject } = props;
const id = row._original[accessor];
deleteObject({
id,
});
};
render(): React.ReactNode {
const { open } = this.state;
let message = null;
if (open) {
message = (
<MessageDialog
message="Are tou sure you want to delete ?"
actions={{
yes: {
label: 'Yes',
callback: this.handleConfirm,
},
no: {
label: 'No',
callback: (e: SyntheticMouseEvent<HTMLButtonElement>) => this.setState({ open: false }),
},
}}
/>
);
}
return (
<React.Fragment>
<Button
position="right"
onClick={this.handleOpen}
hoverIndicator="light-1"
/>
{message}
</React.Fragment>
);
}
}
export default DeleteComponent;

How to do search in table?

I want to search with all the pagination and sorter field on place.
That is i want to call handleChange with searchkeyword.
So how can i call handleSearch and than call handleChange from within handleSearch?
import React from "react";
import { withRouter } from "react-router-dom";
import { Table, Button, Icon, Row, Col, Input } from "antd";
import axios from "axios";
const Search = Input.Search;
class App extends React.Component {
state = {
data: [],
searchValue: "",
loading: false,
visible: false,
pagination: {}
};
componentDidMount() {
this.fetch();
}
handleTableChange = (pagination, filter, sorter, value) => {
console.log(pagination, value, sorter, "Table Change");
let sorterOrder = "";
let sorterField = "";
let searchVal = "";
const pager = { ...this.state.pagination };
pager.current = pagination.current;
this.setState({
pagination: pager
});
if (value) {
console.log("inside if");
searchVal = undefined;
} else {
console.log("inside else");
searchVal = value;
}
if (sorter) {
if (sorter.order === "ascend") {
sorterOrder = "ASC";
}
if (sorter.order === "descend") {
sorterOrder = "DESC";
}
sorterField = sorter.field;
}
this.fetch({
page: pagination.current,
sortField: sorterField,
sortOrder: sorterOrder,
...filter,
value: searchVal
});
};
fetch = (params = {}) => {
this.setState({ loading: true });
axios.post("***/****", params).then(res => {
const pagination = { ...this.state.pagination };
let apiData = res.data.result;
if (res.data.status === 1) {
const objects = apiData.map(row => ({
key: row.id,
id: row.id,
firstName: row.firstName,
lastName: row.lastName,
status: row.status,
email: row.email
}));
console.log(res.data);
pagination.total = res.data.count;
this.setState({
loading: false,
data: objects,
pagination
});
} else {
console.log("Database status is not 1!");
}
});
};
handleSearch = value => {
console.log("value", value);
this.setState({
searchValue: value
});
let searchkey = this.state.searchValue;
const pagination = { ...this.state.pagination };
const sorter = { ...this.state.sorter };
console.log("search", value, pagination, sorter);
this.handleTableChange({
value
});
};
render() {
const columns = [
{
title: "First Name",
dataIndex: "firstName",
sorter: true
},
{
title: "Email",
dataIndex: "email",
sorter: true
}
];
return (
<div>
<Search
placeholder="input search text"
className="searchBut"
onSearch={value => this.handleSearch(value)}
/>
<Button
className="addBut"
style={{ marginTop: "0" }}
type="primary"
onClick={() => this.openForm()}
>
+ Add Admin
</Button>
</div>
<Table
bordered
columns={columns}
dataSource={this.state.data}
pagination={{ total: this.state.pagination.total, pageSize: 4 }}
loading={this.state.loading}
onChange={this.handleTableChange}
/>
);
}
}
export default withRouter(App);
here when i give value in search field it will call post request with request payload as follows:
{sortField: "", sortOrder: ""}
sortField: ""
sortOrder: ""
So how can i do that?
I'm not sure what you trying of achieve it here.
But you can always filter the source data of the table. Like following
<Table
bordered
columns={columns}
dataSource={this.state.data.filter(data=> Object.keys(data).filter(key => data[key].includes(searchValue)).length > 0 ? true: false)}
pagination={{ total: this.state.pagination.total, pageSize: 4 }}
loading={this.state.loading}
onChange={this.handleTableChange}
/>
let me know if it helps.

React component tree close previously opened parent node

I have created a react component tree for navigation.
You can see it working in the below codepen.
React Component Tree
let navConfigData = {
isDashboardVisible: true,
tierOneLinks: [
{
name: "First Page",
iconName: "star",
iconAbbreviation: "FP",
tierTwoItems: [
{
name: "Tier 2 Page",
iconName: "star",
iconAbbreviation: "FP",
tierThreeItems: [
{
name: "Tier 3 Page",
iconName: "star",
iconAbbreviation: "FP",
path: "#"
}
]
},
{
name: "Tier 2 sec Page",
iconName: "star",
iconAbbreviation: "FP",
path: "#"
}
]
},
{
name: "Second Page",
iconName: "",
iconAbbreviation: "SP",
path: "#"
},
{
name: "Third Page",
iconAbbreviation: "TP",
path: "#",
tierTwoItems: [
{
name: "Tier 2 Page",
iconName: "star",
iconAbbreviation: "FP",
tierThreeItems: [
{
name: "Tier 3 Page",
iconName: "star",
iconAbbreviation: "FP",
path: "#"
}
]
},
{
name: "Tier 2 sec Page",
iconName: "star",
iconAbbreviation: "FP",
path: "#"
}
]
},
{
name: "Fourth Page",
iconName: "send",
iconAbbreviation: "FO",
path: "#"
}
],
supportLinks: [
{
name: "First Support Page",
iconName: "settings",
iconAbbreviation: "FI",
path: "#"
},
{
name: "Second Support Page",
iconName: "security",
iconAbbreviation: "SE",
path: "#"
},
{
name: "Third Support Page",
iconName: "help",
iconAbbreviation: "TH",
path: "#"
}
]
};
class NavigationDrawerTierThree extends React.Component {
onClick = evt => {
this.props.onSelect(this.props.tierThree.name);
};
render() {
const { tierThree, selectedTierThreeLink } = this.props;
debugger;
return (
<a
className="mdc-list-item my-nav-drawer__tier-three"
onClick={this.onClick}
>
<span className="my-nav-drawer__tier-two-label">
{tierThree.name}
</span>
</a>
);
}
}
class NavigationDrawerTierTwo extends React.Component {
// static propTypes = {
// tierTwo: object.isRequired,
// showNavIcon: bool,
// onSelect: func.isRequired,
// selectedTierTwoLink: string.isRequired
// };
state = { tierTwoIsExpanded: false };
onClick = evt => {
debugger;
this.props.onSelect(this.props.tierTwo.name, "tier2");
const { tierTwoIsExpanded } = this.state;
this.setState({ tierTwoIsExpanded: !tierTwoIsExpanded });
};
getArrowIcon = () => {
return this.state.tierTwoIsExpanded ? (
<span class="material-icons cdk-nav-drawer__tier-two-icon">></span>
) : (
<span class="material-icons cdk-nav-drawer__tier-two-icon">
^
</span>
);
};
getAnchorClassBasedOnTier = () => {
return this.props.showNavIcon
? "cdk-nav-drawer__tier-two"
: "cdk-nav-drawer__tier-three";
};
getLabelClassBasedOnTier = () => {
return this.props.showNavIcon
? "cdk-nav-drawer__tier-two-label"
: "cdk-nav-drawer__tier-three-label";
};
render() {
const { tierTwo, showNavIcon, selectedTierTwoLink } = this.props;
const { tierTwoIsExpanded } = this.state;
debugger;
return (
<div>
<a
className="mdc-list-item my-nav-drawer__tier-two"
onClick={this.onClick}
>
{showNavIcon && this.getArrowIcon()}
<span className="my-nav-drawer__tier-two-label">
{tierTwo.name}
</span>
</a>
{tierTwoIsExpanded && this.props.children}
</div>
);
}
}
class NavigationDrawerTierOneAnchor extends React.Component{
// static propTypes = {
// tierOne: object.isRequired,
// onSelect: func.isRequired,
// selectedTierOneLink: string.isRequired
// };
// state = { tierIsExpanded: false };
onClick = evt => {
this.props.onSelect(this.props.tierOne.name, "tier1");
// const { tierIsExpanded } = this.state;
// this.setState({ tierIsExpanded: !tierIsExpanded });
};
render(){
const { tierOne, selectedTierOneLink, expanded } = this.props;
return(
<div>
<a
className="mdc-list-item my-nav-drawer__tier-one"
href={tierOne.path}
onClick={this.onClick}
ref={a => {
this.anchor = a;
}}
>
<span className="cdk-nav-drawer__tier-one-label">
{tierOne.name}
</span>
</a>
{expanded && this.props.children}
</div>
);
}
}
class NavigationDrawerAppTiers extends React.Component {
// static propTypes = {
// tierOneArray: array.isRequired,
// onToggleExpand: func.isRequired,
// onSelect: func.isRequired,
// selectedTierOneLink: string.isRequired,
// selectedTierTwoLink: string.isRequired,
// selectedTierThreeLink: string.isRequired,
// expandedTierOneName: string.isRequired
// };
render(){
const { tierOneArray, onSelect, selectedTierOneLink, selectedTierTwoLink, selectedTierThreeLink, expandedTierOneName } = this.props;
return (
<div className="mdc-drawer__content my-nav-drawer__app-tiers">
<nav className="mdc-list">
{tierOneArray.map((tierOneLink, index) => (
<NavigationDrawerTierOneAnchor
tierOne={tierOneLink}
onSelect={onSelect}
key={index}
expanded={tierOneLink.name === this.props.expandedTierOneName}
selectedTierOneLink={selectedTierOneLink}
>
{(tierOneLink.tierTwoItems || []).map((tierTwoItem, index) => (
<NavigationDrawerTierTwo
tierTwo={tierTwoItem}
onSelect={onSelect}
selectedTierTwoLink={selectedTierTwoLink}
showNavIcon={
(tierTwoItem.tierThreeItems &&
tierTwoItem.tierThreeItems.length > 0) ||
false
}
>
{(tierTwoItem.tierThreeItems || []).map(
(tierThreeItem, index) => (
<NavigationDrawerTierThree
tierThree={tierThreeItem}
onSelect={onSelect}
selectedTierThreeLink={selectedTierThreeLink}
/>
)
)}
</NavigationDrawerTierTwo>
))}
</NavigationDrawerTierOneAnchor>
))}
</nav>
</div>
);
}
}
class NavigationDrawer extends React.Component {
// static propTypes = {
// navConfig: object.isRequired
// };
state = {
isDrawerCollapsed: false,
selectedTierOneLink: "",
selectedTierTwoLink: "",
selectedTierThreeLink: "",
expandedTierOneName: ""
};
onSelect = (selectedLinkName, selectedTier) => {
if(selectedTier == "tier1"){
if (selectedLinkName === this.state.selectedTierOneLink) {
// User clicked on the same link again
this.setState(state => ({
expandedTierOneName: state.expandedTierOneName?"":selectedLinkName
}))
} else {
this.setState(state=>({
expandedTierOneName:selectedLinkName
}))
}
this.setState(state => ({ selectedTierOneLink: selectedLinkName }));
this.setState(state => ({ selectedTierTwoLink: "" }));
} else if (selectedTier == "tier2"){
this.setState(state => ({ selectedTierTwoLink: selectedLinkName }));
this.setState(state => ({ selectedTierThreeLink: "" }));
} else {
this.setState(state => ({ selectedTierThreeLink: selectedLinkName }));
this.setState(state => ({ selectedTierTwoLink: "" }));
}
};
render(){
const { navConfig } = this.props;
return(
<nav className="mdc-drawer mdc-drawer--permanent mdc-typography my-nav-drawer">
<div className="my-nav-drawer__links">
<NavigationDrawerAppTiers
tierOneArray={navConfig.tierOneLinks}
onSelect={this.onSelect}
selectedTierOneLink={this.state.selectedTierOneLink}
selectedTierTwoLink={this.state.selectedTierTwoLink}
selectedTierThreeLink={this.state.selectedTierThreeLink}
expandedTierOneName={this.state.expandedTierOneName}
/>
</div>
</nav>
);
}
}
React.render(
<NavigationDrawer navConfig={navConfigData}/>,
document.body
);
The component is max upto three levels and I don't want it to achieve currently with recursion.
I am looking for a behavior to close the previously opened Parent tree node after selecting any child from another parent tree.
To explain in detail from the Codepen example, I need help on the below scenario.
Currently if no child Items are selected, only One parent node will be toggled.
I need help in achieving the below scenario.
Click on any child Item from First page,
Now clicking on the Third page should not collapse the First Page(since an item is selected from First Page), First Page should collapse when any child item from Third page is selected.
If no child Item is selected from Third page and Third Page is clicked again then all the opened parent nodes (First page and third page) should be collapsed.
Could someone help me with modifying the codpen.
Below code throws initialState is not defined
class NavigationDrawer extends React.Component {
static propTypes = {
navConfig: object.isRequired
};
initialState = this.props.navConfig.tierOneLinks.reduce((acc, { name }) => {
acc[name] = false;
return acc;
}, {});
state = {
expanded: initialState,
isDrawerCollapsed: false,
selectedTierOneLink: "",
selectedTierTwoLink: "",
selectedTierThreeLink: "",
expandedTierOneName: ""
};
onSelect = (selectedLinkName, selectedTier) => {
if(selectedTier == "tier1"){
if (selectedLinkName === this.state.selectedTierOneLink) {
// User clicked on the same link again
this.setState(state => ({
expandedTierOneName: state.expandedTierOneName?"":selectedLinkName
}))
} else {
this.setState(state=>({
expandedTierOneName:selectedLinkName
}))
}
this.setState(state => ({ selectedTierOneLink: selectedLinkName }));
this.setState(state => ({ selectedTierTwoLink: "" }));
} else if (selectedTier == "tier2"){
this.setState(state => ({ selectedTierTwoLink: selectedLinkName }));
this.setState(state => ({ selectedTierThreeLink: "" }));
} else {
this.setState(state => ({ selectedTierThreeLink: selectedLinkName }));
this.setState(state => ({ selectedTierTwoLink: "" }));
}
};
render(){
const { navConfig } = this.props;
return(
<nav className="mdc-drawer mdc-drawer--permanent mdc-typography my-nav-drawer">
<div className="my-nav-drawer__links">
<NavigationDrawerAppTiers
tierOneArray={navConfig.tierOneLinks}
onSelect={this.onSelect}
selectedTierOneLink={this.state.selectedTierOneLink}
selectedTierTwoLink={this.state.selectedTierTwoLink}
selectedTierThreeLink={this.state.selectedTierThreeLink}
expandedTierOneName={this.state.expandedTierOneName}
/>
</div>
</nav>
);
}
}
I'm not going to edit the Codepen and do all the work for you, but I'll give you a general idea of how to achieve your requirements.
Click on any child Item from First page, Now clicking on the Third page should not collapse the First Page
To accomplish this, you need a separate expanded state for each tierOneLinks:
state = {
expanded: {},
};
Then you can use state.expanded[tierOne.name] to check if the tier one panel is expanded, and expand it with
this.setState(prevState => ({
expanded: {
...prevState.expanded, // leave other panels expanded
[tierOne.name]: true,
},
}));
First Page should collapse when any child item from Third page is selected.
To accomplish this, the child item's onClick handler need to call a callback function (from the parent component, passed as props) that does the following:
this.setState({
expanded: {
[tierOne.name] : true, // collapse all other panels
}
})
If no child Item is selected from Third page and Third Page is clicked again then all the opened parent nodes (First page and third page) should be collapsed.
To accomplish this, check if the current page is already expanded, and if so, set all panels to collapsed:
if (state.expanded[tierOne.name]) this.setState({ expanded: {} });
Alternative
Use a Set or array as the state for the list of expanded pages.
You need to create a copy of the previous state when you want to update it.

Resources