How to call an event on tabs changed in react-bootstrap - reactjs

I've implemented Navigation Tabs in my React application using React-Bootstrap.
Like this:
<Tabs defaultActiveKey={1}>
<Tab eventKey={1} title="Log in">
{/* Irrelevant code */}
</Tab>
<Tab eventKey={2} title="Sign up">
{/* Irrelevant code */}
</Tab>
</Tabs>
Now on changing tabs I would like to call the following funtion:
changeTab(login) {
if (login)
this.setState({ heading: "Log in" })
else
this.setState({ heading: "Sign up" })
}
Where login is a Boolean that will be true for when the Log in tab is selected and false when the Sign up tab is selected.
How can I do that?
Edit:
I've figured out that you can call a function on when the tabs are clicked like this:
<Tabs defaultActiveKey={1} onClick={()=>this.changeTab()}>
<Tab eventKey={1} title="Log in">
{/* Irrelevant code */}
</Tab>
<Tab eventKey={1} title="Sign up">
{/* Irrelevant code */}
</Tab>
</Tabs>
But how can I know which tab was clicked? I need it to change the state based on which tab is clicked.

You need to use onSelect in the Tabs component.
Like this:
<Tabs defaultActiveKey={1} onSelect={this.handleSelect()}>
<Tab eventKey={1} title="Log in">
{/* Irrelevant code */}
</Tab>
<Tab eventKey={2} title="Sign up">
{/* Irrelevant code */}
</Tab>
</Tabs>
And then make this your handleSelect function:
handleSelect(key) {
if (key === 1)
this.setState({ heading: "Log in" })
else
this.setState({ heading: "Sign up" })
}

<Tab.Container id="" defaultActiveKey={key} onSelect={this.handleSelect}>
<Nav variant="tabs">
<Nav.Item>
<Nav.Link eventKey={'1'}>Staking</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey={'2'}>Providers</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey={'3'}>Overview</Nav.Link>
</Nav.Item>
</Nav>
<Tab.Content>
<Tab.Pane eventKey={'1'}>
<Row>
<Col>
1111
</Col>
</Row>
</Tab.Pane>
</Tab.Content>
<Tab.Content>
<Tab.Pane eventKey={'2'}>
<div>22222</div>
</Tab.Pane>
</Tab.Content>
<Tab.Content>
<Tab.Pane eventKey={'3'}>
<div>333</div>
</Tab.Pane>
</Tab.Content>
</Tab.Container>
Now in your state add 'key' field with initial value '1'
constructor(props) {
super(props);
this.state = {
key: '1'
};
}
Then write a function
handleSelect = (key) => {
console.log(key,';;',typeof key)
if(key === '1') {
console.log('ll', key)
} else if(key === '2') {
console.log('ll', key)
} else if(key === '3') {
console.log('ll', key)
}
}
Initially when the page loades, the function is not called so you can make API calls or any thing you want to do in the 1st tab, in componentDidMount or any other function and place it in the 1st tab i.e where I've written 1111,after this when you click another tab, handleSelect function is called and based on key value with use if..else statement to perform specific task for specific tab.
Hope this helps. If any issue please let us know in the comment section.

Here, You can use onSelect as Barry Michael Doyle said. Let me post you a sample code to make it more clear for you.
function Example() {
return (
<Tabs defaultActiveKey="home" id="uncontrolled-tab-example"
className="mb-3" onSelect={(e) => handleClick(e)}>
<Tab eventKey="homeTab" title="Home">
</Tab>
<Tab eventKey="profileTab" title="Profile">
</Tab>
<Tab eventKey="contactTab" title="Contact">
</Tab>
</Tabs>
);
function handleClick(e) {
console.count(e);
//result will be the eventKey of the tab you clicked on.
// `homeTab` (when clicked on home tab)
// `profileTab` (when clicked on profile tab)
// `constactTab` (when clicked on Contact tab)
}
}

Related

antd collapse.panel not re rendering

I have this collapse panel in antd.
<Collapse defaultActiveKey={[1]} onChange={onChange}>
<Panel header="Billing Details" key="2" forceRender>
<BillingPanel
invoiceCycleOptions={invoiceCycleOptions}
projectData={projectData}
payModelOptions={payModelOptions}
accTypeOptions={accTypeOptions}
onDateChange={onDateChange}
isEditMode={isEditMode}
isPopulated={isPopulated}
prjStartDate={prjStartDate}
/>
</Panel>
<Panel header="Other Details" key="3" forceRender>
<OtherDetailsPanel
csmOptions={csmOptions}
projectData={projectData}
csm={csm}
onPrimaryCsmSelect={onPrimaryCsmSelect}
accountantOptions={accountantOptions?.map(
(option) => option?.name
)}
isEditMode={isEditMode}
secondaryCsmoptions={secondaryCsmoptions}
setShow={setShow}
setDocument={setDocument}
show={show}
salesPersonOptions={salesPersonOptions}
setIsValidSize={setIsValidSize}
isValidSize={isValidSize}
leadSourceOptions={leadSourceOptions}
marketingChannelOptions={marketingChannelOptions}
activeBillingOptions={activeBillingOptions}
activeBilling={activeBilling}
form={form}
selectedCsm={selectedCsm}
primaryCsm={primaryCsm}
secondaryCsmList={secondaryCsmList}
/>
</Panel>
</Collapse>
when projectData changes, the panel with the header "Other Details" does not re render. I am getting updated projectData in this component but not in the OtherDetailsPanel component. Can anyone help me?

How to add if else inside the Tabs in react bootstrap

I try to execute following code but I got some error.
Error : ReactBootstrap: The Tab component is not meant to be rendered! It's an abstract component that is only valid as a direct Child of the Tabs Component. For custom tabs components use TabPane and TabsContainer directly.
import { Row, Col, Tabs, Tab } from "react-bootstrap";
import One from "../One.jsx";
//One,Two .. etc There are more
render(
<Tabs>
<Tab eventKey={1} title="Tab 1"><One/></Tab>
<Tab eventKey={2} title="Tab 2"><Two/></Tab>
<Tab eventKey={3} title="Tab 3"><Three/></Tab>
{this.state.type === type && (
<Tab eventKey={4} title="Tab 4"><Four/></Tab>
<Tab eventKey={5} title="Tab 5"><Five/></Tab>
<Tab eventKey={6} title="Tab 6"><Six/></Tab>
)}
</Tabs>
)
I found this solution by accident.
I used to declare component's name as Tab without import from 'react-bootstrap' and using JSX condition rendering not any problem
But when I changed component's name to another, I found error from 'react-bootstrap' and my JSX condition rendering didn't work anymore cause 'react-bootstrap' wont accept JSX shorthand fragment or any.
So I declare empty component for handle error and using <>...</> in JSX condition rendering and everything works for me.
import React from "react";
import { Tabs } from "react-bootstrap";
const Tab = () => {
return <></>;
};
export const App = (props) => {
return(
<Tabs>
<Tab eventKey={1} title="Tab 1"><One/></Tab>
<Tab eventKey={2} title="Tab 2"><Two/></Tab>
<Tab eventKey={3} title="Tab 3"><Three/></Tab>
{props.type === type && (
<>
<Tab eventKey={4} title="Tab 4"><Four/></Tab>
<Tab eventKey={5} title="Tab 5"><Five/></Tab>
<Tab eventKey={6} title="Tab 6"><Six/></Tab>
</>
)}
</Tabs>
)
}
On top is not good practice but it's easy to declare condition.
In case you want to do with better practice use this instead.
import React from "react";
import { Tabs, Tab } from "react-bootstrap";
export const App = (props) => {
return(
<Tabs>
<Tab eventKey={1} title="Tab 1"><One/></Tab>
<Tab eventKey={2} title="Tab 2"><Two/></Tab>
<Tab eventKey={3} title="Tab 3"><Three/></Tab>
{props.type === type && <Tab eventKey={4} title="Tab 4"><Four/></Tab>}
{props.type === type && <Tab eventKey={5} title="Tab 5"><Five/></Tab>}
{props.type === type && <Tab eventKey={6} title="Tab 6"><Six/></Tab>}
</Tabs>
)
}
I don't think you can construct new Tab components like that using conditional rendering. As stated in the error message, you can use Tab.Container & Tab.Pane to create your customs Tabs.
Reference to the docs:
For more complex layouts the flexible TabContainer, TabContent, and
TabPane components along with any style of Nav allow you to quickly
piece together your own Tabs component with additional markup needed.
Example implementation of Tabs contruction with conditional rendering:
return (
<Tab.Container defaultActiveKey={1}>
<Nav variant="pills" className="flex-column">
<Row>
<Nav.Item>
<Nav.Link eventKey={1}>Tab 1</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey={2}>Tab 2</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey={3}>Tab 2</Nav.Link>
</Nav.Item>
{this.state.type === type && (
<>
<Nav.Item>
<Nav.Link eventKey={4}>Tab 4</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey={5}>Tab 5</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey={6}>Tab 6</Nav.Link>
</Nav.Item>
</>
)}
</Row>
</Nav>
<Tab.Content>
<Tab.Pane eventKey={1} title="Tab 1">
1
</Tab.Pane>
<Tab.Pane eventKey={2} title="Tab 2">
2
</Tab.Pane>
<Tab.Pane eventKey={3} title="Tab 3">
3
</Tab.Pane>
{this.state.type === type && (
<>
<Tab.Pane eventKey={4} title="Tab 4">
4
</Tab.Pane>
<Tab.Pane eventKey={5} title="Tab 5">
5
</Tab.Pane>
<Tab.Pane eventKey={6} title="Tab 6">
6
</Tab.Pane>
</>
)}
</Tab.Content>
</Tab.Container>
);
In fact, if you view the components on React Dev Tools, you will notice that the "Tab" component in fact is not actually rendered when using Tabs & Tab combo - hence they defined it as "abstract" component
Alternatively, if you must use Tabs & Tab JSX combo, then you are going to have to implement the condition on the entire Tabs rendering - not just a section of it. You can find an example here: https://codesandbox.io/s/beautiful-pond-quc2b?file=/src/App.js
You can refer to the following official documentation. It is explained very well.
https://reactjs.org/docs/conditional-rendering.html
Here is a sample code which I took from documentation. Hope this will clear your concept.
render() {
const isLoggedIn = this.state.isLoggedIn;
let button;
if (isLoggedIn) {
button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
button = <LoginButton onClick={this.handleLoginClick} />;
}
return (
<div>
<Greeting isLoggedIn={isLoggedIn} />
{button}
</div>
);
}

Placing a picture next to a title for a react bootstrap Tab

React bootstrap Tabs allow us to create tabs.
<Tabs defaultActiveKey="profile" id="uncontrolled-tab-example">
<Tab eventKey="home" title="Home">
<Sonnet />
</Tab>
<Tab eventKey="profile" title="Profile">
<Sonnet />
</Tab>
<Tab eventKey="contact" title="Contact" disabled>
<Sonnet />
</Tab>
</Tabs>
For each Tab there is a title tag that accepts a string. I wonder if it is possible to display a picture instead of the title? Or display both? Also, I wish I could display a picture next to the Tab's title.
see the first tab, you have a title and an image one next to each other.
<Tab.Container id="left-tabs-example" defaultActiveKey="first">
<Row>
<Col sm={3}>
<Nav variant="pills" className="flex-column">
<Nav.Item>
<Nav.Link eventKey="first">
Tab 1
<img src="https://lh3.googleusercontent.com/-pxzt5JSmq3o/AAAAAAAAAAI/AAAAAAAAARw/oSQ00wYMa9g/photo.jpg?sz=32"></img>
</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link eventKey="second">Tab 2</Nav.Link>
</Nav.Item>
</Nav>
</Col>
<Col sm={9}>
<Tab.Content>
<Tab.Pane eventKey="first">
<Sonnet />
</Tab.Pane>
<Tab.Pane eventKey="second">
<Sonnet />
</Tab.Pane>
</Tab.Content>
</Col>
</Row>
</Tab.Container>

Dynamic EventKey not working React-Bootstrap

I am dynamically rendering my tabs in React-Bootstrap, but somehow the eventKey doesn't recognise the values and the tabs aren't clickable.
Here's the code.
var tabButtons = tabsList.map(function(text, index){
if(text.enabled==1)
{
return <NavItem eventKey={index} key={index}><center> {text.value}</center></NavItem>; }
});
Here tabList is an array which contains information about whether the button is enabled. If yes, then display the button information.
The code where I am calling these tabs.
render() {
return (
<div>
<Tab.Container id="tab" defaultActiveKey="0">
<Row className="show-grid">
<Col sm={12}>
<Nav bsStyle="tabs" justified>
{tabButtons}
</Nav>
</Col>
<Col sm={12}>
<Tab.Content animation>
<Tab.Pane eventKey="0">
<FirstTabContent />
</Tab.Pane>
<Tab.Pane eventKey="1">
Second
</Tab.Pane>
<Tab.Pane eventKey="2">
<ThirdTabContent />
</Tab.Pane>
</Tab.Content>
</Col>
</Row>
</Tab.Container>
</div>
);
I have no idea, why aren't the eventKey able to use the index values.
Anything I am missing? Another approach perhaps?
Apparently after some hit and tries, got it working.
The problem was indeed in eventKey.
Replaced eventKey="0" with eventKey={0}
Though I have no idea what difference it makes. Anyone?

Reactjs Material UI Tabs label will disappear and will retain logo for smaller screen

So I am new in using Material UI Tabs and I want the labels to disappear when the screen is resized. for example when the screen is in 500px or smaller, the logo will only retain and the label will disappear.
below is the sample code of my material ui Tabs
<Tabs onChange={this.handleChange.bind(this)} value={this.state.status}>
<Tab icon={<FontIcon className="fa fa-cogs" />} label="Process" value='orderProcessing' />
<Tab icon={<FontIcon className="fa fa-money" />} label="Paid" value='orderConfirmed' />
<Tab icon={<FontIcon className="fa fa-industry" />} label="Production" value='onProduction' />
<Tab icon={<FontIcon className="fa fa-shopping-cart" />} label="Qc and Packaging" value={3} />
<Tab icon={<FontIcon className="fa fa-cart-arrow-down" />} label="Sold" value='sold' />
<Tab icon={<FontIcon className="fa fa-ban" />} label="Cancelled" value='cancelled' />
<Tab icon={<FontIcon className="fa fa-globe" />} label="All Transactions" value='' />
</Tabs>
You can accomplish this by using this.isDeviceSize(). Here is an example:
Updated to show one tab with only a label and the other with only the icon when the screen is small. Previously both tabs removed the icons and the question was actually asking how to remove the labels. Now the example below shows how to do either.
import React from 'react'
import {Mixins, Tabs, Tab} from 'material-ui'
const {StylePropable, StyleResizable} = Mixins
import {MapsDirectionsRun} from 'material-ui/lib/svg-icons'
export default React.createClass({
propTypes: {
onChangeMuiTheme: React.PropTypes.func,
},
contextTypes: {
muiTheme: React.PropTypes.object,
},
mixins: [StylePropable, StyleResizable],
render() {
return (
<Tabs>
<Tab
label="Tab 1"
icon={this.isDeviceSize(StyleResizable.statics.Sizes.MEDIUM) ? (<MapsDirectionsRun />) : null}>
Tab 1 content
</Tab>
<Tab
label={this.isDeviceSize(StyleResizable.statics.Sizes.MEDIUM) ? "Tab 2" : null}
icon={<MapsDirectionsRun />}>
Tab 2 content
</Tab>
</Tabs>
)
}
})

Resources