ehsan-shv / vue-tradingviewWidgets

Tradingview widgets for Vue 3 and Nuxt 3.
MIT License
91 stars 19 forks source link

Symbol with dynamic value #14

Closed MiaadSayyahi closed 1 year ago

MiaadSayyahi commented 2 years ago

Hi dear friend I used this service and set the symbol value dynamically But after changing the name of the currency, the chart is not updated to be loaded with the new currency I even used several methods to reload the component manually after changing the name of the currency, but unfortunately it did not work. Can you help me to solve my problem?

ehsan-shv commented 2 years ago

Hi! Would you give me a code demo here?

MiaadSayyahi commented 2 years ago

Hi! Would you give me a code demo here?

const currencyName = ref('')

const Option = computed(() => ({ width: '88vw', height: '500', symbol: currencyName, interval: '60', style: '1', locale: 'en', enable_publishing: false, allow_symbol_change: true, theme: 'dark' }))

<Chart

      class="d-flex flex-row justify-content-center"
      :options="Option"

/>

*currencyName value is filled from the api

ehsan-shv commented 2 years ago

key may helps you: <Chart :key="Option.symbol" class="d-flex flex-row justify-content-center" :options="Option" />

MiaadSayyahi commented 2 years ago

I used this method but after choosing a new currency, it does not show the chart at all

kayahasa commented 1 year ago

same problem here. I am facing same problem

ondrejhadrava commented 1 year ago

I managed to fix this by copying src/components/Chart.vue into my project and removing if (scriptExists()) return, which prevented from re-rendering.

Here is the component you can copy and paste into your project:

<template>
    <div :id="container" />
</template>

<script lang="ts">
import { defineComponent, onMounted, ref } from 'vue'

declare global {
  interface Window {
    TradingView: any;
  }
}
window.TradingView = window.TradingView || {}
export default defineComponent({
    name: 'Chart',
    props: {
        options: {
            type: Object,
            default: () => ({}),
        },
    },
    setup(props) {
        const container = ref('tradingview-chart')
        const scriptID = ref('tradingview-chart-script')

        const defualtOptions = {
            width: 980,
            height: 610,
            symbol: 'NASDAQ:AAPL',
            interval: 'D',
            timezone: 'Etc/UTC',
            theme: 'light',
            style: '1',
            locale: 'en',
            toolbar_bg: '#f1f3f6',
            enable_publishing: false,
            allow_symbol_change: true,
            container_id: 'tradingview-chart',
        }

        const canUseDOM = () => {
            return typeof window !== 'undefined' && window.document && window.document.createElement
        }

        const getScriptElement = () => {
            return document.getElementById(scriptID.value)
        }

        // const scriptExists = () => {
        //  return getScriptElement() !== null
        // }

        const appendScript = (onload: () => void) => {
            if (!canUseDOM()) return
            // if (scriptExists()) return

            const script = document.createElement('script')
            script.id = scriptID.value
            script.type = 'text/javascript'
            script.async = true
            script.src = 'https://s3.tradingview.com/tv.js'
            script.onload = onload
            document.getElementsByTagName('head')[0].appendChild(script)
        }

        const initWidget = () => {
            setTimeout(() => {
                if (typeof window.TradingView === 'undefined') return
                const options: { container_id: string } = { ...defualtOptions, ...props.options }
                if (options.container_id !== container.value) {
                    console.error('container_id in Chart component must be "tradingview-chart"')
                    return
                }
                new window.TradingView.widget(Object.assign({ container_id: container }, options))
            }, 300)
        }

        onMounted(() => {
            appendScript(() => initWidget())
        })
        return { container }
    },
})
</script>

I am pretty sure there is a better way to fix this. I may take a look at it later.

ehsan-shv commented 1 year ago

I managed to fix this by copying src/components/Chart.vue into my project and removing if (scriptExists()) return, which prevented from re-rendering.

Here is the component you can copy and paste into your project:

<template>
  <div :id="container" />
</template>

<script lang="ts">
import { defineComponent, onMounted, ref } from 'vue'

declare global {
  interface Window {
    TradingView: any;
  }
}
window.TradingView = window.TradingView || {}
export default defineComponent({
  name: 'Chart',
  props: {
      options: {
          type: Object,
          default: () => ({}),
      },
  },
  setup(props) {
      const container = ref('tradingview-chart')
      const scriptID = ref('tradingview-chart-script')

      const defualtOptions = {
          width: 980,
          height: 610,
          symbol: 'NASDAQ:AAPL',
          interval: 'D',
          timezone: 'Etc/UTC',
          theme: 'light',
          style: '1',
          locale: 'en',
          toolbar_bg: '#f1f3f6',
          enable_publishing: false,
          allow_symbol_change: true,
          container_id: 'tradingview-chart',
      }

      const canUseDOM = () => {
          return typeof window !== 'undefined' && window.document && window.document.createElement
      }

      const getScriptElement = () => {
          return document.getElementById(scriptID.value)
      }

      // const scriptExists = () => {
      //  return getScriptElement() !== null
      // }

      const appendScript = (onload: () => void) => {
          if (!canUseDOM()) return
          // if (scriptExists()) return

          const script = document.createElement('script')
          script.id = scriptID.value
          script.type = 'text/javascript'
          script.async = true
          script.src = 'https://s3.tradingview.com/tv.js'
          script.onload = onload
          document.getElementsByTagName('head')[0].appendChild(script)
      }

      const initWidget = () => {
          setTimeout(() => {
              if (typeof window.TradingView === 'undefined') return
              const options: { container_id: string } = { ...defualtOptions, ...props.options }
              if (options.container_id !== container.value) {
                  console.error('container_id in Chart component must be "tradingview-chart"')
                  return
              }
              new window.TradingView.widget(Object.assign({ container_id: container }, options))
          }, 300)
      }

      onMounted(() => {
          appendScript(() => initWidget())
      })
      return { container }
  },
})
</script>

I am pretty sure there is a better way to fix this. I may take a look at it later.

I think watching the props with watch() will fix the issue. I'm gonna refactor the whole code base and fix this issue

ondrejhadrava commented 1 year ago

@ehsan-shv Yeah that was one of my thoughts. Are you about to implement it this week, or later? I am thinking about contributing to this project and this seems something I can handle.

ehsan-shv commented 1 year ago

@ehsan-shv Yeah that was one of my thoughts. Are you about to implement it this week, or later? I am thinking about contributing to this project and this seems something I can handle.

I'm thinking about using Vite for packaging the components for NPM and it takes time. if you are interested in contributing to and refactoring the project, please send your Discord account to my Email then we can discuss refactoring in detail.

ehsan-shv commented 1 year ago

I've just checked and dynamic props worked in the latest version. So just install the latest version. Also, this example may help.

ehsan-shv commented 1 year ago

If there is an issue with dynamic props please reopen the issue.