I'm having a problem with donut charts in ApexCharts in my React App.
I have an API that returns to me a JSON and I pass this JSON data to some charts. The chart it's showing correct data, but the label isn't showing anything.
If I change something in the ChartComponent, for example, change the 'fontSize' from 15 to 10 the values โโof the labels are shown, but when rendering the screen, they disappear and return to 0.
see here how the graphs are appearing
see here how the graphs are when I change the 'fontSize'
App()
export default function App() {
const referenceDate = new Date();
const currentYear = referenceDate.getFullYear();
const currentMonth = referenceDate.getMonth() + 1;
const currentMonthName = referenceDate.toLocaleString("default", {
month: "long",
});
const [month, setMonth] = useState(currentMonthName);
const [monthId, setMonthId] = useState(currentMonth);
const [apiData, setApiData] = useState();
useEffect(() => {
async function fillData() {
if (month) {
await getData(currentYear, monthId).then((response) =>
setApiData(response)
);
}
}
fillData();
}, [monthId]);
const handleChange = (e) => {
const selectedMonth = e.target.value;
const selectedMonthId = Months[e.target.value].id;
setMonth(selectedMonth);
setMonthId(selectedMonthId);
};
return (
<>
<div className={styles.chartGroup}>
<ChartCard title="Business Unit Head" value={apiData ? apiData['first'] : 0}></ChartCard>
<ChartCard title="Financial" value={apiData ? apiData['second'] : 0}></ChartCard>
</div>
<div className={styles.chartGroup}>
<ChartCard title="Commercial And Pipeline [LATAM]" value={apiData ? apiData['third'] : 0}></ChartCard>
<ChartCard title="Commercial And Pipeline [NAM]" value={apiData ? apiData['fourth'] : 0}></ChartCard>
</div>
<div className={styles.chartGroup}>
<ChartCard title="HR And Recuitment" value={apiData ? apiData['fifth'] : 0}></ChartCard>
<ChartCard title="Delivery" value={apiData ? apiData['sixth] : 0}></ChartCard>
</div>
</div>
</>
);
}
const getData = async (year, month) => (await axiosInstance.get(`/homeChart/${year}/${month}`)).data;
async function generateChartData(data) {
if (data) {
return data;
} else {
console.log("no data");
}
}
ChartComponent
export default function ChartCard(props) {
let progressValue = 0;
let lapseValue = 0;
const data = props.value;
progressValue = data;
lapseValue = 100 - data;
const options = {
colors: ["#0ead69", "#e71d36"],
labels: ["Progress", "Lapse"],
title: {
text: props.title,
align: "center",
style: {
fontSize: "15px",
fontWeight: "normal",
textDecoration: "underline",
},
},
stroke: {
width: 0,
},
legend: {
show: false,
},
dataLabels: {
enabled: false,
},
plotOptions: {
pie: {
expandOnClick: true,
donut: {
background: "white",
labels: {
show: true,
total: {
show: true,
fontSize: "15",
fontWeight: 10,
formatter: function () {
return data + "%";
},
},
name: {
show: false,
},
value: {
show: true,
},
},
},
},
},
};
const series = [progressValue, lapseValue];
return (
<>
<div className={styles.ChartDiv}>
<Chart
data={data}
type="donut"
width="100%"
height={140}
series={series}
options={options}
/>
</div>
</>
);
}
JSON return
{
"first": 4,
"second": 24,
"third": 2.5,
"forth": 9.5,
"fifth": 22,
"sixth": 2
}
Related
I tried to do similar text animation as this lottiefiles website.
My logics was set width and content in object once changed, the css transition will made it look like animation but how to opacity the content before run interval function?
const AnimationComponent = () => {
const [ contents, setContents ] = [
{ id: 1, text: "Collate", width: "140px" },
{ id: 2, text: "Manage", width: "159px" },
{ id: 3, text: "Organise", width: "179px" },
];
const [showText, setShowText] = useState<IAnimate>(animated[0]);
useEffect(() => {
const intervalText = setInterval(() => {
setShowText((prev) => {
const index = prev.id - 1;
if (index === -1) return animated[0];
switch (animated[index].text) {
case "Collate":
return animated[1];
case "Manage":
return animated[2];
case "Organise":
return animated[0];
default:
return animated[0];
}
});
}, 3000);
return () => {
clearInterval(intervalText);
}
}, []);
return (
<Animation as="div">
<AnimateItem
style={{ width: showText.width }}
>
{showText.text}
</AnimateItem>
<span> your</span>
</Animation>
)
}
I'm using draft.js and trying to extract the content with an onClick function and log it to the console. I've spent several hours doing this, but keep getting console errors and I still can't figure out the underlying logic.
Can anyone please offer a guide?
The code is just the default draft.js one with my function and a button added:
import React from "react";
import { Editor, EditorState, getDefaultKeyBinding, RichUtils } from "draft-js";
import "./draft.css";
class TextEditor extends React.Component {
constructor(props) {
super(props);
this.state = { editorState: EditorState.createEmpty() };
this.focus = () => this.refs.editor.focus();
this.onChange = (editorState) => this.setState({ editorState });
this.handleKeyCommand = this._handleKeyCommand.bind(this);
this.mapKeyToEditorCommand = this._mapKeyToEditorCommand.bind(this);
this.toggleBlockType = this._toggleBlockType.bind(this);
this.toggleInlineStyle = this._toggleInlineStyle.bind(this);
}
_handleKeyCommand(command, editorState) {
const newState = RichUtils.handleKeyCommand(editorState, command);
if (newState) {
this.onChange(newState);
return true;
}
return false;
}
_mapKeyToEditorCommand(e) {
if (e.keyCode === 9 /* TAB */) {
const newEditorState = RichUtils.onTab(
e,
this.state.editorState,
4 /* maxDepth */
);
if (newEditorState !== this.state.editorState) {
this.onChange(newEditorState);
}
return;
}
return getDefaultKeyBinding(e);
}
_toggleBlockType(blockType) {
this.onChange(RichUtils.toggleBlockType(this.state.editorState, blockType));
}
_toggleInlineStyle(inlineStyle) {
this.onChange(
RichUtils.toggleInlineStyle(this.state.editorState, inlineStyle)
);
}
render() {
const { editorState } = this.state;
// If the user changes block type before entering any text, we can
// either style the placeholder or hide it. Let's just hide it now.
let className = "RichEditor-editor";
var contentState = editorState.getCurrentContent();
if (!contentState.hasText()) {
if (contentState.getBlockMap().first().getType() !== "unstyled") {
className += " RichEditor-hidePlaceholder";
}
}
return (
<div className="RichEditor-root">
<BlockStyleControls
editorState={editorState}
onToggle={this.toggleBlockType}
/>
<InlineStyleControls
editorState={editorState}
onToggle={this.toggleInlineStyle}
/>
<div className={className} onClick={this.focus}>
<Editor
blockStyleFn={getBlockStyle}
customStyleMap={styleMap}
editorState={editorState}
handleKeyCommand={this.handleKeyCommand}
keyBindingFn={this.mapKeyToEditorCommand}
onChange={this.onChange}
placeholder="Tell a story..."
ref="editor"
spellCheck={true}
/>
</div>
</div>
);
}
}
function handleOnClick(e) {
const content = this.state.editorState.getCurrentContent();
console.log(content);
e.preventDefault();
console.log(EditorState.getCurrentContent);
}
// Custom overrides for "code" style.
const styleMap = {
CODE: {
backgroundColor: "rgba(0, 0, 0, 0.05)",
fontFamily: '"Inconsolata", "Menlo", "Consolas", monospace',
fontSize: 16,
padding: 2,
},
};
function getBlockStyle(block) {
switch (block.getType()) {
case "blockquote":
return "RichEditor-blockquote";
default:
return null;
}
}
class StyleButton extends React.Component {
constructor() {
super();
this.onToggle = (e) => {
e.preventDefault();
this.props.onToggle(this.props.style);
};
}
render() {
let className = "RichEditor-styleButton";
if (this.props.active) {
className += " RichEditor-activeButton";
}
return (
<span className={className} onMouseDown={this.onToggle}>
{this.props.label}
</span>
);
}
}
const BLOCK_TYPES = [
{ label: "H1", style: "header-one" },
{ label: "H2", style: "header-two" },
{ label: "H3", style: "header-three" },
{ label: "H4", style: "header-four" },
{ label: "H5", style: "header-five" },
{ label: "H6", style: "header-six" },
{ label: "Blockquote", style: "blockquote" },
{ label: "UL", style: "unordered-list-item" },
{ label: "OL", style: "ordered-list-item" },
{ label: "Code Block", style: "code-block" },
];
const BlockStyleControls = (props) => {
const { editorState } = props;
const selection = editorState.getSelection();
const blockType = editorState
.getCurrentContent()
.getBlockForKey(selection.getStartKey())
.getType();
return (
<div className="RichEditor-controls">
{BLOCK_TYPES.map((type) => (
<StyleButton
key={type.label}
active={type.style === blockType}
label={type.label}
onToggle={props.onToggle}
style={type.style}
/>
))}
</div>
);
};
var INLINE_STYLES = [
{ label: "Bold", style: "BOLD" },
{ label: "Italic", style: "ITALIC" },
{ label: "Underline", style: "UNDERLINE" },
{ label: "Monospace", style: "CODE" },
];
const InlineStyleControls = (props) => {
const currentStyle = props.editorState.getCurrentInlineStyle();
return (
<div className="RichEditor-controls">
{INLINE_STYLES.map((type) => (
<StyleButton
key={type.label}
active={currentStyle.has(type.style)}
label={type.label}
onToggle={props.onToggle}
style={type.style}
/>
))}
<input type="submit" onClick={handleOnClick} />
</div>
);
};
export default TextEditor;
I have a case regarding the onclick button to open the "choose template" sidebar.
the interface is like this.
So when the button is pressed, the "choose template" sidebar will appear.
However, when I click the button, the sidebar won't appear. do you think that's why? is there something wrong with my coding? Thank you
My Code=
Editor.jsx
import { useEffect, useRef, useState } from "react";
import { useRouter } from "next/router";
import styles from "./Editor.module.scss";
import PropTypes from "prop-types";
import { Button } from "../../global/Button";
import ColorPicker from "./ColorPicker";
import "react-edit-text/dist/index.css";
import RightArrow from "../../../public/images/qrcode/rightArrow.svg";
let qrCode;
if (typeof window !== "undefined") {
console.log("i am client");
const QRCodeStyling = require("qr-code-styling");
qrCode = new QRCodeStyling({
width: 1000,
height: 1000,
margin: 50,
qrOptions: { typeNumber: "0", mode: "Byte", errorCorrectionLevel: "Q" },
imageOptions: { hideBackgroundDots: true, imageSize: 0.2, margin: 10 },
dotsOptions: {
type: "rounded",
color: "#756ce0",
gradient: {
type: "radial",
rotation: 0,
colorStops: [
{ offset: 0, color: "#aa80f9" },
{ offset: 1, color: "#756ce0" },
],
},
},
backgroundOptions: { color: "#ffffff", gradient: null },
image: "https://i.ibb.co/SrpHzTQ/icon-200px.png",
dotsOptionsHelper: {
colorType: { single: true, gradient: false },
gradient: { linear: true, radial: false, color1: "#6a1a4c", color2: "#6a1a4c", rotation: "0" },
},
cornersSquareOptions: { type: "extra-rounded", color: "#756ce0" },
cornersSquareOptionsHelper: {
colorType: { single: true, gradient: false },
gradient: { linear: true, radial: false, color1: "#000000", color2: "#000000", rotation: "0" },
},
cornersDotOptions: { type: "", color: "#613583", gradient: null },
cornersDotOptionsHelper: {
colorType: { single: true, gradient: false },
gradient: { linear: true, radial: false, color1: "#000000", color2: "#000000", rotation: "0" },
},
backgroundOptionsHelper: {
colorType: { single: true, gradient: false },
gradient: { linear: true, radial: false, color1: "#ffffff", color2: "#ffffff", rotation: "0" },
},
});
}
import { BsFileEarmarkPdfFill } from "react-icons/bs";
import { IoIosArrowBack } from "react-icons/io";
const Editor = ({ isResponsive, template, list, merchant, setActive, color, toggleClick }) => {
const { Template } = template;
const warna = "linear-gradient(180deg, #aa80f9 0%, #756ce0 100%)";
const router = useRouter();
const qrRef = useRef();
const [colorProps, setColorProps] = useState(warna);
useEffect(() => {
setTimeout(() => {
if (qrRef.current) qrCode.append(qrRef.current);
}, 100);
}, [Template]);
useEffect(() => {
qrCode.update({
data: process.env.NEXT_PUBLIC_SHARE_URL + "/" + router.query.shareKey,
});
}, [Template]);
// const handleklik = (e) => {
// console.log('Free pizza!');
// }
return (
<>
<div className={styles.container}>
<ColorPicker colorProps={color} callback={(event) => setColorProps(event)} />
<Button onClick={toggleClick} className={styles.button}>
Open Template
</Button>
<IoIosArrowBack
className={styles.arrow + " " + styles.back}
onClick={() => {
setActive(template.id === 0 ? list.length - 1 : template.id - 1);
}}
/>
<div className={styles.paper_container}>
<Template qrRef={qrRef} merchant={merchant} color={colorProps.hex} isResponsive={isResponsive} />
<div className={styles.paper_overlay} id="paper-overlay">
<BsFileEarmarkPdfFill />
<span>Generating PDF</span>
</div>
</div>
<RightArrow
className={styles.arrow + " " + styles.next}
onClick={() => {
setActive(template.id === list.length - 1 ? 0 : template.id + 1);
}}
/>
</div>
</>
);
};
Editor.propTypes = {
template: PropTypes.string,
list: PropTypes.string,
merchant: PropTypes.string,
setActive: PropTypes.string,
color: PropTypes.string,
isResponsive: PropTypes.bool,
toggleClick: PropTypes.func,
};
export default Editor;
Template.jsx
import { useState, useEffect } from "react";
import Image from "next/image";
import styles from "./Template.module.scss";
import PropTypes from "prop-types";
import { FaCheck } from "react-icons/fa";
import { Button } from "../../global/Button";
const Card = ({ data, active, setActive }) => {
return (
<div className={styles.card} onClick={() => setActive(data.id)}>
<Image src={data.image} alt={"template " + data.id} width={116} height={164} />
{active === data.id && (
<div className={styles.overlay}>
<FaCheck />
</div>
)}
</div>
);
};
const Template = ({ list, active, setActive, download }) => {
const [isResponsive, setResponsive] = useState(typeof window !== "undefined" ? window.innerWidth <= 800 : false);
const [isHide, setHide] = useState(true);
useEffect(() => {
const handleResize = () => {
if (window.innerWidth <= 800) {
setResponsive(true);
} else {
setResponsive(false);
}
};
if (window !== "undefined") window.addEventListener("resize", handleResize);
}, []);
useEffect(() => {
setHide(true);
}, [isResponsive]);
return (
<div className={styles.container}>
<div className={styles.card_container} style={{ right: isHide ? null : 0, position: isResponsive && "fixed" }}>
{isResponsive && !isHide && <div className={styles.template_overlay} onClick={() => setHide(true)} />}
<h3>Pilih Template</h3>
{list.map((template) => {
return <Card data={template} key={template.id} active={active} setActive={setActive} />;
})}
</div>
<Button onClick={download} className={styles.button}>
DOWNLOAD
</Button>
</div>
);
};
Card.propTypes = {
data: PropTypes.string,
active: PropTypes.string,
setActive: PropTypes.string
};
Template.propTypes = {
list: PropTypes.string,
active: PropTypes.string,
setActive: PropTypes.string,
download: PropTypes.string,
isResponsive: PropTypes.bool
};
export default Template;
[sharekey].jsx
import { useState, useEffect } from "react";
import { jsPDF } from "jspdf";
import html2canvas from "html2canvas";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
import styles from "./Qrcode.module.scss";
import { useRecoilValue } from "recoil";
import { userProfile } from "../../../utils/recoil";
import Sidebar from "../../../components/global/Wrapper/Sidebar/index";
import Editor from "../../../components/edit-survey/qrcode/Editor";
import Template from "../../../components/edit-survey/qrcode/Template";
import TemplateOne from "../../../components/edit-survey/qrcode/template/One";
import TemplateTwo from "../../../components/edit-survey/qrcode/template/Two";
import TemplateThree from "../../../components/edit-survey/qrcode/template/Three";
import TemplateFour from "../../../components/edit-survey/qrcode/template/Four";
import TemplateFive from "../../../components/edit-survey/qrcode/template/Five";
import TemplateSix from "../../../components/edit-survey/qrcode/template/Six";
const Template1 = "/images/qrcode/Template1.jpg";
const Template2 = "/images/qrcode/Template2.jpg";
const Template3 = "/images/qrcode/Template3.jpg";
const Template4 = "/images/qrcode/Template4.jpg";
const Template5 = "/images/qrcode/Template5.jpg";
const Template6 = "/images/qrcode/Template6.jpg";
const templateList = [
{ Template: TemplateOne, id: 0, image: Template1 },
{ Template: TemplateTwo, id: 1, image: Template2 },
{ Template: TemplateThree, id: 2, image: Template3 },
{ Template: TemplateFour, id: 3, image: Template4 },
{ Template: TemplateFive, id: 4, image: Template5 },
{ Template: TemplateSix, id: 5, image: Template6 },
];
const color = {
r: "170",
g: "128",
b: "249",
a: "1",
};
const Qrcode = () => {
const [activeTemplate, setActiveTemplate] = useState(0);
const profile = useRecoilValue(userProfile);
const [isResponsive, setResponsive] = useState(typeof window !== "undefined" ? window.innerWidth <= 800 : false);
const [isHide, setHide] = useState(true);
useEffect(() => {
const handleResize = () => {
if (window.innerWidth <= 800) {
setResponsive(true);
} else {
setResponsive(false);
}
};
if (window !== "undefined") window.addEventListener("resize", handleResize);
}, []);
useEffect(() => {
setHide(true);
}, [isResponsive]);
const download = () => {
const paper = document.getElementById("paper-pdf");
const overlay = document.getElementById("paper-overlay");
overlay.style.display = "flex";
paper.style.transform = "scale(2)";
html2canvas(paper).then((canvas) => {
const imgData = canvas.toDataURL("image/jpg");
const pdf = new jsPDF({
orientation: "potrait",
unit: "pt",
format: "a5",
});
const imgProps = pdf.getImageProperties(imgData);
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
pdf.addImage(imgData, "JPG", 0, 0, pdfWidth, pdfHeight);
pdf.save("QRCode.pdf");
paper.style.transform = null;
overlay.style.display = null;
});
};
return (
<Sidebar style={{ paddingTop: 0, paddingBottom: 0, paddingRight: 0 }}>
<div className={styles.container}>
<Editor
color={color}
template={templateList[activeTemplate]}
list={templateList}
merchant={profile.merchant}
setActive={setActiveTemplate}
toggleClick={() => setHide(!isHide)}
isResponsive={isResponsive}
/>
<Template list={templateList} active={activeTemplate} setActive={setActiveTemplate} download={download} isResponsive={isResponsive} />
</div>
</Sidebar>
);
};
export const getServerSideProps = async ({ locale }) => ({
props: {
...(await serverSideTranslations(locale, ["common", "edit-survey"])),
},
});
export default Qrcode;
you should pass down the isHide and setIsHide down to Template component. and remove the isHide, setIsHide useState from the Template component
so in [sharekey].jsx
<Template list={templateList} active={activeTemplate} setActive={setActiveTemplate} download={download} isResponsive={isResponsive} isHide={isHide} setIsHide={setIsHide}/>
I have two issues.
Onload, the bottom links should render only once, but they are rendered twice.
When clicking the box links at the bottom, the current links should smoothly fade out and the new ones fade in.
Instead, the new ones initially fade in stacked with the previous ones.
what am I doing wrong here?
Sandbox Link
Relevant animation code:
export default function DynamicScreen({}: IProps) {
const { screenKey } = useParams()
const [isLeavingScreen, setIsLeavingScreen] = useState(false)
const [screen, setScreen] = useState<IDynamicScreen>()
const [screenLinks, setScreenLinks] = useState<IDynamicScreenLink[]>([])
const navigate = useNavigate()
const isFirstRenderRef = useRef(true)
useEffect(() => {
if (isFirstRenderRef.current) {
isFirstRenderRef.current = false
return
}
}, [])
useEffect(() => {
const loadScreen = async () => {
console.log("Screen - Loading")
const { data: _screen } = await api.getScreen(screenKey!)
setScreen(_screen)
setScreenLinks(
[_screen.link1?.[0], _screen.link2?.[0], _screen.link3?.[0]].filter(
Boolean,
),
)
console.log("Screen - Loaded")
}
loadScreen()
}, [screenKey])
const springApiLory = useSpringRef()
const springLoryStyle = useSpring({
from: { opacity: 0, scale: 0 },
to: { opacity: 1, scale: 1 },
ref: springApiLory,
})
const springApiTitle = useSpringRef()
const springTitleStyle = useSpring({
from: { opacity: 0, transform: "translateY(-25px)" },
to: !isLeavingScreen
? { opacity: 1, transform: "translateY(0)" }
: {
opacity: 0,
transform: "translateY(-25px)",
},
ref: springApiTitle,
})
const springApiScriptHtml = useSpringRef()
const springScriptHtmlStyle = useSpring({
from: { opacity: 0, transform: "translateX(-25px)" },
to: !isLeavingScreen
? { opacity: 1, transform: "translateY(0)" }
: {
opacity: 0,
transform: "translateX(-25px)",
},
ref: springApiScriptHtml,
})
const springApiLinks = useSpringRef()
const linkTransition = useTransition(isLeavingScreen ? [] : screenLinks, {
ref: springApiLinks,
from: { opacity: 0 },
enter: { opacity: 1 },
leave: isLeavingScreen ? { opacity: 0 } : {},
trail: 100,
})
const chain = [
springApiLory,
springApiTitle,
springApiScriptHtml,
springApiLinks,
]
useChain(
!isLeavingScreen ? chain : chain.reverse(),
[...Array(chain.length).keys()].map(calcStaggerDelay),
)
const goToLink = (link: string) => {
setIsLeavingScreen(true)
setTimeout(() => {
setScreenLinks([])
navigate(`/${link}`)
setIsLeavingScreen(false)
}, 1000)
}
if (!screen) return null
return (
<>
<div className="dynamic-screen-top">
<div className="left">
<animated.div style={springTitleStyle}>
<h1>{screen.title}</h1>
</animated.div>
<animated.div style={springScriptHtmlStyle}>
<div
dangerouslySetInnerHTML={{
__html: screen.scriptHtml,
}}
/>
</animated.div>
{/* TODO screen.actions */}
</div>
<animated.div style={springLoryStyle} className="right">
๐โโ๏ธ
</animated.div>
</div>
<div className="dynamic-screen-bottom">
{linkTransition((style, screenLink) => (
<animated.div
style={style}
className="dynamic-screen-bottom-link-wrap"
>
<DynamicScreenLink
linkKey={screenLink!.key}
onClick={goToLink}
text={screenLink!.text}
imageUrl={screenLink!.imageUrl}
size={screenLink!.size}
/>
</animated.div>
))}
</div>
</>
)
}
interface IProps {}
const calcStaggerDelay = (i: number) => i * 0.1 + 0.1
I don't know if this helps you continue, but what i did first of all is to set screenLinks the to an empty array when navigating to new page
const goToLink = (link: string) => {
setScreenLinks([]);
setIsLeavingScreen(true);
setTimeout(() => {
navigate(`/${link}`);
setIsLeavingScreen(false);
}, 300);
};
and also, if isLeavingScreen, then set the width to zero, in order for the next screenLinks to take whole space
const linkTransition = useTransition(isLeavingScreen ? [] : screenLinks, {
ref: springApiLinks,
from: { opacity: 0 },
enter: { opacity: 1 },
leave: isLeavingScreen ? { display: "none", width: 0 } : {},
trail: 100
});
demo
Can anybody send code on how to implement fluent UI details List in Functional Component(https://developer.microsoft.com/en-us/fluentui#/controls/web/detailslist/basic) and how to fetch data from API to details List
That's a start you will need to "refact" this code by the way this is a really good practice :
import * as React from "react";
import { Announced } from "office-ui-fabric-react/lib/Announced";
import {
TextField,
ITextFieldStyles
} from "office-ui-fabric-react/lib/TextField";
import {
DetailsList,
DetailsListLayoutMode,
Selection,
IColumn
} from "office-ui-fabric-react/lib/DetailsList";
import { MarqueeSelection } from "office-ui-fabric-react/lib/MarqueeSelection";
import { Fabric } from "office-ui-fabric-react/lib/Fabric";
import { mergeStyles } from "office-ui-fabric-react/lib/Styling";
import { Text } from "office-ui-fabric-react/lib/Text";
const exampleChildClass = mergeStyles({
display: "block",
marginBottom: "10px"
});
const textFieldStyles: Partial<ITextFieldStyles> = {
root: { maxWidth: "300px" }
};
export interface IDetailsListBasicExampleItem {
key: number;
name: string;
value: number;
}
export interface IDetailsListBasicExampleState {
items: IDetailsListBasicExampleItem[];
selectionDetails: string;
}
export const DetailsListBasicExampleFunction: React.FunctionComponent<
{} | IDetailsListBasicExampleState
> = () => {
const _allItems: IDetailsListBasicExampleItem[] = [];
const [selection, setSelection] = React.useState<Selection | undefined>();
function _getSelectionDetails(): string {
const selectionCount = selection ? selection.getSelectedCount() : 0;
switch (selectionCount) {
case 0:
return "No items selected";
case 1:
return (
"1 item selected: " +
(selection.getSelection()[0] as IDetailsListBasicExampleItem).name
);
default:
return `${selectionCount} items selected`;
}
}
const [state, setState] = React.useState({
items: _allItems,
selectionDetails: _getSelectionDetails()
});
React.useEffect(() => {
const _selection: Selection = new Selection({
onSelectionChanged: () =>
setState((prev) => {
return { ...prev, selectionDetails: _getSelectionDetails() };
})
});
setSelection(_selection);
for (let i = 0; i < 200; i++) {
_allItems.push({
key: i,
name: "Item " + i,
value: i
});
}
setState((prev) => {
return { ...prev, items: _allItems };
});
}, []);
const _columns: IColumn[] = [
{
key: "column1",
name: "Name",
fieldName: "name",
minWidth: 100,
maxWidth: 200,
isResizable: true
},
{
key: "column2",
name: "Value",
fieldName: "value",
minWidth: 100,
maxWidth: 200,
isResizable: true
}
];
// Populate with items for demos.
const _onFilter = (
ev: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>,
text: string
): void => {
console.log(text);
setState((prev) => {
return {
...prev,
items: text
? _allItems.filter((i) => i.name.toLowerCase().indexOf(text) > -1)
: _allItems
};
});
};
const _onItemInvoked = (item: IDetailsListBasicExampleItem): void => {
alert(`Item invoked: ${item.name}`);
};
return selection ? (
<Fabric>
<div className={exampleChildClass}>{state.selectionDetails}</div>
<Text>
Note: While focusing a row, pressing enter or double clicking will
execute onItemInvoked, which in this example will show an alert.
</Text>
<Announced message={state.selectionDetails} />
<TextField
className={exampleChildClass}
label="Filter by name:"
onChange={(e, t) => _onFilter(e, t ?? "")}
styles={textFieldStyles}
/>
<Announced
message={`Number of items after filter applied: ${state.items.length}.`}
/>
<MarqueeSelection selection={selection}>
<DetailsList
items={state.items}
columns={_columns}
setKey="set"
layoutMode={DetailsListLayoutMode.justified}
selection={selection}
selectionPreservedOnEmptyClick={true}
ariaLabelForSelectionColumn="Toggle selection"
ariaLabelForSelectAllCheckbox="Toggle selection for all items"
checkButtonAriaLabel="select row"
onItemInvoked={_onItemInvoked}
/>
</MarqueeSelection>
</Fabric>
) : (
<div>Loading</div>
);
};
UPDATE
To pass this sample of code in JSX this is pretty easy you just need to remove all type thing.
And to fetch data I use axios.
see the code below:
import * as React from "react";
import { Announced } from "office-ui-fabric-react/lib/Announced";
import { TextField } from "office-ui-fabric-react/lib/TextField";
import {
DetailsList,
DetailsListLayoutMode,
Selection
} from "office-ui-fabric-react/lib/DetailsList";
import { MarqueeSelection } from "office-ui-fabric-react/lib/MarqueeSelection";
import { Fabric } from "office-ui-fabric-react/lib/Fabric";
import { mergeStyles } from "office-ui-fabric-react/lib/Styling";
import { Text } from "office-ui-fabric-react/lib/Text";
import axios from "axios";
const exampleChildClass = mergeStyles({
display: "block",
marginBottom: "10px"
});
const textFieldStyles = {
root: { maxWidth: "300px" }
};
export const DetailsListBasicExampleFunction = () => {
const _allItems = [];
const [selection, setSelection] = React.useState();
function _getSelectionDetails() {
const selectionCount = selection ? selection.getSelectedCount() : 0;
switch (selectionCount) {
case 0:
return "No items selected";
case 1:
return "1 item selected: " + selection.getSelection()[0].name;
default:
return `${selectionCount} items selected`;
}
}
const [state, setState] = React.useState({
items: _allItems,
selectionDetails: _getSelectionDetails()
});
React.useEffect(() => {
const _selection = new Selection({
onSelectionChanged: () =>
setState((prev) => {
return { ...prev, selectionDetails: _getSelectionDetails() };
})
});
setSelection(_selection);
//********************** */fetch data from api***************************************
axios
.get("/data.json") //pass your url in param
.then((res) =>
setState((prev) => {
return { ...prev, items: res.data };
})
); //pass data in setState
}, []);
const _columns = [
{
key: "column1",
name: "Name",
fieldName: "name",
minWidth: 100,
maxWidth: 200,
isResizable: true
},
{
key: "column2",
name: "Value",
fieldName: "value",
minWidth: 100,
maxWidth: 200,
isResizable: true
}
];
// Populate with items for demos.
const _onFilter = (ev, text) => {
console.log(text);
setState((prev) => {
return {
...prev,
items: text
? _allItems.filter((i) => i.name.toLowerCase().indexOf(text) > -1)
: _allItems
};
});
};
const _onItemInvoked = (item) => {
alert(`Item invoked: ${item.name}`);
};
return selection ? (
<Fabric>
<div className={exampleChildClass}>{state.selectionDetails}</div>
<Text>
Note: While focusing a row, pressing enter or double clicking will
execute onItemInvoked, which in this example will show an alert.
</Text>
<Announced message={state.selectionDetails} />
<TextField
className={exampleChildClass}
label="Filter by name:"
onChange={(e, t) => _onFilter(e, t ?? "")}
styles={textFieldStyles}
/>
<Announced
message={`Number of items after filter applied: ${state.items.length}.`}
/>
<MarqueeSelection selection={selection}>
<DetailsList
items={state.items}
columns={_columns}
setKey="set"
layoutMode={DetailsListLayoutMode.justified}
selection={selection}
selectionPreservedOnEmptyClick={true}
ariaLabelForSelectionColumn="Toggle selection"
ariaLabelForSelectAllCheckbox="Toggle selection for all items"
checkButtonAriaLabel="select row"
onItemInvoked={_onItemInvoked}
/>
</MarqueeSelection>
</Fabric>
) : (
<div>Loading</div>
);
};