This will only work in the same execution in which you created the widget, and not in the subsequent event handler where you retrieve the widget, because in this case everything is GenericWidget, whether it exists or not.
You yourself can make sure that the solution is not implemented:
function doGet() { var app = UiApp.createApplication(); app.add(app.createButton().setId("control").addClickHandler( app.createServerHandler("clicked"))); app.add(app.createLabel(exists(app))); return app; } function clicked() { var app = UiApp.getActiveApplication(); app.add(app.createLabel(exists(app))); return app; } function exists(app) { var control = app.getElementById("control"); return control != null && Object.keys(control).length < 100; }
The application will print βtrueβ first, but in the click handler it will print βfalseβ for the same widget.
It is by design; GenericWidget is a "pointer" of widget views in a browser. We donβt keep track of which widgets you created to reduce data transfer and the delay between the browser and your script (otherwise we would have to send a long list of which widgets exist for each event handler). You have to keep track of what you have created and only βaskβ about widgets that you already know (and that you already know the βrealβ type).
If you really want to keep track of which widgets exist, you have two main options. First, you need to write entries in ScriptDb when creating widgets, and then view them later. Something like that:
function doGet() { var app = UiApp.createApplication(); var db = ScriptDb.getMyDb(); // You'd need to clear out old entries here... ignoring that for now app.add(app.createButton().setId('foo') .addClickHandler(app.createServerHandler("clicked"))); db.save({id: 'foo', type: 'button'}); app.add(app.createButton().setId('bar')); db.save({id: 'bar', type: 'button'}); return app }
Then in the handler you can see what is there:
function clicked() { var db = ScriptDb.getMyDb(); var widgets = db.query({});
Alternatively, you can do this exclusively in UiApp using tags
function doGet() { var app = UiApp.createApplication(); var root = app.createFlowPanel(); // need a root panel // tag just needs to exist; value is irrelevant. var button1 = app.createButton().setId('button1').setTag(""); var button2 = app.createButton().setId('button2').setTag(""); // Add root as a callback element to any server handler // that needs to know if widgets exist button1.addClickHandler(app.createServerHandler("clicked") .addCallbackElement(root)); root.add(button1).add(button2); app.add(root); return app; } function clicked(e) { throw "\n" + "button1 " + (e.parameter["button1_tag"] === "") + "\n" + "button2 " + (e.parameter["button2_tag"] === "") + "\n" + "button3 " + (e.parameter["button3_tag"] === ""); }
This will throw:
button1 true button2 true button3 false
because there are buttons 1 and 2, but 3 are not. You can get affection by storing the type in the tag, but thatβs enough to test the existence of the widget. It works because all children of the root are added as callbacks, and tags for all callbacks are sent along with the handler. Please note that this is as expensive as it seems, and an application with a huge number of widgets can potentially affect performance, although in many cases this is probably good, especially if you only add root as a callback element for handlers that actually in fact, you need to check the existence of arbitrary widgets.