Open stefanuebe opened 2 years ago
Not sure if enhancement is the correct tag, might also be counted as bug.
Samples to reproduce the issue - simply comment out different use cases
@Route(value = "sample")
public class SampleView extends VerticalLayout {
public SampleView() {
Button button1 = new Button();
Button button2 = new Button();
Button[] buttonArray = Stream.of(button1, button2).toArray(Button[]::new);
Element[] elements = Stream.of(buttonArray).map(Component::getElement).toArray(Element[]::new);
// using components directly - exception
getElement().executeJs("console.warn($0, $1, $2)", "foo", "bar", buttonArray);
// using elements - exception
getElement().executeJs("console.warn($0, $1, $2)", "foo", "bar", elements);
// trying different flow internal approaches
// encode - shows an array on the client side, but all null
getElement().executeJs("console.warn($0, $1, $2)", "foo", "bar", toJsonArray(elements));
// append and then encode - the elements are displayed in the ui, but the console output still shows an array of null values
getElement().appendChild(elements);
getElement().executeJs("console.warn($0, $1, $2)", "foo", "bar", toJsonArray(elements));
// json utils - exception
getElement().executeJs("console.warn($0, $1, $2)", "foo", "bar", JsonUtils.listToJson(Arrays.asList(elements)));
// append and use multiple calls - this works
getElement().executeJs("console.warn($0, $1)", "foo", "bar");
getElement().appendChild(elements);
getElement().executeJs("console.warn($0)", elements);
}
private static JsonArray toJsonArray(Element[] pElements) {
JsonArray array = Json.createArray();
for (int i = 0; i < pElements.length; i++) {
array.set(i, JsonCodec.encodeWithTypeInfo(pElements[i]));
}
return array;
}
}
A simple workaround to allow the call of a single method with some automatic parsing of nested arrays.
public static void callFunctionWithDynamicParams(Element pElement, String pMethod, Serializable... pParameters) {
int i = 0;
String paramVars = "";
List<Serializable> expandedParams = new LinkedList<>();
for (Serializable parameter : pParameters) {
if (parameter instanceof Serializable[] a) {
paramVars += "[";
for (Serializable o : a) {
paramVars += "$" + i++ + ",";
expandedParams.add(o);
}
paramVars = paramVars.substring(0, paramVars.length() - 1) + "]";
} else {
paramVars += "$" + i++ + ",";
expandedParams.add(parameter);
}
}
if(paramVars.endsWith(","))
paramVars = paramVars.substring(0, paramVars.length() - 1);
pElement.executeJs("this." + pMethod + "(" + paramVars + ")", expandedParams.toArray(new Serializable[0]));
}
Describe your motivation
Simple example: I want to call a javascript method and pass some simple parameters plus an array of components. I tried several different approaches to get this working, but found none. I tried converting the components to elements and then to a json array, but that does not work. Using the JsonUtils also threw exceptions. Not sure how such an use case can be realized atM.
Describe the solution you'd like
The JsonCodec, which is used to serialize JS parameters, should be extended to support different types of common iterables. Those iterables would be converted to a JsonArray.
Supported types should be:
Potential alternatives
I tried several:
This for instance did not work, it just threw another exception:
Same, when trying to use the JsonUtils for conversion:
The only workaround that I found is to split the calls into multiple calls:
Sample exception
Part of an exception stack thrown, when an array is passed (in this case an array of Element)