I face problem when I try to get return value from an action callback and the value that is read by Javascript is always undefined. I already read some posts that discuss the same issues like here and here and also read docs about add_action_callback but unfortunately I failed to implement it to my code.
Here is my code in Ruby side:
# add callback to calculate QTO
@dlg.add_action_callback("calculate") { |action_context|
self.export_qto()
}
def self.export_qto()
# grab active model
model = Sketchup.active_model
# initiate selected entities total volume
message = "Volume of all selected entities: \n"
vol = 0.0
# select entities
selected = model.selection
if (selected.length > 0)
selected.each { |item|
if (item.typename == 'Group')
if (item.volume != -1)
vol = vol + item.volume
message = message + item.definition.name + '(' + item.typename + ')' + ': ' + format_volume_in_model_units(item.volume, 2) + "\n"
end
end
}
puts message
message
else
UI.messagebox('No entities selected. Select entities and try again!', type=MB_OK)
end
end
And here is my code in Javascript side:
function calculate() {
let hasil = []
let result = sketchup.calculate({
onCompleted: function (data) {
console.log(data)
hasil.push(data)
}
})
if (result) {
document.getElementById('hasilhitungan').innerHTML = hasil[0];
console.log('Hasil: ', hasil[0]);
}
}
Do I have to always use execute_script on the Ruby side to be able to send the return value back to Javascript? Or I could still use this approach instead?
Do you really need an html dialog? You can use a multiline message box.
You receive a string, why don’t you:
function calculate() {
let hasil = ""
sketchup.calculate({
onCompleted: function (data) {
console.log(data)
hasil = data
}
})
if (result) {
document.getElementById('hasilhitungan').innerHTML = hasil;
console.log('Hasil: ', hasil);
} else {
document.getElementById('hasilhitungan').innerHTML = "no result";
}
}
Some suggestions…
You don’t need () inside if method
if item.is_a? Sketchup::Group && item.volume != -1
instead
if (item.typename == 'Group')
if (item.volume != -1)
In the above snippet, result will be undefined because the sketchup.calculate call will return immediately. Your test if in … if (result) will likely always be false.
in other words, you’ve written the calculate function as if it’s statements will be synchronous and linear. They will not. The callbacks upon the JS sketchup object are asynchronous. So, result will always be undefined.
Ie, the call to sketchup.calculate() will return immediately with no value.
Also, it is quite likely that by the time the onCompleted JS callback gets called, that the JS function calculate will have returned and the hasil array will have gone out of scope and would have been garbage collected.
You may need to define the hasil array globally outside the calculate function.
Thanks for your reply and suggestion… Yes, I plan to improve the code so that I can send more detailed data (may be in the form of JSON) from Ruby to the HtmlDialog, not just using multiline message box.
Thanks for the correction in the way of writing the conditional and the loop…
But unfortunately I still get a null in the HtmlDialog. I tried to use the execute_script in the add_action_callback block to send the data to HtmlDialog but it still failed.
Now my code is like this in Ruby side:
@dlg.add_action_callback("calculate") { |action_context|
message = self.export_qto()
@dlg.execute_script("document.getElementById('hasilhitungan').innerHTML = '<p>Data is #{message}</p>'")
message
}
def self.export_qto()
# grab active model
model = Sketchup.active_model
# initiate selected entities total volume
message = ""
vol = 0.0
# select entities
selected = model.selection
unless selected.empty?
message = "Volume of all selected entities: \n"
selected.each { |item|
next unless item.respond_to?(:volume) && item.volume > 0
vol = vol + item.volume
message << "#{item.definition.name} (#{item.typename}): "<<
"#{format_volume_in_model_units(item.volume, 2)}\n"
}
puts message
else
message = 'No entities selected. Select entities and try again!'
puts message
#UI.messagebox(message, MB_OK)
end
return message
end
and like this in JS side:
function calculate() {
sketchup.calculate({
onCompleted: function (data) {
console.log(data)
if(data !== null && data !== undefined){
document.getElementById('hasilhitungan').innerHTML = `<p>${data}</p>`;
console.log('Hasil: ', data);
} else {
document.getElementById('hasilhitungan').innerHTML = `<p>Data is ${data}</p>`;
console.log(`Data is ${data}`)
}
}
})
}
still don’t know where my mistake is in the code…