I am trying to add an external div element(Summary Panel) on the right side of the bar chart I have implemented using react-plotly.js.
The div element would pop-up next to the chart when onClick event is fired on the chart. The panel would display the information related to the bar that was clicked. The data object based on which the bar chart is created is:
const barData = [
{ endTime: '', startTime: '', duration: 6, initiatorUsername: 'abc', title: 'abc1', aTitle: 'Manager', outcome: 'Success' },
{ endTime: '1521203405', startTime: '1520389805', duration: 7, initiatorUsername: 'defs', title: 'Senior Analyst', aTitle: 'Manager', outcome: 'Failure' }
];
I haven't seen any such example or any documentation related to add external div element to the chart. Is it possible to link chart to the external div element ?
I did attempt to implement it by doing the following:
<Plot
data={this.prepData(timelineData)}
onClick={(data) => {
this.renderCustomPanel(data);
}
onHover={(hover) => this.getHoverInfo(hover)}
type={'bar'}
layout={layout}
style={{ width: '95%' }}
/>
renderCustomPanel(e) {
const panelInfo = timelineData.map(i => `<span className="panel-info">
<span className="tooltip-value" style='font-size:15px;display:block'>${i.duration} days <br> Start time: ${moment.unix(i.startTime).format('MMM-DD-YYYY h:mm:ss')} <br> End time:${moment.unix(i.endTime).format('MMM-DD-YYYY h:mm:ss')}</span></span>`);
return panelInfo;
}
The onClick function does call the function but doesn't display the div element. I did try applying css styles to the element but nothing works. Firstly, how do I make a panel display onClick?
Alternate solution that comes to my mind is to make panel a separate sibling component. In that case, How do I pass the data to it such that in the description section it displays the information related to the bar that was clicked ?
class SummaryPanel extends Component {
constructor(props) {
super(props);
this.state = {
isActive: true
};
}
render() {
return (
<div className='summaryPanel'>
<Card
label='Summary panel'
heading=''
description=''
/>
<button type="button" className="close" data-dismiss="alert" aria-label="Close" onClick={() => this.hideAlert()}><span aria-hidden="true">×</span></button>
</div>
);
}
}
Related
I have built a custom tree view in React, and each item contains a dropdown which is positioned using Popper. Since the child elements are not visible on render, Popper is not positioning the dropdown correctly, for example:
When the tree is open on mount (i.e the children are visible), the positioning is correct:
Each level in the tree is rendered via a CategoryNavItem component, which essentially looks like this:
<div className={ className.join(' ') }>
<div className={ `collection-nav_item-link depth${depth}` } style={{ paddingLeft: `${paddingLeft}px`}}>
<Link to={ linkTo } onClick={() => { setIsOpen(!isOpen) }}>
<i className="collection-nav_item-link_icon"></i>
<span className="collection-nav_item-link_text">{ category.name }</span>
</Link>
<Dropdown
toggleClassName="btn-icon-white btn-sm"
toggleContent={ <Icon name="ellipsis-h" />}
position="bottom-end"
size="small"
items={[
{ text: 'Edit category' },
{ text: 'Add subcategory', onClick: (() => { dispatch(openAddSubcategory(category)) }) }
]} />
</div>
{ children }
</div>
The Dropdown component is where we use Popper, and it works well everywhere else. The visibility of a CategoryNavItem is handled via the component's state in React.
Is there any way to trigger Popper's update() method programmatically in React? We should force update when toggling the item's visibility.
It turns out we just need to expose the update property from the usePopper hook, and then call it when setting the dropdown's visibility, for example:
const { styles, attributes, update } = usePopper(referenceElement, popperElement, {
placement: placement,
modifiers: [
{ name: 'arrow', options: { element: arrowElement } },
{ name: 'offset', options: { offset: [ 0, 3 ] } }
]
});
And similarly:
const toggleDropdown = (e) => {
e.preventDefault();
e.stopPropagation();
setVisible(!visible);
update();
};
According to the docs, you can manually update the propper instance so that it recomputes the tooltip position:
Manual update
You can ask Popper to recompute your tooltip's position by running instance.update().
This method will return a promise, that will be resolved with the updated State, from where you will optionally be able to read the updated positions.
const state = await popperInstance.update();
When clicking on your item visibility toggle, you could add your popper manual update, like the line of code above.
Here is the reference.
I am trying to add a hyperlink to the cell data Summary which when clicked can open a popover in one of the column.
const columns = [
{
title: 'Name',
data: 'name',
searchable: true
},
{
title: 'Summary',
data: 'instanceName',
searchable: true,
render: (data, type, row) => `
<div>
<p style="color: green">Applied- ${this.calculatecount(row.name)}</p>
</div>
`
];
How to make this Applied - (count) an hyperlink and when clicked should show a popover.
the number of the instances can be large so need to show the list in the popover.
<Popover title="Successfully Applied">
<div>
<p style="color: green">Names of the instances applied</p>
</div>
</Popover>
I am very new to office ui fabric-react and react in general so don't hesitate to give me pointers if I am doing it totally wrong.
Although my requirement is fairly simple, I just can't get it figured out.
I have a page with a list view (DetailsList Component of office-ui-fabric-reactjs), this DetailsList get it's items from an API endpoint which is working fine:
componentDidMount() {
_items = []
// Get list of Mediums, then push it to the _items array
axiosTRS.get('/media').then(response => {
response.data.map(item => {
_items.push({ id: item.mediumID, name: item.name, imo: item.imo })
})
this.setState({ items: _items })
})
}
The DetailsList is being filled perfectly. However, now I want to add a 'EDIT' button to each row, so this is no separate column.
I figured I would do this on the onRenderRow property where the DetailLists get's rendered:
render() {
return (
<div>
<Panel panelHeaderName={'Medium Overview'}>
<div>
<MarqueeSelection selection={this.selection} >
<DetailsList
onRenderRow={this.onRenderRows}
onRenderDetailsHeader={this.onRenderColumn}
selection={this.selection}
selectionMode={this.state.selectionMode}
onColumnHeaderClick={this.sorting}
onColumnResize={this.columnResizer}
layoutMode={DetailsListLayoutMode.justified}
className='customPanel'
columns={this.state.columns}
items={this.state.items}
// onRenderItemColumn={ this._onRenderColumn }
/>
</MarqueeSelection>
<br />
<div align="right">
</div>
</div>
</Panel>
</div>
)
}
In the onRenderRows function I first get all the DetailsRow props, and then add the Edit button:
onRenderRows(props) {
return (
<div>
<DetailsRow
{...props}
/>
<PrimaryButton
onClick={() => {
alert(props.item.name)
}}
text='click me'
/>
</div>
)
}
The problem is that the button keeps displaying below the row with data. Should I fix this by adding css or what is my best option to get the button on the same row?
Is there an easier way to accomplish this? I also tried / researched the option of adding an extra column for the buttons, but I don't think this is the way to go, and I didn't got that working either.
As a side-note, I am using fabric components with ES6 instead of TSX (as you probably noticed).
Add this function
private _onRenderItemColumn(item: any, index: number, column: IColumn): JSX.Element {
if (column.fieldName === 'fieldName') {
return <Link data-selection-invoke={true}>{"Edit"}</Link>;
}
return item[column.fieldName];
}
using onItemInvoked() of < DetailsList />
setup columns for < DetailsList />
React Components:
constructor(props: {}) {
super(props);
this._columns = [
{ key: 'index', name: 'No.', fieldName: 'index', isResizable: false },
{ key: 'edit', name: 'Edit', fieldName: 'edit', isResizable: false,
onRender: (item) => (
<Link onClick={() => { console.log('clicked', item); }}>Edit</Link>
),
},
]
}
I am using React Big Calendar
https://github.com/intljusticemission/react-big-calendar .
And it has an Drag n Drop option using react-dnd https://github.com/react-dnd/react-dnd . What I am trying to do is to have draggable elements outside of calendar, which I can drag inside the Calendar. Like this : https://codepen.io/kotazi/pen/KVoXob .
class Application extends React.Component {
render() {
return <div><External />
<Calendar /></div>;
}
}
/*
* A simple React component
*/
class Calendar extends React.Component {
render() {
return <div id="calendar"></div>;
}
componentDidMount() {
$('#calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
editable: true,
droppable: true, // this allows things to be dropped onto the calendar
drop: function() {
// is the "remove after drop" checkbox checked?
if ($('#drop-remove').is(':checked')) {
// if so, remove the element from the "Draggable Events" list
$(this).remove();
}
}
})
}
}
class External extends React.Component {
render() {
return <div id='external-events'>
<h4>Draggable Events</h4>
<div className='fc-event'>My Event 1</div>
<div className='fc-event'>My Event 2</div>
<div className='fc-event'>My Event 3</div>
<div className='fc-event'>My Event 4</div>
<div className='fc-event'>My Event 5</div>
<p>
<input type='checkbox' id='drop-remove' />
<label for='drop-remove'>remove after drop</label>
</p>
</div>;
}
componentDidMount() {
$('#external-events .fc-event').each(function() {
// store data so the calendar knows to render an event upon drop
$(this).data('event', {
title: $.trim($(this).text()), // use the element's text as the event title
stick: true // maintain when user navigates (see docs on the renderEvent method)
});
// make the event draggable using jQuery UI
$(this).draggable({
zIndex: 999,
revert: true, // will cause the event to go back to its
revertDuration: 0 // original position after the drag
});
});
}
}
/*
* Render the above component into the div#app
*/
React.render(<Application />, document.getElementById('app'));
Only 'solution' that I have found is this one https://github.com/intljusticemission/react-big-calendar/issues/318 but I have no idea how he did it. I have the same code as drag example http://intljusticemission.github.io/react-big-calendar/examples/index.html#prop-onNavigate . Can someone help me, please?
I have a div with many <p> and <span> inside, is there any example of how to create a show more/less button with ReactJS to adjust the size of a div?
I have tried to install npm read more and npm truncate, but it seems not to solve my problem. Because I have to adjust the size of a div and the text in the button on click in React.
Thanks!
With React you can easily adapt the rendering of your component depending on the state. You can have a boolean in the state (isOpen for example) and toggle the value when you click on the more/less button.
After that, you have just to render X items and change the button text depending on the boolean value.
I made an exemple with datas stored inside an array, but you could easily adapt to your case.
const MAX_ITEMS = 3;
class MoreLessExample extends React.Component{
componentWillMount() {
this.state = {
isOpen: false,
};
this.items = [
'Item 1',
'Item 2',
'Item 3',
'Item 4',
'Item 5',
'Item 6',
];
}
toggle = () => {
this.setState({ isOpen: !this.state.isOpen });
}
getRenderedItems() {
if (this.state.isOpen) {
return this.items;
}
return this.items.slice(0, MAX_ITEMS);
}
render() {
return(
<div>
{this.getRenderedItems().map((item, id) => (
<div key={id}>{item}</div>
))}
<button onClick={this.toggle}>
{this.state.isOpen ? 'less' : 'more'}
</button>
</div>
);
}
}
ReactDOM.render(<MoreLessExample />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
You may want to use react-bootstrap on that. Wrap your div in Collapse component like this...
constructor(){
super();
this.state = { showText: false };
}
render(){
return(
<div>
<p>Some text here...</p>
<a onClick={() => this.setState({ showText: !this.state.showText })>See more</a>
<Collapse in={this.state.showText}>
<div>
<span>
Some more texts here...
</span>
</div>
</Collapse>
</div>
);
}
Check this out https://react-bootstrap.github.io/utilities/transitions/
Here's a Material UI answer:
import { Button, makeStyles } from "#material-ui/core";
import React, { useState } from "react";
const useStyles = makeStyles((theme) => ({
hidden: {
display: "-webkit-box",
WebkitLineClamp: 4,
overflow: "hidden",
WebkitBoxOrient: "vertical"
}
}));
function ReadMore({ children }) {
const classes = useStyles();
const [isHidden, setIsHidden] = useState(true);
return (
<>
<div className={isHidden ? classes.hidden : null}>{children}</div>
<Button size="small" onClick={() => setIsHidden(!isHidden)}>
{isHidden ? "⬇ More" : "⬆ Less"}
</Button>
</>
);
}
export default ReadMore;
And Implement it like this:
<ReadMore>
<Typography>
Hey World, what's up
</Typography>
</ReadMore>
I know this question is a bit old but I figured I would throw in my solution for a simple show more text using functional components which should help get anyone who stumbles across this going in the right direction.
const [showMore, setShowMore] = useState<boolean>(false);
const text = 'CaPay is a super application that includes 68 high qualityscreens to help you launch digital wallet application projects and speed up your design process. Designed on 2 leading platforms Sketch & Figma makes it easy to customize to create impressive projects weee I am longer show more please CaPay is a super application that includes 68 high qualityscreens to help you launch digital wallet application projects and speed up your design process. Designed on 2 leading platforms Sketch & Figma makes it easy to customize to create impressive projects weee I am longer show more please';
const getText = () => {
// For Text that is shorter than desired length
if (text.length <= 258) return text;
// If text is longer than desired length & showMore is true
if (text.length > 258 && showMore) {
return (
<>
<p>{text}</p>
<button
onClick={() => setShowMore(false)}>
Show Less
</button>
</>
);
}
// If text is longer than desired length & showMore is false
if (text.length > 258) {
return (
<>
<p>{text.slice(0, 258)}</p>
<button
onClick={() => setShowMore(true)}>
Show Full Description
</button>
</>
);
}
};
//Then just call in component
<p>{getText()}</p>