Access object field in a loop
Opened this issue · 4 comments
Current state
I have a collection of objects, this is working:
@LmlAction("blocks")
public Array<Block> getBlocks() {
return level.blocks;
}
<:foreach element="$blocks">
<textbutton color="red">{element}</textbutton>
</:foreach>
public class Block {
public boolean isWritten = false;
@Override
public String toString() {
return isWritten ? "x" : " ";
}
}
Goal
I'd like to colorize "x" blocks to red based on isWritten
field.
Problem
Accessing the isWritten
field is the unknown to me. How do I do that?
I thought about 2 ways:
- pass the
element
(or index) to a method to evaluate it - access the field directly from the template which doesn't work for me:
<:foreach element="$blocks">
<textbutton color="red">{element.isWritten}</textbutton>
</:foreach>
Try using the condition syntax. It should work similarly to this:
<textbutton color="{? '{element}' = 'x' ? red : default}">{element}</textbutton>
You'd have to check if conditions support executing methods, but I'm positive that they just might.
Also, loops support going through multiple collections at once. While it isn't an ideal solution, you can also do something like this:
// Java 8-ish pseudo-code:
@LmlAction("blocksWritten")
public Array<Boolean> getBlocksWrittenStatus() {
return level.blocks.map(Block::isWritten);
}
<:foreach element="$blocks" isWritten="$blocksWritten">
<textbutton color="{? {isWritten} ? red : white}">{element}</textbutton>
</:foreach>
Thank you for your kind response.
1. Workaround but not a solution
This 'x' comparison would be a workaround, I know that. But, there are going to be more booleans than just isWritten
. So, neither is a solution for me.
2. Obfuscation?
I've seen between threads that obfuscation matters so Java things should be named with LmlAction
annotation to be accessible from a template. However, actor macro doesn't seem to fit this rule:
- https://github.com/czyzby/gdx-lml/blob/master/examples/gdx-lml-tests/assets/templates/examples/actorMacro.lml
- https://github.com/czyzby/gdx-lml/blob/master/examples/gdx-lml-tests/core/src/main/java/com/github/czyzby/tests/reflected/MainView.java#L232
Thus, I think either the macro should be "fixed" (please don't) or field access from a template (stated in this thread) should be supported :)
3. Redraw
However, the worst thing is I realized all of this probably won't automatically update since there is no change detection. What would be the way to properly redraw some elements (taking fresh data from Java part), then?
I'm sorry for asking so many things but it's all related and I'd like to keep the same context.
This 'x' comparison would be a workaround, I know that. But, there are going to be more booleans than just
isWritten
. So, neither is a solution for me.
I'm sorry to hear that. If field access does not work, I'm afraid you're stuck with the workarounds or doing part of the job in Java, as LML is in maintenance mode.
I've seen between threads that obfuscation matters so Java things should be named with
LmlAction
annotation to be accessible from a template. However, actor macro doesn't seem to fit this rule:
@LmlAction
is encouraged, but not necessary. If no annotated method is found, the parser looks for methods by name from any registered action containers.
Field access is somewhat supported, as I recall, in a sense that you can access a field similarly to how you would invoke a method: with $
operator. I don't think nested fields are supported though.
What would be the way to properly redraw some elements (taking fresh data from Java part), then?
You should implement your listeners in Java. All properties that are available in LML, are simple Java methods that you can call in your views. Look into @LmlActor
and getting references to the widgets from LML templates.
I'm sorry for asking so many things but it's all related and I'd like to keep the same context.
It's OK, I'm happy to help.