-
Notifications
You must be signed in to change notification settings - Fork 14
Open
Labels
Description
reactable
has an underappreciated WidgetContainer
that handles htmlwidgets
(see lines ). I think vueR
should have a similar structure but without the tags
for data and options. Here is a very rough draft example that needs significant improvement, iteration, and testing.
library(htmltools)
library(htmlwidgets)
library(shiny)
library(vueR)
library(listviewer)
library(plotly)
# handle non-standard behaviors by some widgets
get_widget_data <- function(widget) {
as.tags(widget)[[2]]$children[[1]]
}
p <- plot_ly(palmerpenguins::penguins, x = ~bill_length_mm, y = ~body_mass_g)
tl <- tagList(
crosstalk::crosstalkLibs(), # necessary for g2
vueR::html_dependency_vue(minified = FALSE),
htmlDependency(
"htmlwidgets",
packageVersion("htmlwidgets"),
src = system.file("www", package = "htmlwidgets"),
script = "htmlwidgets.js"
),
p$dependencies, # this is far from ideal but plotly works differently; in most cases do not need to add since *Output handles
tags$div(
tags$button("update data", onclick = "updateData()")
),
tags$div(
id = "app",
tag('html-widget', list(
jsoneditOutput("je"),
`:x` = 'x',
`name` = 'jsonedit' # ideally we find a way to avoid this
)),
tag('html-widget', list(
plotlyOutput("pl"),
`:x` = 'x',
`name` = 'plotly' # ideally we find a way to avoid this
))
),
tags$script(HTML(
sprintf("
Vue.component(
'html-widget',
{
props: ['x', 'name'],
template: '<div><slot></slot></div>',
methods: {
// Copied from HTMLWidgets code
// Implement a vague facsimilie of jQuery's data method
elementData: function(el, name, value) {
if (arguments.length == 2) {
return el['htmlwidget_data_' + name];
} else if (arguments.length == 3) {
el['htmlwidget_data_' + name] = value;
return el;
} else {
throw new Error('Wrong number of arguments for elementData: ' +
arguments.length);
}
},
updateWidget: function() {
var component = this;
// use HTMLWidgets.widgets to give us a list of available htmlwidget bindings
var widgets = HTMLWidgets.widgets;
// assume there might be lots, so filter for the one we want
// in this case, we want jsonedit
var widget = widgets.filter(function(widget){
return widget.name === component.name
})[0];
// get our htmlwidget DOM element
var el = this.$el.querySelector('.html-widget');
var instance = this.elementData(el, 'init_result')
widget.renderValue(
el,
this.x,
instance
);
}
},
mounted: function() {
if(typeof(this.x) === 'undefined' || this.x === null) { return }
var component = this;
// use HTMLWidgets.widgets to give us a list of available htmlwiget bindings
var widgets = HTMLWidgets.widgets;
// assume there might be lots, so filter for the one we want
// in this case, we want jsonedit
var widget = widgets.filter(function(widget){
return widget.name === component.name
})[0];
// get our htmlwidget DOM element
var el = this.$el.querySelector('.html-widget');
// get our htmlwidget instance with initialize
var instance = widget.initialize(el);
this.elementData(el, 'init_result', instance);
widget.renderValue(
el,
this.x,
instance
);
},
// updated not working since does not watch deep
// but if the expectation is that data and options are replaced completely
// then updated will trigger
updated: function() {
this.updateWidget()
},
watch: {
x: {
handler: function() {console.log('updating');this.updateWidget()},
deep: true
}
}
}
)
var app = new Vue({
el: '#app',
data: () => (%s)
})
function updateData() {
app.x.data[0].y = app.x.data[0].y.map(d => Math.random())
}
",
get_widget_data(p)
)
))
)
browsable(tl)
JohnCoene
Metadata
Metadata
Assignees
Labels
Type
Projects
Milestone
Relationships
Development
Select code repository
Activity
timelyportfolio commentedon Apr 30, 2021
Gior Test
FrissAnalytics commentedon May 1, 2021
Leaflet test
note: example does not update data yet.
timelyportfolio commentedon May 1, 2021
@FrissAnalytics nice to see that
leaflet
works. In ashiny
context I'd like to see if we can take advantage of theproxy
methods provided byleaflet
.FrissAnalytics commentedon May 1, 2021
yep! Tried to get the leaflet data in the example above. Turned out it's a pretty complicated object with a highly non-trivial structure, unless you are familiar how the shiny leaflet implementation works.
Would be much cleaner to have access to the proxy and to manipulate the widget instance from server.R.
timelyportfolio commentedon May 17, 2021
@FrissAnalytics Here is a little more complicated example with a
plotly
htmlwidget in Vuetify table cells. It is a mess but does prove that it can be done.timelyportfolio commentedon May 17, 2021
@FrissAnalytics I probably should have started with a simpler example and then built from there. Here is a Vuetify data table with
iris
data.