tradingview / charting-library-examples

Examples of Charting Library integrations with other libraries, frameworks and data transports
MIT License
1.33k stars 744 forks source link

cannot read UDFCompatibleDataFeed in next js #310

Closed samuelzega closed 1 year ago

samuelzega commented 1 year ago

what i do to integrate trading view to our own project (NEXT JS):

import React from 'react';
import dynamic from 'next/dynamic';

const TVChartContainer = dynamic(
    () =>
        import('../../components/organism/TVChartContainer').then(mod => mod.TVChartContainer),
    { ssr: false },
);

const Index = () => {
    return (<TVChartContainer />);
};

export default Index;
edew commented 1 year ago

Well window.Datafeeds won't be defined by default.

You have to reference the datafeeds bundle script or import the datafeeds in another way that makes sense for you project.

samuelzega commented 1 year ago

can i have example to import or reference datafeed @edew

edew commented 1 year ago

You can check the example in this repository https://github.com/tradingview/charting-library-examples/blob/master/nextjs-javascript/pages/_document.js

samuelzega commented 1 year ago

wahh its solved, before i put the _document.js in pages folder, thank you

btw can i ask one more question. I try to search about some stock but not exist. What should i do, so i can get full access for indonesian stock code. @edew

edew commented 1 year ago

The Charting Library is meant to be used with your own source of market data. We don't provide the data.

0xAskar commented 1 year ago

@edew @samuelzega if i put my _document.js in my pages folders, does the route for the Script tag still stay the same? I have my chart_library and my datafeeds folders inside root/public/static/chart_library and root/public/static/datafeeds while my _document.js is in pages where its located in root/pages/_document.js. but, i'm still getting the same window.datafeeds undefined error despite importing it in

update: the script is now working somehow, i tried to double check it; however, i'm getting this error:

image

any idea why? Here's my component code:

import React, { createRef } from 'react';
import Styles from "./index.module.css"
import {
  widget,
  ChartingLibraryWidgetOptions,
} from '../../public/static/charting_library';

const getLanguageFromURL = ()=> {
  const regex = new RegExp('[\\?&]lang=([^&#]*)');
  const results = regex.exec(location.search);
  return results === null
    ? null
    : (decodeURIComponent(
        results[1].replace(/\+/g, ' '),
      ));
};

export class TVChartContainer extends React.PureComponent {
  tvWidget = null;
  ref= createRef();
  componentDidMount() {
    console.log(window.Datafeeds)
    const widgetOptions = {
        symbol: 'AAPL',
        interval: 'D',
        // datafeedUrl: 'https://demo_feed.tradingview.com',
        datafeedUrl: new window.Datafeeds.UDFCompatibleDatafeed('https://demo_feed.tradingview.com'),
        libraryPath: '/static/charting_library/',
        chartsStorageUrl: 'https://saveload.tradingview.com',
        chartsStorageApiVersion: '1.1',
        clientId: 'tradingview.com',
        userId: 'public_user_id',
        fullscreen: false,
        autosize: true,
        studiesOverrides: {},
}   
console.log(widgetOptions.datafeedUrl)

    const tvWidget = new widget(widgetOptions);
    this.tvWidget = tvWidget;
    console.log("are we in here?")
    tvWidget.onChartReady(() => {
        console.log("hello?")
      tvWidget.headerReady().then(() => {
        const button = tvWidget.createButton();
        button.setAttribute(
          'title',
          'Click to show a notification popup',
        );
        button.classList.add('apply-common-tooltip');
        button.addEventListener('click', () =>
          tvWidget.showNoticeDialog({
            title: 'Notification',
            body: 'TradingView Charting Library API works correctly',
            callback: () => {
            },
          }),
        );
        button.innerHTML = 'Check API';
      });
    });
  }

  componentWillUnmount() {
    if (this.tvWidget !== null) {
      this.tvWidget.remove();
      this.tvWidget = null;
    }
  }

  render() {
    return (
      <div>
        <div ref={this.ref} className={Styles.TVChartContainer} />
      </div>
    );
  }
}
sniper365 commented 1 year ago

You can check the example in this repository https://github.com/tradingview/charting-library-examples/blob/master/nextjs-javascript/pages/_document.js

Is there any nextjs-typescript example? I mixed nextjs-javascript and react-typescript for my Next 13/typescript project.

Btw still error UDFCompatibleDataFeed...

//components/layout/Head.tsx

import NextHead from 'next/head'
import { useRouter } from 'next/router'
import Script from 'next/script'

/**
 * Constants & Helpers
 */
export const WEBSITE_HOST_URL = 'https://...app'

/**
 * Prop Types
 */
export interface MetaProps {
  description?: string
  image?: string
  title: string
  type?: string
}

/**
 * Component
 */
export const Head = ({
  customMeta,
}: {
  customMeta?: MetaProps
}): JSX.Element => {
  const router = useRouter()
  const meta: MetaProps = {
    title: 'Next.js ',
    description: 'Next.js ',
    image: `${WEBSITE_HOST_URL}/images/site-preview.png`,
    type: 'website',
    ...customMeta,
  }

  return (
    <NextHead>
      <title>{meta.title}</title>
      <Script src="/static/charting_library/charting_library.js"></Script>
      <Script src="/static/datafeeds/udf/dist/bundle.js"></Script>
    </NextHead>
  )
} 

//components/layout/Layout.tsx

import { Container, Flex, Link, SimpleGrid, Text, Image } from '@chakra-ui/react'
import { ConnectButton } from '@rainbow-me/rainbowkit'
import NextLink from 'next/link'
import React from 'react'
import { Head, MetaProps } from './Head'

interface LayoutProps {
  children: React.ReactNode
  customMeta?: MetaProps
}

export const Layout = ({ children, customMeta }: LayoutProps): JSX.Element => {
  return (
    <>
      <Head customMeta={customMeta} />
      <header>
        <Container maxWidth="container.xl">          
        </Container>
      </header>
      <main>
        <Container maxWidth="container.xl">{children}</Container>
      </main>
      <footer>
        <Container mt="8" py="8" maxWidth="container.xl">
        </Container>
      </footer>
    </>
  )
}

//components/TVChartContainer/index.tsx

import * as React from 'react';
import styles from './index.module.css';
import {
    widget,
    ChartingLibraryWidgetOptions,
    LanguageCode,
    IChartingLibraryWidget,
    ResolutionString,
} from '../../public/static/charting_library/charting_library';

export interface ChartContainerProps {
    symbol: ChartingLibraryWidgetOptions['symbol'];
    interval: ChartingLibraryWidgetOptions['interval'];

    // BEWARE: no trailing slash is expected in feed URL
    datafeedUrl: string;
    libraryPath: ChartingLibraryWidgetOptions['library_path'];
    chartsStorageUrl: ChartingLibraryWidgetOptions['charts_storage_url'];
    chartsStorageApiVersion: ChartingLibraryWidgetOptions['charts_storage_api_version'];
    clientId: ChartingLibraryWidgetOptions['client_id'];
    userId: ChartingLibraryWidgetOptions['user_id'];
    fullscreen: ChartingLibraryWidgetOptions['fullscreen'];
    autosize: ChartingLibraryWidgetOptions['autosize'];
    studiesOverrides: ChartingLibraryWidgetOptions['studies_overrides'];
    container: ChartingLibraryWidgetOptions['container'];
}

export interface ChartContainerState {
}

function getLanguageFromURL(): LanguageCode | null {
    const regex = new RegExp('[\\?&]lang=([^&#]*)');
    const results = regex.exec(location.search);
    return results === null ? null : decodeURIComponent(results[1].replace(/\+/g, ' ')) as LanguageCode;
}

export class TVChartContainer extends React.PureComponent<Partial<ChartContainerProps>, ChartContainerState> {
    public static defaultProps: Omit<ChartContainerProps, 'container'> = {
        symbol: 'AAPL',
        interval: 'D' as ResolutionString,
        datafeedUrl: 'https://demo_feed.tradingview.com',
        libraryPath: '/charting_library/',
        chartsStorageUrl: 'https://saveload.tradingview.com',
        chartsStorageApiVersion: '1.1',
        clientId: 'tradingview.com',
        userId: 'public_user_id',
        fullscreen: false,
        autosize: true,
        studiesOverrides: {},
    };

    private tvWidget: IChartingLibraryWidget | null = null;
    private ref: React.RefObject<HTMLDivElement> = React.createRef();

    public componentDidMount(): void {
        if (!this.ref.current) {
            return;
        }

        const widgetOptions: ChartingLibraryWidgetOptions = {
            symbol: this.props.symbol as string,
            // BEWARE: no trailing slash is expected in feed URL
            // tslint:disable-next-line:no-any
            datafeed: new (window as any).Datafeeds.UDFCompatibleDatafeed(this.props.datafeedUrl),
            interval: this.props.interval as ChartingLibraryWidgetOptions['interval'],
            container: this.ref.current,
            library_path: this.props.libraryPath as string,

            locale: getLanguageFromURL() || 'en',
            disabled_features: ['use_localstorage_for_settings'],
            enabled_features: ['study_templates'],
            charts_storage_url: this.props.chartsStorageUrl,
            charts_storage_api_version: this.props.chartsStorageApiVersion,
            client_id: this.props.clientId,
            user_id: this.props.userId,
            fullscreen: this.props.fullscreen,
            autosize: this.props.autosize,
            studies_overrides: this.props.studiesOverrides,
        };

        const tvWidget = new widget(widgetOptions);
        this.tvWidget = tvWidget;

        tvWidget.onChartReady(() => {
            tvWidget.headerReady().then(() => {
                const button = tvWidget.createButton();
                button.setAttribute('title', 'Click to show a notification popup');
                button.classList.add('apply-common-tooltip');
                button.addEventListener('click', () => tvWidget.showNoticeDialog({
                    title: 'Notification',
                    body: 'TradingView Charting Library API works correctly',
                    callback: () => {
                        console.log('Noticed!');
                    },
                }));
                button.innerHTML = 'Check API';
            });
        });
    }

    public componentWillUnmount(): void {
        if (this.tvWidget !== null) {
            this.tvWidget.remove();
            this.tvWidget = null;
        }
    }

    public render(): JSX.Element {
        return (
            <div
                ref={this.ref}
                className={'TVChartContainer'}
            />
        );
    }
}

//components/TradingView/index.tsx

import React, { useState } from 'react'
import dynamic from 'next/dynamic';

const Chart = dynamic(
  () =>
    import('../../components/TVChartContainer').then(
      (mod) => mod.TVChartContainer
    ),
  { ssr: false }
);

export default function TradingView() {
  return (
    <>
      <Chart />
    </>
  );
}

//pages/Home.tsx

import {
  Grid,
  GridItem,
  Box,
  Button,
  Divider,
  Heading,
  Input,
  Link,
  ListItem,
  Text,
  UnorderedList,
  useToast,
} from '@chakra-ui/react'
import type { NextPage } from 'next'
import { useReducer } from 'react'

import TradingView from '../components/TradingView'

/**
 * Constants & Helpers
 */

/**
 * Prop Types
 */

const Home: NextPage = () => {  

...

  return (
    <Layout>
      <Grid
        h='200px'
        templateRows={{ base: '1fr)', lg: 'repeat(8, 1fr)' }}
        templateColumns={{ base: '1fr', lg: 'repeat(4, 1fr)' }}
        gap={4}
      >
        <GridItem rowSpan={1} colSpan={{ base: 4, lg: 3 }} bg='bitoro.1100' borderRadius='md'>
          <Box maxWidth="container.sm" p='4'>
            <Text fontSize="xl">ETH:USDT</Text>
          </Box>
        </GridItem>
        <GridItem rowSpan={4} colSpan={{ base: 4, lg: 3 }} bg='bitoro.1100' h='360px' borderRadius='md'>
          <TradingView />
        </GridItem>
      </Grid>
    </Layout>
  )
}

export default Home

And copied to /public/static/charting_library, datafeeds

I am struggling to find solution... but not succeed. Any suggestion?

josedejesuschavez commented 4 months ago

Add:

File Public/index.html

Captura desde 2024-03-04 12-37-29