How to get html value

I have a problem when get value from HTML dialog.

<script type = "text/javascript">
function sendValue(id) {
	sketchup.receiveValue(id, document.getElementById(id).value);
<input type="text" id="elemName">

This is callback function at sketchup.

add_action_callback('receiveValue') { |not_used, id, val|
def receive_value(id, val)
  @values[id] = val

I try to get input value like this, but I can’t get value.

dlgValues = @dialog.process_values

def request_element_value(id)
  return unless id.is_a?(String) || id.respond_to?(:to_s)
def process_values

I can’t get dlgValues, so I checked the size of dlgValues.
The first messagebox receives a size of 0, and the second messagebox receives a size of 2.
I don’t understand because I didn’t do anything between the messageboxes.

Asynchronous means a statement is executed independently and the main program flow continues without waiting for a return.

Immediately after @dialog.request_element_value("elemHeight") is triggered, dlgValues = @dialog.process_values is executed and at that point of time neither sketchup.receiveValue(id, document.getElementById(id).value); has been run, nor @values[id] = val. The value that your message box wants to show is not yet known. You need to open the message box after the value is known.
Since message boxes are blocking, the first message box took enough time so that the callback was executed before you open the second message box (not a solution).

There are different ways to solve it. Important is to understand that the problem is about sequence of events: messagebox must come after you know for sure that the event receive_value has actually happened, that is not just after an arbitrary amount of time like 1s.

  • You can move process_values and UI.messagebox(dlgValues.size) inside of the block of add_action_callback('receiveValue'). However this callback is then not any more generic and will always receive values and also process and display them.

    <script type = "text/javascript">
    function sendValues(ids) {
        var dict = {};
        for (var id in ids) {
            dict[id] = document.getElementById(id).value;
    def request_and_process_element_values(ids)
      execute_script("sendValues([#{', ')}]);")
    add_action_callback('receiveValues') { |not_used, dict|
      @values = dict
    request_and_process_element_values(["elemName", "elemHeight"])

Another issue

Another issue is that your code has secret dependencies that are not obvious to a reader, namely that @dialog.request_element_value must be used before @dialog.process_values. A reader or developer (maybe you) might not know this or forget it and use these lines in opposite order or only one of both. It is totally hidden that the first method sets @values and the second method reads @values. From a code design standpoint, this is a source of errors. You can clarify such a dependency by passing the values directly, like:

values = @dialog.request_element_value("elemHeight")
dlgValues = @dialog.process_values(values)

  • You can use a library like SketchUp Bridge to do the dirty work for you and make it easier to pass values (before downloading, check out the tutorial). Your code would become something like:
@dialog.get("sendValue", "elemName").then{ |value| UI.messagebox(value) }