我的UiBinder模板中有一个ID为“test”的div,并希望在其上执行一些jQuery的东西。如果我在我的UiBinder java类的末尾执行本机方法,则javascript调用失败,因为div似乎还没有:
public MyWidget() {
initWidget(uiBinder.createAndBindUi(this));
AppUtils.initializeSomething();
}
解决方法是使用计时器并稍微延迟我的JS代码。这有效,但在我看来非常难看。如果UiBinder模板已完全加载,是否有任何干净的解决方案来执行我的javascript?
public MyWidget() {
initWidget(uiBinder.createAndBindUi(this));
new Timer(){
@Override
public void run() {
AppUtils.initializeSomething();
};
}.schedule(1000);
}
原生方法:
public static native void initializeSomething()/*-{
$wnd.$('#test').doSomeJsStuff();
}-*/;
答案 0 :(得分:1)
public MyWidget() { initWidget(uiBinder.createAndBindUi(this)); AppUtils.initializeSomething(); }
由于这只是构造函数,此时DOM元素都存在,但尚未附加,因此任何尝试查找附加dom元素的代码都将失败(例如,jQuery将尝试{{1找出document.getElementById
,由于小部件尚未附加到文档,因此会失败。
相反,您有两个基本选项:
运行初始化只是已经知道要修改哪个元素。由于您使用的是uiBinder,因此可以在Java类中创建一个$('#test')
字段,并要求将其分配给某个具有Element
属性的元素,该元素具有相同名称的ui:field
属性。这就像你当前如何将元素的ID设置为" test",然后期望用`$(' #test')找到它。像这样:
在.ui.xml文件中:
<g:HTMLPanel>
<div ui:field="testElement">...</div>
...
</g:HTMLPanel>
在.java类中:
@UiField Element testElement;
然后在您的JSNI方法中,您可以传入元素或在调用它时引用它。这是initializeSomething
和构造函数的样子:
public MyWidget() {
initWidget(uiBinder.createAndBindUi(this));
AppUtils.initializeSomething(this.testElement);
}
public static native void initializeSomething(Element elt)/*-{
//jQuery lets you wrap a dom element instead of finding it,
//and we already know where it is
$wnd.$(elt).doSomeJsStuff();
}-*/;
接下来,等到附加到DOM运行doSomeJsStuff()
- 两种简单的方法。在原始JS中,你是第一种方式,尽管我认为这对JS来说是非常错误的。所以这是第一个错误的方式:
//make the elements
MyWidget widget = new MyWidget();
//attach them to the dom (note that if you attach to a different
// parent, that parent too must be attached
// and so on).
RootPanel.get().add(widget);
//now that we are attached, run the setup code!
widget.doSomeJsStuff();
这显然是愚蠢的 - 我们正在写一堂课,那堂课应该足够聪明,能够照顾好自己!
让我们再试一次,这次指示班级在附加后运行doSomeJsStuff()
。有两种方法可以完成这项工作,onAttach
和onLoad
- 没有关于doSomeJsStuff
做什么的具体细节,我不知道你需要什么,但是{{1是一个更容易使用的人。
重要的是要注意,每次附加小部件时都会调用这些方法,而不仅仅是第一次。如果这对您很重要,您可能需要检查是否尚未附加小部件。如果没有,我们所需要的只是:
onLoad