When you write YML user interface descriptions, you can statically set the values of any properties available for the particular Item type. For example
Text {
id: dayofweek
color: "blue"
text: "Today is Monday"
}
However, it is often the case you need to dynamically read or set new values for properties from your extension Java code. This can be achieved using the property()
and setProperty()
functions of the Pendant API service.
To reference the property of an item, requires referencing the item itself, which means you'll need to give the item an id
, as above in which the Text
item has id: dayofweek
. Item IDs must start with a lower-case letter. Then you can write:
pendant.setProperty("dayofweek", "text", "Today is Sunday");
pendant.setProperty("dayofweek", "color", "#000000"); // black
Property values can be read back using property()
:
System.out.println(pendant.property("dayofweek", "text"));
The appropriate Java type for the value depends on the property type in question. In this case is it String
for a string
property.
You may not always need to read property values using property()
since many event types include relevant property values. For example, the TextField
's TextEdited
event includes the text
property that was edited. You can println
events to see what field they include.
During development and debugging, it can be useful to add:
extension.outputEvents = true;
in your initialization, which will cause all received events to be output. Don't forget to disabled it for production!
You'll notice that the property(String itemID, String name)
Java API function actually returns an object of class Any
. The Any
type is a union wrapper around other types, so that it can hold values of any API type at run-time. You can see its definition in the Thrift API IDL as:
union Any {
1: bool bValue;
2: i64 iValue;
3: double rValue;
4: string sValue;
5: Vector vValue;
6: Position pValue;
7: list<Any> aValue; // aka array
8: map<string, Any> mValue;
}
The Java implementation of class Any
(generated by Thrift) uses idiomatic Java getter and setter methods, so to retrieve the String
value of an Any
result requires calling the getSValue()
method. You can also set the value using the setSValue(String)
method. Note that an exception will be thrown if you call get for the wrong type (e.g. getIValue()
on an Any
object currently holding a String
). To check if an Any
object is holding a particular type, use the methods isSetBValue()
, setSetIValue()
etc.
import yaskawa.ext.api.Any;
...
Any a = pendant.property("dayofweek", "text");
System.out.println(a.isSetSValue()); // true - text is a String
System.out.println(a.getSValue()); // e.g. "Today is Monday"
System.out.println(a.isSetRValue()); // false - not a double (real)
a.setIValue(10); // change type of local var a to int and value to 10
System.out.println(a.isSetIValue()); // true
System.out.println(a.getIValue()); // 10
If you have a moderate number of properties to be set at one time, it can be more efficient to set them via a single API call to setProperties()
, than one call to setProperty()
for each property. Using setProperties()
directly as it is specified in the raw API can be tedious, so the Java client library provides some convenience functions so that is may be used as follows:
import static yaskawa.ext.Pendant.propValue;
var propList = List.of(propValue("item1id","color", "red"),
propValue("item1id","bgcolor", "green"),
propValue("item2id","color", "orange"),
propValue("item3id","width", 400.0)
);
pendant.setProperties(propList);
The setProperty()
function is a synchronous blocking call, so it incurs one round-trip from your extension to the API for each call. In contrast, the setProperties()
function is asynchronous - it returns immediately without waiting for any response from the API (which also means no errors can be caught).
As evidenced by the definition of the Any
type above, it can also hold list and map (dictionary) values. In particular, lists of Any
or maps of strings to Any
; which implies the elements of a list or map values can themselves be lists or maps, allowing indefinite nesting to represent complex objects.
If you want to update the list of string options for a ComboBox
, you might write:
pendant.setProperty("myselector", "options", new String[] {"Option1", "Option2", "Option3"});
Recall that YML allows declaration of your own properties. Consider:
Item {
id: myitem
// a map in which key d is a list and key e is a nested map
property map mymap: { a: 1, b:2, "c":3, d:[1,2,3], e:{aa:"AA", bb:"BB"} }
}
// update mymap property to have a map of three Strings
pendant.setProperty("myitem", "mymap", Map.of("a",3,"b",4,"c",5));