Alternative to get_element_value method for HtmlDialog



Has a best practices alternative method been set for transferring values from a dialog to an extension? I was storing values in hidden inputs and moving those to the extension with the get_element_value method on the WebDialog.



In the UI::HtmlDialog class, the add_action_callback() instance method will convert between Js and Ruby types automatically.

In the old UI::WebDialog class, your webpages could only send String data via a protocol handler.

The UI::HtmlDialog class does not use the protocol handler to send data to Ruby.

That said, you could still likely do it, thus defining a singleton method upon your HtmlDialog instance:

EDIT: Proven not to work! The UI::HtmlDialog class’ execute_script() method returns nil.

Non-working attempt ...
@dlg.define_singleton_method(:get_element_value) {|id|

Or, you can create your own subclass of UI::HtmlDialog, thus:

module Archetris
  class NiftyDialog < UI::HtmlDialog

    def get_element_value( id )


EDIT: For a working example see


Thanks, Dan. That’s incredibly helpful.


@Dan: question is though: is it best practice to continue storing values in hidden elements OR just use the callback to send data from JS to Ruby instead?


The storing of values, and whether they are hidden or visible is not really the issue anymore. (You can still have hidden values, stored in hidden html elements, or even better stored in Javascript objects.)

It is the passing of values to the Ruby side is the more important concept.

So yes, best practice going forward will be to use the new sketchup Javascript object, which will convert on the Ruby side to the correct class of Ruby object.
No more chopping up big strings into little strings and then convert the strings to arrays and numbers, etc.

I just showed the above code as a workaround for getting old code to work without a large overhaul.


the method #execute_script is defined to return nil


Yes, and the API docs are never wrong … :rolling_eyes:

If the above does not work,… then try something like this:

EDIT: This does not work either, See below.

(Collapsed as this example will also not work.)
module AuthorTest

  @@loaded ||= false

  class NiftyDialog < UI::HtmlDialog

    def initialize(*args)
      @ready ||= {}
      @returned_values ||= {}
      add_action_callback('returned_value') {|ac,id,value|
        @returned_values[id]= value
      add_action_callback('element_value_ready') {|ac,id|
        @ready[id]= true

    def get_element_value( id )
      @ready[id]= false
          { onCompleted: function() {
      until @ready[id]

  end # custom HtmlDialog subclass
  def self::open
    @dlg = NiftyDialog::new(dialog_title: "Test")
      <!DOCTYPE html>
          <div id="DataField">
            Testing 1, 2, 3, ...

  def self::test
    msg = "Getting the 'DataField' element's value ..."
    msg<< "  value is: \"#{@dlg.get_element_value('DataField')}\""
    puts msg

  def self::reset
    @dlg.close if @dlg && @dlg.visible?
    @dlg = nil

  if !@@loaded
    sm ="Plugins").add_submenu("Get Element Value Test")
    sm.add_item('Open Dialog') { self::open }
    sm.add_item('Test') { self::test }
    sm.add_item('Reset') { self::reset }
    @@loaded = true


EDIT: For a working example see


Yep. This is true for the UI::HtmlDialog class. Seems like it used to work for the old UI::WebDialog class.

I just tested and it seems now (with the UI::HtmlDialog class,) there is no way to get an immediate synchronous value of a HtmlDialog element. Control must return to the SketchUp engine before the JS to Ruby callbacks will fire. So then there is no way, that a custom get_element_value() method could ever itself return the value, if it is the instigator of the JS call to send the value to Ruby.

get_element_value_test.rb (2.6 KB)

This is unfortunate as that ol’ get_element_value() method came in very handy.

What’s the workaround ?

It seems that you’ll need to make a call to fire a method on the JS side to collect ALL values that you might wish to test on the Ruby-side, and pass them en masse to Ruby as a array, etc. Or,… you move this kind of immediate comparison expression to the JS side of your code.


EDIT: For an asynchronous working example see