class UIInstance getElementById(id) returns a Generic object if the widget is a ListBox - listbox

I have an app, which display a panel with fields filled from a document.
The user edit the fields, and the updated values updates the document.
Everything is working, with one exception.
The panel has several TextBox and a ListBox. When the panel is displayed, a function fills the values in the text boxes. It uses getElementById in order to get the widgets.
I would like to show the ListBox with the proper value already selected. Unfortunately, the getElementById on this widget returns a Generic, and the standard methods of ListBox aren't available.
Here is a fragment of code:
function fillSingleDocFields(meta, app) {
var eleTitolo = app.getElementById('idnomeDoc'); // OK!
eleTitolo.setText(meta.titolo);
var lbTipologia = app.getElementById('idtipologia');
Logger.log(lbTipologia); // KO
setListBoxSelected(lbTipologia, meta.tipologia);
return app;
}
the setListBoxSelected function fails on the first ListBox specific method:
function setListBoxSelected(lb, value) {
for (var i=0;i<lb.getItemCount();i++) // runtime error
{
if ( lb.getValue(i) == value)
lb.setSelectedIndex(i);
}
}
The error is (translated from italian): no getItemCount function in Generic object.
Here is the code execution transcript:
[13-07-08 12:13:01:691 CEST] (class).getElementById([idnomeDoc]) [0 secondi]
[13-07-08 12:13:01:692 CEST] (class).setText([mio titolone 2]) [0 secondi]
[13-07-08 12:13:01:692 CEST] (class).getElementById([idtipologia]) [0 secondi]
[13-07-08 12:13:01:692 CEST] (class).toString() [0 secondi]
[13-07-08 12:13:01:692 CEST] (class).toString() [0 secondi]
[13-07-08 12:13:01:692 CEST] Logger.log([Generic, []]) [0 secondi]
[13-07-08 12:13:01:693 CEST] (class).toString() [0 secondi]
[13-07-08 12:13:01:735 CEST] Esecuzione non riuscita: TypeError: Impossibile trovare la funzione getItemCount nell'oggetto Generic. (riga 29, file "Controller") [0.404 secondi di esecuzione totale]
A possible solution could be to set the selected value in the ListBox when I create it, but unfortunately, at that moment, that values is unknown.
My questions are:
is it possible to cast the result of getElementById? (I don't think so, looking to similar questions);
is there something wrong in my approach? Or is the getElementById always returning Generic objects (this contrast with other answers).
Thanks

Your issue is not with the generic widget returned by getElementById. Which, even though does not autocomplete specific methods anymore, still accepts that you call it.
The issue is that the ListBox object does not have a getItemCount method. Here's is a quick test:
function testList() {
var app = UiApp.createApplication().setTitle('Test');
var list = app.createListBox().addItem('test');
Logger.log(list.getItemCount());
return app.add(list);
}
And for that matter, it also does not have a getValue method.
Usually Apps Script widgets does not have such methods (for you to get things). You have to either know that beforehand or get it from a callback-element, by inspecting the parameter passed to your callback-handler function.

Unfortunately there is no implementation of this function. (see issue)
But you can pass values ​​through the callback in handler function. See example.
function ui(){
var app = UiApp.createApplication();
var lb = app.createListBox().setName('lb'); //not id
lb.addItem('first item').addItem('second item');
var hndlr = app.createServerHandler('send')
.addCallbackElement(lb); //be sure to add callback
var btn = app.createButton('SEND');
btn.addClickHandler(hndlr);
app.add(lb).add(btn);
SpreadsheetApp.getActiveSpreadsheet().show(app);
}
function send(e){
var app = UiApp.getActiveApplication();
var lbValue = e.parameter.lb; //selected value
//do somethink with lbValue
app.add(app.createLabel(lbValue));
return app;
}

Related

A list of Dart StringBuffers seem to interfere with each other

I'm doing a nested iteration over two lists, in which I am populating some StringBuffers, like this:
var int_list = [1, 2, 3];
var letters_list = ['a', 'b', 'c'];
var row_strings = List.filled(3, StringBuffer());
var single_buffer = StringBuffer();
int_list.asMap().forEach((int_index, column) {
letters_list.asMap().forEach((letter_index, letter) {
// debug the writing operation
print('writing $letter_index - $letter');
row_strings[letter_index].write(letter);
// try a buffer not in a list as a test
if (letter_index == 0) {
single_buffer.write(letter);
}
});
});
print(single_buffer);
print(row_strings);
What I expect to happen is that in the list of StringBuffers, buffer 0 gets all the 'a's, buffer 1 gets all the 'b's, and buffer 3 the 'c'.
The debug output confirms that the writing operation is doing the right thing:
writing 0 - a
writing 1 - b
writing 2 - c
writing 0 - a
writing 1 - b
writing 2 - c
writing 0 - a
writing 1 - b
writing 2 - c
and the single string buffer gets the right output:
aaa
But the output of the list is this:
[abcabcabc, abcabcabc, abcabcabc]
What is going on here? There seems to be some strange behaviour when the StringBuffers are in a list.
Your problem is this line:
var row_strings = List.filled(3, StringBuffer());
This constructor is documented as:
List.filled(int length, E fill, {bool growable: false})
Creates a list of the given length with fill at each position.
https://api.dart.dev/stable/2.10.5/dart-core/List/List.filled.html
So what you are doing is creating a single StringBuffer instance and uses that on every position in your row_strings list.
What you properly want, is to create a new StringBuffer for each position in the list. You need to use List.generate for that:
List.generate(int length,E generator(int index), {bool growable: true})
Generates a list of values.
Creates a list with length positions and fills it with values created by calling generator for each index in the range 0 .. length - 1 in increasing order.
https://api.dart.dev/stable/2.10.5/dart-core/List/List.generate.html
Using that, we end up with:
final row_strings = List.generate(3, (_) => StringBuffer());
We don't need the index argument in our generator so I have just called it _. The function (_) => StringBuffer() will be executed for each position in the list and saved. Since out function returns a new instance of StringBuffer each time it is executed, we will end up with a list of 3 separate StringBuffer instances.

box callback functions returning the same string in Rascal

I'm trying to draw some boxes in Rascal and trying to give each box its own callback function. On entering the box with the mouse the corresponding string should get displayed in the text element (so hovering box1 should display box1 etc.).
However, at the moment the text does pop up but just displays "box3" for each of the 3 boxes.
Any ideas?
strings = ["box1", "box2", "box3"];
boxes = [ box(
size(100, 100),
onMouseEnter(void() {
output = s;
})
) | s <- strings];
render(hcat([
vcat(boxes),
text(str () {return output;})
]));
Good question, classical problem. The essence of the problem is that Rascal uses "non-capturing closures": this means that functions that are returned from another function share the same context. In your case this is the variable s introduced by s <- strings. This nearly always happens when you create function values in a loop (as you do here). The solution is to wrap another function layer around the returned function.
Here is a simple example:
list[int()] makeClosures()
= [ int() {return i;} | i <- [0,1,2]];
void wrong(){
lst = makeClosures();
println(lst[0]());
println(lst[1]());
println(lst[2]());
}
which will print surprisingly the values 2,2and2`. The solution is, as said, to introduce another function level:
int() makeClosure(int i)
= int() { return i;};
list[int()] makeClosuresOK()
= [ makeClosure(i) | i <- [0,1,2]];
void right(){
lst = makeClosuresOK();
println(lst[0]());
println(lst[1]());
println(lst[2]());
}
now calling right() will print 1, 2, and 3 as expected.
I leave it as an exercise how this is done in your example, but I am prepared to give a solution when you ask for it. Good luck!

onFullSync action, show updated info - DHTMLX Grid + RoR

I have a Ruby on Rails project where I use a DHTMLX Grid.
Is there a way of showing, using the event handler "onFullSync" provided by the grid API, to show updated data?
Let me explain a little better... I know I can do something like:
dp.attachEvent("onFullSync", function(){
alert("update complete");
})
But what I want is something more complex. I want to, after each completed update, alter a div adding the information like this:
Field 2 was updated to XYZ and field 3 was updated to XER on line X
Field 1 was updated to 123 and field 3 was updated to XSD on line Y
Is this possible?
Thanks
There is a onAfterUpdate event that can be used similar to onFullSync
http://docs.dhtmlx.com/api__dataprocessor_onafterupdate_event.html
It will fire after each data saving operation ( if you are saving 5 rows - it will fire 5 times )
Still, info about updated columns will not be available here.
Also, you can try onEditCell event of grid. It fires after changing data in db, but before real saving in database. Here you can get all necessary info - row, column, old value and new value.
http://docs.dhtmlx.com/api__link__dhtmlxtreegrid_oneditcell_event.html
So, what I end up doing was:
After creating the grid I created an array:
var samples = [];
Then, as per #Aquatic suggestion, I added to "onEditCell" event the following line:
samples[samples.length] = grid.cells(rId, 5).getValue();
This allowed me to add to the array the value present on column 5 of the row changed. Then, on "onFullSync" event I hide or show the div created on the view with the messages (I distinguish if it's on row or more changed on the grid).
//Deals with messages after update
dp.attachEvent("onFullSync", function(){
unique_samples = uniq_fast(samples.sort());
if (unique_samples.length == 1){
$('#updated-samples').text("");
$(".messages").show();
$('#updated-samples').text("A seguinte amostra foi actualizada: " + unique_samples[0]);
//to clear the array
samples = [];
} else if (unique_samples.length > 1){
$('#updated-samples').text("");
$(".messages").show();
$('#updated-samples').text("As seguintes amostras foram actualizadas: " + unique_samples.sort().join(", "));
//to clear the array
samples = [];
} else {
$('#updated-samples').text("");
$(".messages").hide();
//to clear the array
samples = [];
}
})
The problem with using "onEditCell" is that everytime a field is changed on that row I get a repeated value on my "samples" array, I I had to remove duplicate from that array. For that I used one of the suggestions at this answer
// remove duplicates in array
function uniq_fast(a) {
var seen = {};
var out = [];
var len = a.length;
var j = 0;
for(var i = 0; i < len; i++) {
var item = a[i];
if(seen[item] !== 1) {
seen[item] = 1;
out[j++] = item;
}
}
return out;
}
Then I have on the beginning of the view, to show the messages:
<div class="alert alert-success messages" id="updated-samples">
And that's it. I could be not the most efficient way but it works for what I wanted. I will leave the question open a few more days to see if any other option appears.

Using array notation instead of NSM on functions deeper then js.context.X

Can all objects after js.context be accessed with array notation from Dart? For example, I'd like to convert the following to use array notation:
var request = js.context.gapi.client.request(js.map(requestData));
Will the following array notation work?
var request = js.context['gapi']['client']['request'](js.map(requestData));
Also, should the following be done if trying to access JavaScript builtin methods?
js.context['JSON']['stringify'](jsonResp);
TL;DR : Starting from r24278 use array notation for properties and noSuchMethod for methods.
Using js.context['gapi']['client'] gives the same result as js.context.gapi.client. The main advantage of Array notation is that it avoids noSuchMethod. Until recently it was the only way to work around an issue in dart2js where minified does not work with noSuchMethod. This issue is fixed, and minification should work with Dart-JS interop.
I did a little benchmark some times ago :
For attribute access : array notation is around 10% faster than noSuchMethod. ( js.context.x vs. js.context['x'] )
For method access : array notation is around 50% slower than noSuchMethod. ( js.context.f() vs. js.context['f']() )
This last result is explained by 2 communications between JS and Dart for js.context['f'](). One to retrieve the function reference ( js.context['f'] ) and an other to call this function.
Last concern, using noSuchMethod can increase your dart2js result size (but not so much where I had tested it).
This works for me:
var hug = new js.Proxy(context['Hug']);
var hugDatabase = new js.Proxy(context['HugDatabase']);
hugDatabase['addHug'](hug);
print(hugDatabase['hugs']['length']);
Which interacts with this JavaScript:
function Hug(strength) {
this.strength = strength;
}
Hug.prototype.embrace = function(length) {
return 'Thanks, that was a good hug for ' + length + ' minutes!';
}
Hug.prototype.patBack = function(onDone) {
onDone('All done.');
}
function HugDatabase() {
this.hugs = [];
}
HugDatabase.prototype.addHug = function(hug) {
this.hugs.push(hug);
}
The full example is here: https://github.com/sethladd/dart-example-js-interop/blob/master/web/dart_js_interop_example.dart

Google Custom Function : error Invalid assignment left-hand side

I've created a custom google spreadsheet function via the script editor that calculates pace. I call the function in my spreadsheet via
=pace(00:33:00,10,km)
and the logic for the function is
function pace(time, dist, unit)
{
return pace(time.getHours(),time.getMinutes(),time.getSeconds(), dist, unit);
}
function pace(hrs,mins,secs,dist,unit)
{
var d = dist;
if(unit=="m"||unit="M")
d = dist*1.609344;
var minutes = 60*hrs+mins+secs/60.0;
var pace = minutes/d;
return pace;
}
but when the function is executed all i get is
error: Invalid assignment left-hand side.
I think the logic is correct and the issue is related to the publication status of the script?
H,
It seems you are missing and equal sign in the second argument to your if statement.
if(unit=="m"||unit=="M")

Resources