GWT widget with JSNI not attached yet - gwt

I created a widget that extends SimplePanel and execute some JSNI in onLoad() method:
public class AceEditor extends SimplePanel implements HasText {
private JavaScriptObject editor;
#Override
protected void onLoad() {
super.onLoad();
editor = createEditor(getElement());
}
private static native JavaScriptObject createEditor(Element element) /*-{
return $wnd.ace.edit(element);
}-*/;
#Override
public native void setText(String value) /*-{
this.#org.obiba.opal.web.gwt.ace.client.AceEditor::editor.setValue(value);
}-*/;
#Override
public final native String getText() /*-{
return this.#org.obiba.opal.web.gwt.ace.client.AceEditor::editor.getValue();
}-*/;
}
The problem is when I call setText for the first time, the widget is not attached yet (onLoad was not called yet).
I use this widget with UiBinder.
I could use addAttachHandler and check if the widget is attached but it does not seem the right way to do it...
Any idea of why the widget is not attached sooner?

Can you put the call to createEditor in the constructor instead of onload ?
It seems that your code is calling the setText before the page is loaded.
Now if that is the case calling createEditor in the constructor should be proper.

Any idea of why the widget is not attached sooner?
By definition, it shouldn't be 'attached' until after you've added it to an already-attached parent (either to RootPanel, or another thing already added to RootPanel). Have you done so and onLoad still isn't called?
If your JS tool (in this case ace) requires that a DOM node exists, then you don't need to wait for onLoad to be called to do anything - as of your Widget subclass's constructor being finished, you must already have specified an element.
If you actually require that this element is attached to the document before you can perform operations on it, then yes, of course, you need to wait until onLoad is called.

Related

Diff between get.put and get.lazyput

I am new to Getx's dependency injection, so can some one explain to me the benefits of Get.put() and Get.lazyPut() and tell me also what difference they have?
Short answer
Get.put() will put immediately
Get.lazyPut() will put when you need it
To my understanding put already puts an instance of the class directly in memory while lazyPut just puts a builder for it in it.
A benefit of lazyPut is that it saves memory until you actually find it. And you can also put more complex code in the builder for it. Another benefit of lazyPut is that you can also say fenix: true on it which means it's able to be reconstructed in case it got disposed of before.
I would think the only benefit of using put is that find should be slightly faster then when called because it doesn't need to call a builder first to get the instance. I don't know if there are other benefits.
In the case of lazyPut, it only creates the instance, and it'll be instantiated only when is used, check more details here
Get.put() :
Will inject a dependency and start executing immediately when it's injected, and I mean with that that its lifecycle methods like onInit() and onReady() will execute when you inject it like this:
class ControllerOne extends GetxController {
int a = 1;
#override
void onInit() {
print('ControllerOne onInit');
super.onInit();
}
#override
void onReady() {
print('ControllerOne onReady');
super.onReady();
}
}
final controller = Get.put(ControllerOne()); // will inject that dependecy, and immediately will call onInit() method then onReady() method
Debug log:
ControllerOne onInit
ControllerOne onReady
Get.lazyPut() :
will also inject a dependency, but it will not start executing the lifecycle methods onInit() and onReady() until you will really use that controller:
class ControllerTwo extends GetxController {
int b = 2;
#override
void onInit() {
print('ControllerTwo onInit');
super.onInit();
}
#override
void onReady() {
print('ControllerTwo onReady');
super.onReady();
}
}
final controller = Get.lazyPut(() => ControllerTwo()); // will inject that dependecy, and wait until it's used then it will call onInit() method, then onReady() method
Debug log:
/* nothing will be printed right now */
but if we do use the controller, as an example:
controller.b = 10;
then the controller will start running will start:
Debug log:
ControllerTwo onInit
ControllerTwo onReady
Hope this clarifies it!

Get Route arguments through BuildContext requires putting it inside build()?

From https://docs.flutter.dev/cookbook/navigation/navigate-with-arguments it appears the preferred way of getting the arguments from a route is using:
ModalRoute.of(context)!.settings.arguments;
But since it requires the context argument it must be called inside the build method:
Widget build(BuildContext context) {
String id = ModalRoute.of(context)!.settings.arguments as String;
var data = httpGet(id);
return Scaffold(
//...
);
}
This means that every time the widget is rebuilt, the route argument will be refetched all over again and possibly another network call too.
The obvious solution is to have a boolean like wasFetched somewhere and add a conditional inside the build method.
Are most people doing the latter?
Edit:
Based on the first reply be #miguel-ruivo, I learned that context can actually be accessed as a property on the State object, and therefore accessible from initState.
In the end I went down the rabbit hole and found that I could call it from didChangeDependencies without needing to use addPostFrameCallback from WidgetsBindings.instance.
According to:
https://api.flutter.dev/flutter/widgets/State/didChangeDependencies.html
It says:
This method is also called immediately after initState. It is safe to
call BuildContext.dependOnInheritedWidgetOfExactType from this method.
Some subclasses do override this method because they need to do some
expensive work (e.g., network fetches) when their dependencies change,
and that work would be too expensive to do for every build.
And since it says dependOnInheritedWidgetOfExactType is safe to call, it would follow that anything dependent on BuildContext is safe to call.
So now I have put the code inside it:
didChangeDependencies() {
String id = ModalRoute.of(context)!.settings.arguments as String;
//do http
}
You can call it only once per widget initialisation by moving it to your initState() and scheduling a post frame so it only accesses BuildContext after rendering.
#override
void initState() {
WidgetsBinding.instance.addPostFrameCallback(() {
String id = ModalRoute.of(context)!.settings.arguments as String;
var data = httpGet(id);
});
}
You can actually access context in your initState method without having to pass it as a parameter.
class _YourScreenState extends State<YourScreen> {
late String? id;
#override
void initState() {
super.initState();
id = ModalRoute.of(context)!.settings.arguments as String?;
}
}

Flame onLoad vs constructor initialization

If I create a component in Flame like this:
class MyComponent extends PositionComponent {
MyComponent() {
// Option 1
}
#override
Future<void> onLoad() {
// Option 2
}
}
What difference does it make if I initialize my component in the constructor (Option 1) or the onLoad method (Option 2)?
If you have things that need to load before the component is added to the game, like an image for example, then you need to do that loading in onLoad so that the game knows that it shouldn't add your component to the game until everything in there is loaded. For example:
class MyComponent extends PositionComponent {
#override
Future<void> onLoad() async {
final sprite = await loadSprite('flame.png');
}
}
So to make your code consistent you can do all your initialization in onLoad, even if it is not needed for all your components.
Another good thing to know about onLoad is that if your are using the HasGameRef mixin the gameRef will be set to your component in onLoad, but not in the constructor.

difference between running a method before super.initState() and after super.initState()

what is the difference between running a method before super.initState() and after super.initState()
#override
void initState() {
super.initState();
getCurrentUser();
}
#override
void initState() {
getCurrentUser();
super.initState();
}
Explanation for framework: Dart is class based object oriented programming language, so when you build a widget you extend it from a base class StatelessWidget or StatefulWidget. initState is lifecycle method in flutter widget (as you might know) which is only available to override in StatefulWidgets and it called only once. So, it call initState of base class which is StatefulWidget thats why you call super.initState()which in turn creates BuildContext and attached State.
Now your question: I didn't find anything different in calling a method before or after super.initState(). Event I tried adding addPostFrameCallback before super.initState() and it worked fine.
Even super.mounted is also true in both cases.
Suggestion
Dart/Flutter documentation "suggests" to call super.initState() as first method before your body implementation.
But if we look at how it is implemented Documentation
#protected
#mustCallSuper
void initState() {
assert(_debugLifecycleState == _StateLifecycle.created);
}
it's possible to see that it contains only an assert(). the assert built-in function it's called only in DEBUG mode, not in production mode. So, at the end of the day, it really doesn't matter, because the super.initState() would practically do nothing.

How to add a click listener to an InputElement in GWT?

I've created the following checkbox
import com.google.gwt.dom.client.InputElement;
...
final InputElement bulkEditCheckbox = Document.get().createCheckInputElement();
Tried many formulas, but just can't wrap it or add a listener to it. Any suggestions?
PS: getting the following error when trying to wrap with SimpleCheckBox.wrap():
‘A widget that has an existing parent widget may not be added to the detach list’
This fixed my issue:
DOM.sinkEvents(element, Event.ONCLICK);
DOM.setEventListener(element, new EventListener() {
#Override
public void onBrowserEvent(Event event) {
if (Event.ONCLICK == event.getTypeInt()) {
...
}
}
});