Comments (8)
I'm experiencing what seems like same issue. The charts are not loading when navigating to a page for the first time with turbo. The proposed fix makes the charts load as expected. However, subsequent navigation in the app then results in error messages in the console, since the listeners on turbo:load
are still active but turbo has loaded a new page that does not contain those charts. Adding the once: true
option prevents these error messages in my case while still solving the original problem of the charts failing to load.
window.addEventListener("turbo:load", createChart, {once: true});
from chartkick.
Also running into this. Any way to fix it locally, while we wait for a fix?
You can override
helper.rb
with the fix above.
Thanks!
As far as I can tell I then need to override the whole function, which is quite long? (New to Rails, so asking stupid questions left and right!)
I did it using the following file content, but it definitely is very fragile, as any changes in any of the other 90 lines of code that I didn't want to change will introduce weird bugs.
module ChartkickHelper
# TODO: THIS IS A HACK to make turbo frames play nicely with charts
# ONLY KEEP UNTIL THE FOLLOWING BUG IS FIXED: https://github.com/ankane/chartkick/issues/608
# IT CAN BE SAFELY DELETED WHEN THAT BUG IS FIXED
def chartkick_chart(klass, data_source, **options)
options = Chartkick::Utils.deep_merge(Chartkick.options, options)
@chartkick_chart_id ||= 0
element_id = options.delete(:id) || "chart-#{@chartkick_chart_id += 1}"
height = (options.delete(:height) || "300px").to_s
width = (options.delete(:width) || "100%").to_s
defer = !!options.delete(:defer)
# content_for: nil must override default
content_for = options.key?(:content_for) ? options.delete(:content_for) : Chartkick.content_for
nonce = options.fetch(:nonce, true)
options.delete(:nonce)
if nonce == true
# Secure Headers also defines content_security_policy_nonce but it takes an argument
# Rails 5.2 overrides this method, but earlier versions do not
if respond_to?(:content_security_policy_nonce) && (content_security_policy_nonce rescue nil)
# Rails 5.2+
nonce = content_security_policy_nonce
elsif respond_to?(:content_security_policy_script_nonce)
# Secure Headers
nonce = content_security_policy_script_nonce
else
nonce = nil
end
end
nonce_html = nonce ? " nonce=\"#{ERB::Util.html_escape(nonce)}\"" : nil
# html vars
html_vars = {
id: element_id,
height: height,
width: width,
# don't delete loading option since it needs to be passed to JS
loading: options[:loading] || "Loading..."
}
[:height, :width].each do |k|
# limit to alphanumeric and % for simplicity
# this prevents things like calc() but safety is the priority
# dot does not need escaped in square brackets
raise ArgumentError, "Invalid #{k}" unless html_vars[k] =~ /\A[a-zA-Z0-9%.]*\z/
end
html_vars.each_key do |k|
# escape all variables
# we already limit height and width above, but escape for safety as fail-safe
# to prevent XSS injection in worse-case scenario
html_vars[k] = ERB::Util.html_escape(html_vars[k])
end
html = (options.delete(:html) || %(<div id="%{id}" style="height: %{height}; width: %{width}; text-align: center; color: #999; line-height: %{height}; font-size: 14px; font-family: 'Lucida Grande', 'Lucida Sans Unicode', Verdana, Arial, Helvetica, sans-serif;">%{loading}</div>)) % html_vars
# js vars
js_vars = {
type: klass.to_json,
id: element_id.to_json,
data: data_source.respond_to?(:chart_json) ? data_source.chart_json : data_source.to_json,
options: options.to_json
}
js_vars.each_key do |k|
js_vars[k] = Chartkick::Utils.json_escape(js_vars[k])
end
createjs = "new Chartkick[%{type}](%{id}, %{data}, %{options});" % js_vars
warn "[chartkick] The defer option is no longer needed and can be removed" if defer
# Turbolinks preview restores the DOM except for painted <canvas>
# since it uses cloneNode(true) - https://developer.mozilla.org/en-US/docs/Web/API/Node/
#
# don't rerun JS on preview to prevent
# 1. animation
# 2. loading data from URL
js = <<~JS
<script#{nonce_html}>
(function() {
if (document.documentElement.hasAttribute("data-turbolinks-preview")) return;
if (document.documentElement.hasAttribute("data-turbo-preview")) return;
var createChart = function() { #{createjs} };
if ("Chartkick" in window) {
window.addEventListener("turbo:load", createChart, {once: true});
} else {
window.addEventListener("chartkick:load", createChart, true);
}
})();
</script>
JS
if content_for
content_for(content_for) { js.respond_to?(:html_safe) ? js.html_safe : js }
else
html += "\n#{js}"
end
html.respond_to?(:html_safe) ? html.html_safe : html
end
end
from chartkick.
Just hit the same issue - the problem seems to be caused by chartkick destroying all charts on turbo:before-render. It seems that inline script runs before that hooks, so new charts are destroyed just after they are rendered.
I fixed it using the following:
Chartkick.config.autoDestroy = false
window.addEventListener('turbo:before-render', () => {
Chartkick.eachChart(chart => {
if (!chart.element.isConnected) {
chart.destroy()
delete Chartkick.charts[chart.element.id]
}
})
})
from chartkick.
When building search forms (or reporting forms with search capabilities), you’ll likely use a similar approach. @ankane I think that updating the library to wait for the turbo:load
event and allowing for Turbo to process the rendered HTML and update the DOM will alleviate any frame replacement errors like this one.
from chartkick.
Also running into this. Any way to fix it locally, while we wait for a fix?
from chartkick.
Also running into this. Any way to fix it locally, while we wait for a fix?
You can override helper.rb
with the fix above.
from chartkick.
I opened a PR #610 with the fix from above. If you wish to use it, just update your Gemfile to:
gem "chartkick", git: "https://github.com/wilg/chartkick", branch: "wilg/turbo"
from chartkick.
Note to anyone else copying @DanielJackson-Oslo code above, the class/module has changed from:
module ChartkickHelper
...
end
to:
class Chartkick
module Helper
...
end
end
Can confirm works as of days date when using TurboDrive and TurboFrames 🎉
from chartkick.
Related Issues (20)
- Charts stuck at "Loading..." [example included] HOT 4
- CSP compliance breaks when used with Turbo Drive w/ and random nonce generator HOT 3
- Add support for chart.js 4.x HOT 3
- Add combo bar/line charts HOT 2
- Jruby Support HOT 1
- Support for Apex Charts HOT 1
- Add support for limiting the serie to a certain time frame HOT 1
- Support for polar (spiderweb) charts HOT 1
- Demo not rendering correctly in Safari HOT 2
- Comparisons in Two Date Ranges HOT 1
- Error importing Chartkick object HOT 2
- Provide ES module for JS with default exports HOT 1
- Rails 7 Setup Additional Step Needed HOT 4
- Canvas accessibility options like aria-label HOT 1
- preffix and suffix on column HOT 1
- X-axis is converted to integers even if datapoint contains alphanumeric characters HOT 1
- Some plugins not (fully) working with Chartkick with Importmaps HOT 2
- Conflicts with Action_text from rails and do not displaying in production(Heroku) HOT 1
- area_chart stoped do work with limit in ruby query HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from chartkick.