DEV Community

Cover image for How to Use a Javascript Reporting Tool with Next.js
Chelsea Devereaux for GrapeCity, Inc.

Posted on • Originally published at grapecity.com

How to Use a Javascript Reporting Tool with Next.js

Next.js is a React-based framework that provides a well-defined structure for your application and optimizations that make the development process and final application faster. Unlike classic front-end frameworks, such as Angular or Vue, Next.js supports Pre-Rendering of the application’s pages at runtime on the server-side or at building time.

ActiveReportsJS components need a browser environment and cannot work on the server-side or at the building time. However, it’s certainly possible to use ActiveReportsJS components within a Next.js application. This article describes the approach to getting it done.

Using Components Wrappers

Suppose you want to use ActiveReportsJS Report Viewer or Report Designer component in a Next.js application. Implementing a wrapper that encapsulates the component’s functionality and exposes an interface to consume it could be convenient. For example, here is the code of the Report Viewer’s wrapper that exposes, in addition to the built-in Viewer’s properties, the reportUri property that points to a report to be loaded.

import { Viewer } from "@grapecity/activereports-react";
    import { Props as ViewerProps } from "@grapecity/activereports-react";
    import { PdfExport } from "@grapecity/activereports";
    import React from "react";
    // import the default theme for the report viewer
    import "@grapecity/activereports/styles/ar-js-ui.css";
    import "@grapecity/activereports/styles/ar-js-viewer.css";

    // eslint-disable-next-line
    const pdf = PdfExport;

    // eslint-disable-next-line react/display-name
    const ViewerWrapper = (props: ViewerWrapperProps) => {
      const ref = React.useRef<Viewer>(null);
      React.useEffect(() => {
        ref.current?.Viewer.open(props.reportUri);
      }, [props.reportUri]);
      return <Viewer {...props} ref={ref} />;
    };

    export type ViewerWrapperProps = ViewerProps & { reportUri: string };

    export default ViewerWrapper;
Enter fullscreen mode Exit fullscreen mode

Similarly, the wrapper for the Report Designer component could look like the following:

    import { Designer } from "@grapecity/activereports-react";
    import { DesignerProps } from "@grapecity/activereports-react";
    import React from "react";
    import "@grapecity/activereports/styles/ar-js-ui.css";
    import "@grapecity/activereports/styles/ar-js-designer.css";

    // eslint-disable-next-line react/display-name
    const DesignerWrapper = (props: DesignerWrapperProps) => {
      const ref = React.useRef<Designer>(null);
      React.useEffect(() => {
        ref.current?.setReport({id: props.reportUri});
      }, [props.reportUri]);
      return <Designer {...props} ref={ref} />;
    };

    export type DesignerWrapperProps = DesignerProps & { reportUri: string };

    export default DesignerWrapper;
Enter fullscreen mode Exit fullscreen mode

Using Wrappers for API Invocation

Suppose you want to use the ActiveReportsJS API. In that case, it could also be encapsulated within a wrapper that does not render any UI but simply tracks properties' changes and calls the API functions. Here is an example of the PDFExport wrapper:

   import {
      PdfSettings,
      exportDocument,
    } from "@grapecity/activereports/pdfexport";
    import { PageReport } from "@grapecity/activereports/core";

    import React from "react";

    export type PdfExportWrapperProps = PdfSettings & { reportUri: string };

    async function exportReport(props: PdfExportWrapperProps) {
      const pageReport = new PageReport();
      await pageReport.load(props.reportUri);
      const doc = await pageReport.run();
      const res = await exportDocument(doc, props);
      res.download("report.pdf");
    }

    export default function PdfExportWrapper(props: PdfExportWrapperProps) {
      React.useEffect(() => {
          if(props.reportUri?.length)
            exportReport(props);
      }, [props]);
      return null;
    }
Enter fullscreen mode Exit fullscreen mode

Dynamic Loading of Wrappers

Next.js contains the Dynamic Import feature that allows loading components at runtime and prevents server-side rendering. This is required for using ActiveReportsJS components within a Next.js application. Below is the sample of the Next.js Page that displays the Report Viewer component and loads the Products.rdlx-json _report into it. The code assumes the wrapper’s code is in the _components\ReportViewer.tsx file.

    import type { NextPage } from "next";
    import React from "react";
    import styles from "../styles/Home.module.css";
    import { ViewerWrapperProps } from "../components/ReportViewer";

    import dynamic from "next/dynamic";
    const Viewer = dynamic<ViewerWrapperProps>(
      async () => {
        return (await import("../components/ReportViewer")).default;
      },
      { ssr: false }
    );

    const Home: NextPage = () => {
      return (
        <div
          className={styles.container}
          style={{ width: "100%", height: "100vh" }}
        >
          <Viewer reportUri="report.rdlx-json" />
        </div>
      );
    };

    export default Home;
Enter fullscreen mode Exit fullscreen mode

You could use the same approach for API wrappers:

    import type { NextPage } from "next";
    import React from "react";
    import styles from "../styles/Home.module.css";

    import { PdfExportWrapperProps } from "../components/PdfExport";

    import dynamic from "next/dynamic";

    const PdfExportWrapper = dynamic<PdfExportWrapperProps>(
      async () => {
        return (await import("../components/PdfExport")).default;
      },
      { ssr: false }
    );

    const Home: NextPage = () => {
      const [report, setReport] = React.useState<string>("");
      return (
        <div
          className={styles.container}
          style={{ width: "100%", height: "100vh" }}
        >
          <button onClick={() => setReport("report.rdlx-json")}>Export Report</button>
          <PdfExportWrapper reportUri={report} pdfVersion="1.7" />
        </div>
      );
    };

    export default Home;
Enter fullscreen mode Exit fullscreen mode

Discussion (0)