react nav link redirect on condition - reactjs

I have two values at data index: isOnline (true and false). Right now <NavLink /> renders on both true and false, but I want to render only when value is false and not when it's true. Is there any possibility to do that?
I want to hide hyperlink if value is true. Hyperlink should only be rendered with false value. At the moment it gives me hyperlink on both true and false. But I want true value not to be linked with any other stuff but false value should be clickable.
import React, { useEffect, useState } from 'react';
import {
Tabs, Icon, Divider, Table, Button, Input, Row, Col,
} from 'antd';
import moment from 'moment';
import { NavLink, Redirect } from 'react-router-dom';
import { getAllLeads } from '../../shared/services/apiService';
import { isSuccess } from '../../shared/utils/jsHelper';
import routePaths from '../../shared/routePaths';
// rowSelection object indicates the need for row selection
const rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
},
getCheckboxProps: (record) => ({
disabled: record.name === 'Disabled User', // Column configuration not to be checked
name: record.name,
}),
};
const dateFormat = 'YYYY-MM-DD';
const Leads = () => {
const [leadList, setLeadList] = useState([]);
const columns = [
{
title: 'Sl no.',
dataIndex: 'name',
render: (name, record) =><span>{leadList.indexOf(record) + 1}</span>
},
{
title: 'Date',
dataIndex: 'createdAt',
},
{
title: 'Name',
dataIndex: 'name',
},
{
title: 'Phone number',
dataIndex: 'phone_number',
},
{
title: 'Email id',
dataIndex: 'email',
},
{
title: 'Type',
dataIndex: 'type',
},
{
title: 'Comment',
dataIndex: 'comment',
},
{
title: 'Property name',
dataIndex: 'propertyId.name',
//render: (name, row) => {row.propertyId ? (<NavLink to={`${routePaths.PROPERTY}/${row.propertyId._id}`}>{name}</NavLink>) : null},
},
{
title:'On-Line / Off-Line',
dataIndex: 'isOnline',
// render: (isOnline, row) => {
// if(!isOnline){
// <NavLink to={`${routePaths.LEADSFORM}/${row._id}`}>
// {isOnline}
// </NavLink>
// }else{null}
// }
render: (isOnline, row) => <NavLink to={`${routePaths.LEADSFORM}/${row._id}`}>{isOnline}</NavLink>,
}
];
const [loading, setLoading] = useState(false);
var tokenSession = localStorage.getItem('token');
if(tokenSession!='undefined' && tokenSession == null){
var setTokenSession = true;
}else{
var setTokenSession = false;
}
const [loggedDashOut, setDashLoggedOut] = useState(setTokenSession? true:false);
if (loggedDashOut) {
return <Redirect to={routePaths.LOGIN} />;
}
const getLeadsList = () => {
setLoading(true);
getAllLeads().then((resp) => {
if (isSuccess(resp)) {
setLeadList(resp.data.data);
}
}).finally(() => setLoading(false));
};
useEffect(() => {
getLeadsList();
return () => {};
}, []);
return (
<Row className="row-pad">
<Col xs={24} sm={24} md={8} lg={8} xl={8}><h3>Leads</h3></Col>
<Col xs={24} sm={24} md={8} lg={8} xl={8}></Col>
<Col xs={24} sm={24} md={8} lg={8} xl={8}>
<NavLink to={routePaths.LEADSFORM}>
<Button type="primary" className="btn-add">Add Leads</Button>
</NavLink>
</Col>
<Divider />
<Table pagination={{ pageSize: 10 }} columns={columns} dataSource={leadList} />
</Row>
);
};
export default Leads;

I'm not sure where is your isOnline variable, but basically if you want to render something conditionally you can try:
return (
...
{isOnline ? null : <NavLink />}
...
)
This will render the <NavLink /> component only when isOnline is false.
This is not the only way to implement conditional rendering in React, just a very common one, and I think it suits your use case.
For more details you can refer to the official docs regarding conditional rendering.
Good luck!

Related

How can I have a button in a const object?

I'm learning React.js and this is a table showing which user has which items.
I would like to have a button for each item and delete the corresponding item.
How do you have or {FaTrash} icon in a const object?
This is my full code below
const columns = [
{
name: "Username",
selector: "username",
sortable: true
},
{
name: "Email",
selector: "email",
sortable: true
},
{
name: "Item",
selector: "items",
sortable: true,
right: true
},
{
name: "Action",
value: <button>Edit</button>
}
]
const Admin = () => {
const [data, setData] = useState(allUsers);
const handleRowClicked = row => {
const updatedData = data.map(item => {
if (row.id !== item.id) {
return item;
}
return {
...item,
toggleSelected: !item.toggleSelected
};
});
setData(updatedData);
}
return ( <>
<div className='users p-5'>
<DataTable
title="Users"
columns={columns}
data={data}
defaultSortField="title"
pagination
onRowClicked={handleRowClicked}
/>
</div>
</> );
}
export default Admin;
I used to pass a function that returns a piece of layout with handler
{
name: "Action",
actionRenderer: ({ index, item }) => {
return (
<button onClick={() => onhandle(item)}>
ActionName <!--or icon component-->
</button>
)
}
},
Than you need to create <DataTableRow> component wich will render each object in your columns array. Somewhere in the <DataTableRow> you will be able to access to actionRenderer and your data item:
<div>{actionColumn.actionRenderer({ index, item })}</div>

Display data in antd table based on selected item from select option

I need to display data on the antd table based on the selected item from select option.The data that are to be displayed are stored in different variables. For example, if school is selected from select option then the datasource is available in schoolData and similarly for other option.
Here's my code:
import React, { useState } from "react";
import Framework from "../framework/Framework";
import { Dropdown, Button, Table, message, Select } from "antd";
import { DeleteOutlined, DownOutlined, EditOutlined } from "#ant-design/icons";
import { Content } from "antd/lib/layout/layout";
import AddNewButton from "../addNewButton/AddNewButton";
import "./attributes.css";
import DataSource from "./Datasource";
import IconDescription from "../icondescription/IconDescription";
import Modal from "antd/lib/modal/Modal";
import { Option } from "antd/lib/mentions";
const Attributes = () => {
const [page, setPage] = useState(1);
const [isModalVisible, setIsModalVisible] = useState(false)
// const [layer, setLayer] = useState()
const columns = [
{
title: "S.N",
dataIndex: "key",
},
{
title: "Name",
dataIndex: "name",
key: "name",
// render: (text) => <a>{text}</a>,
},
{
title: "Address",
dataIndex: "address",
key: "address",
},
{
title: "Contact No.",
dataIndex: "contactno",
key: "contactno",
},
{
title: "Operation",
dataIndex: "operation",
key: "operation",
render: () => {
return (
<div style={{ display: "flex" }}>
<IconDescription icon={<EditOutlined />} label="Edit" />
<IconDescription icon={<DeleteOutlined />} label="Delete" />
</div>
);
},
},
];
const addAttribute = () => {
setIsModalVisible(true)
}
const modalHandleOk = () => {
setIsModalVisible(false);
};
const modalHandleCancel = () => {
setIsModalVisible(false);
};
const selectLayer = (e) => {
console.log("select layer", e)
}
return (
<Framework>
<Content className="attributes">
<div className="select-addNewBtn-container">
<Select defaultValue="school" style={{ width: 120 }} onChange={selectLayer}>
<Option value="school">School</Option>
<Option value="hospital">Hospital</Option>
<Option value="policeStation">Police Station</Option>
</Select>
<AddNewButton name={"Add New Attribute"} addNewBtn={addAttribute} />
<Modal title={"Add New Attribute"} visible={isModalVisible} centered onCancel={modalHandleCancel} onOk={modalHandleOk}>
</Modal>
</div>
<Table
dataSource={DataSource}
columns={columns}
className="data-table"
pagination={{
size: "small",
pageSize: 6,
hideOnSinglePage: true,
showSizeChanger: false,
}}
/>
</Content>
</Framework>
);
};
export default Attributes;
How do i achieve the desired functionality? Do let me know. Quite a beginner at such things.
Assuming Datasource is just a simple array of data objects, and presumably you have another file eg: 'SchoolData' that you need to switch between when the select option is chosen.
What I'd do to keep it simple is create a react state variable to wrap your data and just set it at will in the onChange of your select.
Example

Why am I getting the TypeError: _this.props.data is not a function

I am using material-table to build a table of users from a call to my API. The data returns just fine in the console, but when I got to render it, I get an error. Here is an image of my error.
And my code:
import React, { useState, useEffect, useRef, Fragment } from 'react';
import axios from 'axios';
import { API } from '../../config';
import Layout from '../../components/Layout';
import MaterialTable from 'material-table';
const PendingUser = () => {
const [pendingUser, setPendingUser] = useState({
firstName: '',
lastName: '',
email: '',
agency: ''
});
const isMountedVal = useRef(1);
useEffect(() => {
isMountedVal.current = 1;
return () => {
isMountedVal.current = 0;
};
getPendingUsers();
setPendingUser(pendingUser);
}, []);
const getPendingUsers = async () => {
const { data } = await axios.get(`${API}/admin/pendinguser`);
await data.filter(user => {
user.accountApproved ? setPendingUser(user) : setPendingUser();
setPendingUser(user);
});
};
const handleClick = (name, rowData, index, email) => e => {
e.preventDefault();
try {
if (name === 'deny') {
axios.delete(`${API}/admin/pendinguser/${name}/${rowData._id}`);
} else {
name === 'approve';
axios.put(`${API}/admin/pendinguser/${name}/${rowData._id}`);
}
} catch (error) {
console.log(error);
}
};
const columns = [
{
title: 'First Name',
field: 'firstName'
},
{
title: 'Last Name',
field: 'lastName'
},
{
title: 'Email',
field: 'email'
},
{
title: 'Law Enforcement Agency',
field: 'leAgency'
},
{
title: 'Approve',
field: 'approve',
render: rowData => (
<i
className='far fa-check-circle fa-2x'
style={{ color: 'green' }}
onClick={handleClick('approve', rowData)}
></i>
)
},
{
title: 'Deny',
field: 'deny',
render: rowData => (
<i
className='far fa-times-circle fa-2x'
style={{ color: 'red' }}
onClick={handleClick('deny', rowData)}
></i>
)
},
{
title: 'Denial Reason',
field: 'denialReason',
render: rowData => (
<select>
<option value='Not Law Enforcement'>Not Law Enforcement</option>
<option value='Non US Law Enforcement'>Non US Law Enfrocement</option>
</select>
)
}
];
console.log(pendingUser);
return (
<Layout>
<MaterialTable
title='Pending Users'
columns={columns}
data={pendingUser}
isLoading={!pendingUser.length}
options={{
headerStyle: {
backgroundColor: '#249DCD',
color: 'white',
fontWeight: 'bold'
}
}}
/>
</Layout>
);
};
export default PendingUser;
If I remove the data from the columns render just fine, but what is the point if I cant get the data to render.
Material Table requires data to be either an array or a function. You are instead setting it as an object. So material-table first checks if its an array, its not, so it assumes its a function and tries to invoke it, resulting in the above error.

Cant turn on switch inside Material-Table

I am trying to create material-table with switches, that onclick changes the state of the component.
Here is component with table, which has state of the parent component as a props. I pass rows variable to the material table data prop. Switch is custom rendered field. Whenever I click on it, it triggers changeRow, which finds index of row in rows variable changes it and saves into new variable. ChangeRows is then called to change the state.
The problem is, the switch is not changing. It looks like nothing is happenning, even though I can clearly see new state in console.
const StuffTable = ({rows, changeRows}) => {
const changeRow = (oldRow, e) => {
const changeData = {[e.target.name]: e.target.checked};
const newRow = {...oldRow, ...changeData};
console.log(oldRow, e);
const index = rows.findIndex(dtaRow => dtaRow.id === oldRow.id);
const newData = rows;
newData[index] = newRow;
console.log(newData);
changeRows(newData);
};
return (
<Container maxWidth="lg">
<Button onClick={() => { changeRow({id: 6}, { target: {name: 'borrowable', checked: true} }) }}>klikni</Button>
<MaterialTable
options={{
actionsColumnIndex: -1,
search: true,
exportButton: true,
exportDelimiter: ";"
}}
actions={[
{
icon: 'edit',
tooltip: 'Edit Study',
onClick: (event, rowData) => alert("Do you want to edit?")
}]}
columns={[
{ title: "Název", field: "title" },
{ title: "Stav", field: "status", render: (data) => <Chip label={data.status} color="primary" avatar={<Avatar src="/static/images/avatar/1.jpg" />} /> },
{ title: "Půjčovat", field: "borrowable", render: (data, id) => (<FormControlLabel control={<Switch checked={data.borrowable} onChange={(e) => changeRow(data, e)} name="borrowable" color="primary"/>} label={data.borrowable ? 'půjčovat' : 'nepůjčovat'} />) },
{ title: "Vidí všichni", field: "active", render: (data, id) => (<FormControlLabel control={<Switch checked={data.borrowable} onChange={(e) => changeRow(data, e)} name="borrowable" color="primary"/>} label={data.borrowable ? 'půjčovat' : 'nepůjčovat'} />) },
{ title: "Uskladněno", field: "location" },
]}
data={rows}
title="Moje věci"
/>
</Container>
);
};
export default StuffTable;
I tried to add button, which on click changes state to empty array, and table did show nothing. But when I triggered changeRow (mockup data) with this button, result was the same - no change on the switch.
import React, {useEffect, useState} from 'react';
import StuffTable from "../components/stuffTable";
let rows = [
{id:5, title: "prošívanice", borrowable: false, surname: "Baran", status: "zapůjčeno", location: "Praha" },
{id:6, title: "prošívanice 2", borrowable: false, surname: "Baran", status: "zapůjčeno", location: "Praha" },
{id:7, title: "prošívanice 3", borrowable: false, surname: "Baran", status: "zapůjčeno" , location: "Brno"}
];
Here is Parent component
const MyStuffPage = () => {
const [data, setData] = useState(rows);
return (
<div>
<StuffTable rows={data} changeRows={(data) => {setData(data); console.log("hou",data);}} />
</div>
);
};
export default MyStuffPage;
Here is Codesandbox with this problem:
https://codesandbox.io/s/festive-gould-i1jf7
You need to call onQueryChange whenever you want to render new data or state to the datatable, make these changes:
at the begining create a ref like so:
const tableRef = useRef(null);
then use it in the material table:
<MaterialTable
//add this
tableRef={tableRef}
options={{
actionsColumnIndex: -1,
search: true,
exportButton: true,
exportDelimiter: ";"
}}
then inside your changeRow function after updating the start and the necessary work add this:
tableRef.current.onQueryChange()
this will tell the table to render the new data with the correct state of the switch

How do you use popconfirm in an antd react table?

I have a reactjs component which displays an antd table of which one of the columns is to execute an action to archive the item in the row. If someone clicks on Archive I want it to show a popconfirm with yes/no confirmation before it moves forward and archives the item.
Everything works fine until I add the Popconfirm block. Then I get the below error. I think that there is something wrong with my usage of onconfirm and oncancel in the popconfirm but i'm just not getting something probably obvious here. Appreciate any feedback!
import React, { Component } from 'react';
import { connect } from 'react-redux';
import selectProperties from '../selectors/properties';
import { Table, Tag, Divider, Popconfirm, message } from 'antd';
export class PropertyList extends React.Component {
constructor(){
super();
this.columns = [
{
title: 'Address',
dataIndex: 'street',
key: 'street',
render: text => <a>{text}</a>,
},
{
title: 'City',
dataIndex: 'city',
key: 'city',
},
{
title: 'State',
dataIndex: 'state',
key: 'state',
},
{
title: 'Workflow',
key: 'workflow',
dataIndex: 'workflow',
sorter: (a, b) => a.workflow.length - b.workflow.length,
sortDirections: ['descend'],
render: workflow => {
let color = 'geekblue';
if (workflow === 'Inspection' || workflow === 'Maintenance' || workflow === 'Cleaning') {
color = 'volcano';
}
else if (workflow === 'Rented') {
color = 'green';
}
return (
<span>
<Tag color={color} key={workflow}>
{workflow.toUpperCase()}
</Tag>
</span>
);
},
},
{
title: 'Action',
key: 'action',
render: (text, record) => (
<span>
<a>Edit</a>
<Divider type="vertical" />
<Popconfirm
title="Are you sure?"
onConfirm={this.confirm(record)}
onCancel={this.cancel}
okText="Yes"
cancelText="No"
>
Archive
</Popconfirm>
</span>
),
},
];
}
confirm = (record) => {
message.success('Archived');
console.log("confirm function.. record");
console.log(record);
}
cancel = () => {
message.error('Cancelled');
}
render() {
console.log("PropertyList render");
console.log(this.props);
console.log(this.props.properties);
console.log(this.columns);
return (
<div className="content-container">
<div className="list-body">
{
this.props.properties.length === 0 ? (
<div className="list-item list-item--message">
<span>No properties. Add some!</span>
</div>
) : (
<Table
rowKey="id"
dataSource={this.props.properties}
columns={this.columns}
pagination = { false }
footer={() => ''}
/>
)
}
</div>
</div>
)
}
};
const mapStateToProps = (state) => {
console.log("PropertyList mapStateToProps..");
console.log(state);
return {
properties: selectProperties(state.properties, state.filters)
};
};
const mapDispatchToProps = (dispatch) => ({
updateProperty: (id, property) => dispatch(editProperty(id, property))
});
export default connect(mapStateToProps, mapDispatchToProps)(PropertyList);
you are invoking the method confirm (in onConfirm) immediately when it renders the Table rows.
Change:
onConfirm={this.confirm(record)}
To:
onConfirm={() => this.confirm(record)}

Resources