Safe getElementById or try to determine if an identifier exists in the GUI

The UiInstance.getElementById(ID) method always returns a GenericWidget object, even if the identifier does not exist.

Is there a way to find out if the returned object does not exist in my application, or check if the user interface contains an object with the given ID?


Solution for the user interface created using the GUI constructor:

 function getSafeElement(app, txtID) { var elem = app.getElementById(txtID); var bExists = elem != null && Object.keys(elem).length < 100; return bExists ? elem : null; } 

It returns null if the identifier does not exist. I have not tested all widgets for the key length boundary, so be careful and test it using the graphical interface.

EDIT: this solution only works in doGet() . It does not work in server handlers, so in this case use it in conjunction with @ corey-g's answer.

+4
source share
2 answers

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({}); // all widgets var button = db.query({type: 'button'}); // all buttons var foo = db.query({id: 'foo'}); // widget with id foo } 

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.

+4
source

My initial solution is wrong because it returns false controls.

A solution based on Corey's answer is to add the setTag ("") method, and here we are ready to use the code. It is only suitable for event handlers because it uses tags.

 function doGet() { var app = UiApp.createApplication(); var btn01 = app.createButton("control01").setId("control01").setTag(""); var btn02 = app.createButton("control02").setId("control02").setTag(""); var handler = app.createServerHandler("clicked"); handler.addCallbackElement(btn01); handler.addCallbackElement(btn02); btn01.addClickHandler(handler); btn02.addClickHandler(handler); app.add(btn01); app.add(btn02); return app; } function clicked(e) { var app = UiApp.getActiveApplication(); app.add(app.createLabel("control01 - " + controlExists(e, "control01"))); app.add(app.createLabel("control02 - " + controlExists(e, "control02"))); app.add(app.createLabel("fake - " + controlExists(e, "fake"))); return app; } function controlExists(e, controlName) { return e.parameter[controlName + "_tag"] != null; } 
+3
source

Source: https://habr.com/ru/post/1437746/


All Articles