charting-library-examples
charting-library-examples copied to clipboard
ReferenceError: window is not defined
Describe the bug
Hello, my application is written in nextjs with typescript, and I'm trying to use the react-typescript example, available in the repository. However it is returning this error below, when I call the new widget(widgetOptions)
Additional context
My component is written like this:
import React, { createRef } from 'react';
import { Content, Title } from './styles';
import {
widget,
LanguageCode,
ResolutionString,
IChartingLibraryWidget,
ChartingLibraryWidgetOptions,
} from '../../../public/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 {}
const 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;
};
const TradingGraph = () => {
const 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: {},
};
let tvWidgets: IChartingLibraryWidget | null = null;
let ref: React.RefObject<HTMLDivElement> = createRef();
const widgetOptions: ChartingLibraryWidgetOptions = {
...defaultProps,
// tslint:disable-next-line:no-any
datafeed: defaultProps.datafeedUrl as any,
locale: getLanguageFromURL || 'en',
container: ref.current as HTMLElement,
enabled_features: ['study_templates'],
disabled_features: ['use_localstorage_for_settings'],
};
if (typeof window !== 'undefined') {
const tvWidget = new widget(widgetOptions);
console.log(tvWidget);
tvWidgets = 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';
});
});
if (tvWidgets !== null) {
tvWidgets.remove();
tvWidgets = null;
}
}
return (
<Content className="row">
<Title>Graphics</Title>
<div ref={ref} className={'TVChartContainer'} />
</Content>
);
};
export default TradingGraph;
And even using the given example syntax, it's the same error it returns. and this bug is the same for nextjs-javascript example
Make sure you're adding the
And depending on your version of Next.js you may need to use the custom Script tag instead:
import Document, { Html, Head, Main, NextScript } from 'next/document'
import Script from 'next/script'
class MyDocument extends Document {
render() {
return (
<Html>
<Head>
<Script
src="/datafeeds/udf/dist/bundle.js"
strategy="beforeInteractive"
></Script>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument
Hello, @tjshipe
Unfortunately it didn't work the way you suggested. It continues to return the same error, when I apply the call and the example within my application. I also tested with different versions of next.js in my project and the same error is shown.
The versions of next.js in my project were tested - 12.1.0; 12.1.6; 12.2.4
the code below is from my project's _document.tsx
import Script from 'next/script';
import Document, {
Html,
Head,
Main,
NextScript,
} from 'next/document';
import { ServerStyleSheet } from 'styled-components';
export default class MyDocument extends Document {
render() {
return (
<Html lang="pt-BR">
<Head>
<Script
id="graphic"
strategy="beforeInteractive"
src="/datafeeds/udf/dist/bundle.js"
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
@rodrigopluz How/where are you importing the TradingGraph
component?
@rodrigopluz were you able to fix this problem? I'm having the same issue if anyone can help out. I am trying to follow this nextjs example.
My chart_library
and datafeeds
folders are located in the root directory under public/static
My _document.js has this
...
<script
type="text/javascript"
src="public/static/charting_library/charting_library.js">
</script>
<script src="public/static/datafeeds/udf/dist/bundle.js"></script>
any ideas on why I get the same error?
Hello @0xAskar, yes I managed to solve the problem as follows.
In the _document.tsx file I imported
import Script from 'next/script';
and where do you call the <script ...
you change to
<Script strategy="afterInteractive" src="/static/datafeeds/udf/dist/bundle.js" />
and in my TradingGraph.tsx component, I wrote it like this.
import React, { createRef } from 'react';
import { Content } from './styles';
import {
widget,
Timezone,
ThemeName,
LanguageCode,
ResolutionString,
IChartingLibraryWidget,
ChartingLibraryWidgetOptions,
} from '../../../public/static/charting_library';
const 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 TradingGraph extends React.PureComponent {
tvWidget: IChartingLibraryWidget | null = null;
ref: React.RefObject<HTMLDivElement> = createRef();
componentDidMount() {
const widgetOptions = {
symbol: 'ADBE',
datafeed: new (
window as any
).Datafeeds.UDFCompatibleDatafeed(
'https://demo_feed.tradingview.com',
),
interval: '1D' as ResolutionString,
timezone: 'America/Sao_Paulo' as Timezone,
container: this.ref.current as HTMLElement,
library_path: '/static/charting_library/',
locale: getLanguageFromURL() || ('pt' as LanguageCode),
disabled_features: [''],
enabled_features: [''],
charts_storage_api_version:
'1.4' as ChartingLibraryWidgetOptions['charts_storage_api_version'],
client_id: 'tradingview.com',
theme: 'Dark' as ThemeName,
user_id: 'public_user_id',
};
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: () => {
},
}),
);
button.innerHTML = 'Check API';
});
});
}
componentWillUnmount() {
if (this.tvWidget !== null) {
this.tvWidget.remove();
this.tvWidget = null;
}
}
render() {
return (
<Content>
<div ref={this.ref} className={'TVChartContainer'} />
</Content>
);
}
}
@rodrigopluz thanks for the response! the script tag fixed it, but now i seem to get a datafeed udf undefined error. Did you encounter this before? I will also attached my code
import * as React from 'react';
import styles from './index.module.css';
import { widget, version } from '../../public/static/charting_library';
function getLanguageFromURL() {
const regex = new RegExp('[\\?&]lang=([^&#]*)');
const results = regex.exec(window.location.search);
return results === null ? null : decodeURIComponent(results[1].replace(/\+/g, ' '));
}
export class TVChartContainer extends React.PureComponent {
static defaultProps = {
symbol: 'AAPL',
interval: 'D',
datafeedUrl: '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: {},
};
tvWidget = null;
constructor(props) {
super(props);
this.ref = React.createRef();
}
componentDidMount() {
const widgetOptions = {
symbol: this.props.symbol,
// BEWARE: no trailing slash is expected in feed URL
datafeed: new window.Datafeeds.UDFCompatibleDatafeed(this.props.datafeedUrl),
interval: this.props.interval,
container: this.ref.current,
library_path: this.props.libraryPath,
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';
});
});
}
componentWillUnmount() {
if (this.tvWidget !== null) {
this.tvWidget.remove();
this.tvWidget = null;
}
}
render() {
return (
<>
<header className={styles.VersionHeader}>
<h1>TradingView Charting Library and Next.js Integration Example</h1>
</header>
<div ref={this.ref} className={styles.TVChartContainer} />
</>
);
}
}
try this, in your component call
const TradingGraph: any = dynamic(
() =>
import('../../components/TradingGraph').then(
module => module.TradingGraph as any,
),
{
ssr: false,
},
);
@rodrigopluz So, I do already have this in my component. What is important to note is that I updated the error above as well to include the datafeed error. I had to update my import to fix the other problem, but I'm unsure why the datafeedUrl is undefined. Do you use the demo trading feed url as well and it works? if so, do you see any other problem. I'll add my component code in here.
import dynamic from 'next/dynamic';
const TVChartContainer = dynamic(
() =>
import('../../components/TVChartContainer').then(mod => mod.TVChartContainer),
{ ssr: false },
);
const Index = () => {
return (<TVChartContainer />);
};
export default Index;
then here's the component code
import * as React from 'react';
import styles from './index.module.css';
import { widget, version } from '../../public/static/charting_library';
function getLanguageFromURL() {
const regex = new RegExp('[\\?&]lang=([^&#]*)');
const results = regex.exec(window.location.search);
return results === null ? null : decodeURIComponent(results[1].replace(/\+/g, ' '));
}
export class TVChartContainer extends React.PureComponent {
static defaultProps = {
symbol: 'AAPL',
interval: 'D',
datafeedUrl: 'https://demo_feed.tradingview.com',
// datafeedUrl: "/static/datafeeds/",
libraryPath: '/static/charting_library/',
chartsStorageUrl: 'https://saveload.tradingview.com',
chartsStorageApiVersion: '1.1',
clientId: 'tradingview.com',
userId: 'public_user_id',
fullscreen: false,
autosize: true,
studiesOverrides: {},
};
tvWidget = null;
constructor(props) {
super(props);
this.ref = React.createRef();
}
componentDidMount() {
const widgetOptions = {
symbol: this.props.symbol,
// BEWARE: no trailing slash is expected in feed URL
datafeed: new window.Datafeeds.UDFCompatibleDatafeed(this.props.datafeedUrl),
interval: this.props.interval,
container: this.ref.current,
library_path: this.props.libraryPath,
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,
};
console.log(new widget())
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';
});
});
}
componentWillUnmount() {
if (this.tvWidget !== null) {
this.tvWidget.remove();
this.tvWidget = null;
}
}
render() {
return (
<>
<header className={styles.VersionHeader}>
<h1>TradingView Charting Library and Next.js Integration Example</h1>
</header>
<div ref={this.ref} className={styles.TVChartContainer} />
</>
);
}
}
Where do you place the chart_library
and datafeeds
library as well? @rodrigopluz I'm just confused why this is causing the problem
if you look at the example I gave, I'm not using the static defaultProps
, and all the parameters I pass in the const widgetOptions
itself.
try this way.
Okay I will try your way @rodrigopluz . Give me one second. Thank you for your help
I refer to it that way
const widgetOptions = {
symbol: 'AAPL',
interval: 'D',
datafeedUrl: '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: {},
}
okay @rodrigopluz if you want to talk in the TradingView Discord. If not, we made some progress but am still stuck. My screen is just black, no errors. Here are all the files that are relevant. I'm using the code you sent above. Also to note, my charting_library
and datafeeds
library are in the public/static libraries. Do you see anything that could cause the blank screen?
here is the component code
import React, { createRef } from 'react';
import {
widget,
Timezone,
ThemeName,
LanguageCode,
ResolutionString,
IChartingLibraryWidget,
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 TradingGraph extends React.PureComponent {
tvWidget = null;
ref= createRef();
componentDidMount() {
const widgetOptions = {
symbol: 'ADBE',
datafeed: new (
window
).Datafeeds.UDFCompatibleDatafeed(
'https://demo_feed.tradingview.com',
),
interval: '1D',
timezone: 'America/Sao_Paulo',
container: this.ref.current,
library_path: '/static/charting_library/',
locale: getLanguageFromURL() || ('pt'),
disabled_features: [''],
enabled_features: [''],
charts_storage_api_version:
'1.4',
client_id: 'tradingview.com',
theme: 'Dark',
user_id: 'public_user_id',
};
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: () => {
},
}),
);
button.innerHTML = 'Check API';
});
});
}
componentWillUnmount() {
if (this.tvWidget !== null) {
this.tvWidget.remove();
this.tvWidget = null;
}
}
render() {
return (
<div>
<div ref={this.ref} className={'TVChartContainer'} />
</div>
);
}
}
there is also the page code i already sent above (unchanged).
here's my document.js code
import Document, { Html, Head, Main, NextScript } from "next/document";
import Script from 'next/script';
class MyDocument extends Document {
render() {
return (
<Html lang="en">
<Head>
<script
async
src={`https://www.googletagmanager.com/gtag/js?id=${process.env.NEXT_PUBLIC_GOOGLE_ANALYTICS}`}
/>
{/* <script
type="text/javascript"
src="public/static/charting_library/charting_library.js">
</script> */}
<Script src="/static/datafeeds/udf/dist/bundle.js"/>
.... (other code)
</noscript>
</Html>
);
}
}
export default MyDocument;
what I was referring to, you change your code, it would be just that part
const widgetOptions = {
symbol: 'AAPL',
interval: 'D',
datafeedUrl: '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: {},
}
the rest of your code was correct, in my component I'm using typescript, but this snippet that I put here for you, is not typed.
Okay, I just updated it; however, my screen is still just blank, here's the code now with a screenshot of the page
import React, { createRef } from 'react';
import {
widget,
Timezone,
ThemeName,
LanguageCode,
ResolutionString,
IChartingLibraryWidget,
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 TradingGraph extends React.PureComponent {
tvWidget = null;
ref= createRef();
componentDidMount() {
const widgetOptions = {
symbol: 'AAPL',
interval: 'D',
datafeedUrl: '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: {},
}
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: () => {
},
}),
);
button.innerHTML = 'Check API';
});
});
}
componentWillUnmount() {
if (this.tvWidget !== null) {
this.tvWidget.remove();
this.tvWidget = null;
}
}
render() {
return (
<div>
<div ref={this.ref} className={'TVChartContainer'} />
</div>
);
}
}
try to see if the calling path of charting_library would be the same.
like how many returns you need to have... '../../public/static/charting_library' or '../public/static/charting_library'
import {
widget,
} from '../../public/static/charting_library';
something else, this amount you don't need
Timezone,
ThemeName,
LanguageCode,
ResolutionString,
IChartingLibraryWidget,
ChartingLibraryWidgetOptions,
@rodrigopluz good point that i don't need those things. but my path is already correct. cause if not, then it throws an error. not sure what to do though? What is interesting is that, none of my console.logs are triggering inside the component. So it seems like maybe the dynamic import not working
tests by removing the dynamic. to see if it returns an error.
this problem of getting a black screen, I didn't have this problem.
so if i get rid of the dynamic it gets the datafeeds is not defined problem again. here's my question to you, what is component named and what file is it located? is it components/TradingGraph
and then in an index.js file?
The way that i structured the page index is:
import dynamic from 'next/dynamic';
// import TVChartContainer from "../../components/TVChartContainer/index.js"
const TradingGraph = dynamic(
() =>
import('../../components/TVChartContainer/index').then(
module => module.TradingGraph,
),
{
ssr: false,
},
);
const Index = () => {
return (
<div>
<TradingGraph />
</div>
);
};
export default Index;
Actually, I now get this error: The datafeed seems to be undefined
this is the error that was returning me, and then I did it the way I gave you.
try to change the version of charts_storage_api_version for 1.4
@rodrigopluz the problem is, i am doing the way you're doing it, and I'm still reaching the problem. It seems like you need to add new windows.datafeeds.... but i'm getting a new error of windows.datafeeds is undefined. i'm having same error as this person https://github.com/tradingview/charting-library-examples/issues/310
where is your document.js file located?
actually, i was able to get window.datafeeds, but now i still get this same error
look, take a look again at your _document.js file
I think it should be that way.
class MyDocument extends Document {
render() {
return (
<Html lang="en">
<Head>
<Script
async
strategy="afterInteractive"
src={`https://www.googletagmanager.com/gtag/js?id=${process.env.NEXT_PUBLIC_GOOGLE_ANALYTICS}`}
/>
<Script strategy="afterInteractive" src="/static/datafeeds/udf/dist/bundle.js"/>
.... (other code)
</Head>
</Html>
);
}
}
unforunately, I still get the same error. weirdly enough.
again here's the 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>
);
}
}