2009-07-16 6 views
11

私は、iframe内の外部ドキュメントとやりとりするGWTアプリケーションを作成しています。コンセプトの証明として、ボタンにクリックハンドラをアタッチしようとしています。外部iFrameの要素にGWTイベントをフックする

ジャバスクリプト

GWTで同等のものをやろうとし
var iframe = document.getElementById("rawJSIFrame"); 
var doc = iframe.contentDocument; 
var body = doc.body; 
var button = doc.getElementsByTagName("input").namedItem("submit"); 
button.onclick = function() { 
    alert("Clicked!"); 
}; 

で、次の作品、私は次のようでした:

public void addClickHandlerToSubmitButton(String buttonElementName, ClickHandler clickHandler) { 
    IFrameElement iframe = IFrameElement.as(frame.getElement()); 
    Document frameDocument = getIFrameDocument(iframe); 
    if (frameDocument != null) { 
     Element buttonElement = finder(frameDocument).tag("input").name(buttonElementName).findOne(); 
     ElementWrapper wrapper = new ElementWrapper(buttonElement); 
     HandlerRegistration handlerRegistration = wrapper.addClickHandler(clickHandler); 
    } 
} 

private native Document getIFrameDocument(IFrameElement iframe)/*-{ 
     return iframe.contentDocument; 
}-*/; 

次はElementWrapperクラスです:

public class ElementWrapper extends Widget implements HasClickHandlers { 

    public ElementWrapper(Element theElement) { 
     setElement(theElement); 
    } 

    public HandlerRegistration addClickHandler(ClickHandler handler) { 
     return addDomHandler(handler, ClickEvent.getType()); 
    } 


} 

ボタンを見つけるコードは正常に動作しますが、実際のクリックイベントハンドラは呼び出されません。誰も似たような問題を以前に持っていましたが、どのように解決しましたか?事前に

おかげで、

答えて

10

HilbrandはGWTメソッドonAttach()が呼び出されなかったということで問題に関する権利である:ここではwrapメソッドを使用して変更されたコードです。

私はElementWrapperに次のメソッドを追加して、あなたのオリジナルのソリューションを実装:ElementWrapperが作成された後

public void onAttach() { 
    super.onAttach(); 
    } 

と呼ばれるには、wrapper.onAttach()を追加しました。魅力的な作品!

+0

ありがとう!私はよりクリーンな方法がなければならないことを知っていた:) – triggerNZ

0

あなたは、コードのJavaScriptのピースを再利用するためにJSNIを使用することができます。あなたのJavaScriptコードは、iframe内のボタンに代わってスローするオブジェクトに対してgwtメソッドを呼び出します。

GWTコードがうまくいかない理由は、おそらく1フレーム以上に及ぶことのない通常のブラウザイベントの上にいくつかのレイヤーを使用しているからです。それはちょうど推測です。これを機能/バグリクエストとしてGWTチームに再度提出できます。私が正しいとすれば、あなたのコードはうまく見えます。

+0

クール、返信いただきありがとうございます。私はJSNIの道を探るつもりだと思うが、私は可能な限りカスタムJavaScriptを書くことから離れたい。 – triggerNZ

1

これをさらに調査した後、iframeは無関係であることがわかりました。同じ動作は、ホストページの通常のボタンでは機能しません。

私は基本的にJSNIを使ってGWTのイベント処理メカニズムの一部を複製しています。以下の作品:

Element buttonElement = DOM.getElementById("externalButton"); 
new CustomElementWrapper(buttonElement).addClickHandler(new ClickHandler() { 
public void onClick(ClickEvent event) { 
     Window.alert("GWT hooked into button"); 
    } 
}); 

CustomElementWrapperは次のとおりです。最後

public class CustomElementWrapper extends Widget implements HasClickHandlers { 
    private ClickEventManager clickEventManager; 

    public CustomElementWrapper(Element theElement) { 
     setElement(theElement); 
     clickEventManager = new ClickEventManager(theElement); 
    } 

    public HandlerRegistration addClickHandler(ClickHandler handler) { 
     //The 'right' way of doing this would be the code below. However, this doesn't work 
     // A bug in GWT? 
     //  
     //    return addDomHandler(handler, ClickEvent.getType()); 
     return clickEventManager.registerClickHandler(handler); 
    } 


    void invokeClickHandler() { 
     clickEventManager.invokeClickHandler(); 
    } 

    public boolean isClickHandlerRegistered() { 
     return clickEventManager.isClickHandlerRegistered(); 
    } 
} 

は、実際の作業が発生しClickEventManagerは、次のとおりです。個人的に

public class ClickEventManager { 
private boolean clickHandlerRegistered = false; 
private ClickHandler clickHandler; 
private Element element; 

public ClickEventManager(Element element) { 
    this.element = element; 
} 

public void invokeClickHandler() { 
    //This shouldn't really be null but we are bypassing GWT's native event mechanism 
    //so we can't create an event 
    clickHandler.onClick(null); 
} 

public boolean isClickHandlerRegistered() { 
    return clickHandlerRegistered; 
} 

HandlerRegistration registerClickHandler(ClickHandler handler) { 
    clickHandler = handler; 

    if (!clickHandlerRegistered) { 
     registerClickHandlerInJS(element); 
     clickHandlerRegistered = true; 
    } 
    return new HandlerRegistration() { 
     public void removeHandler() { 
      //For now, we don't support the removal of handlers 
      throw new UnsupportedOperationException(); 
     } 
    }; 
} 
private native void registerClickHandlerInJS(Element element)/*-{ 
    element.__clickManager = this; 
    element.onclick 
     = function() { 
      var cm = this.__clickManager; 
      [email protected]::invokeClickHandler()(); 
     } 
}-*/; 
} 

、私が表示されますので、私はこのソリューションを憎みますGWTのイベント処理を複製し、おそらく不快なJavaScriptのメモリリークを導入する可能性があります。私の最初の投稿が機能しない理由(iframeのアスペクトは赤い鳴き声であることを覚えている)に関するアイデアは高く評価されます。

おかげで、

+0

ありがとう、ありがとう!これはIE7で動作させるために必要なものでした。 – SorcyCat

4

は、私はこの問題は、あなたの最初の例のようにラッピングを使用するときにGWTメソッドonAttach()が呼び出されていないということです期待しています。ボタンウィジェットで静的wrapメソッドを使用することができます。これを使用するには、inputbuttonである必要があります。または、wrapメソッドの実装を見てください。

Element buttonElement = finder(frameDocument).tag("input").name(buttonElementName).findOne(); 
Button button = Button.wrap(buttonElement); 
HandlerRegistration handlerRegistration = button.addClickHandler(clickHandler); 
0

前回の回答をご覧ください。オリジナルのソリューションをわずかに変更するだけで機能します。

1

あなたは、これが役に立つかもしれません:

import com.google.gwt.dom.client.Element; 
import com.google.gwt.event.dom.client.ClickEvent; 
import com.google.gwt.event.dom.client.ClickHandler; 
import com.google.gwt.event.dom.client.HasClickHandlers; 
import com.google.gwt.event.shared.HandlerRegistration; 
import com.google.gwt.user.client.ui.AbsolutePanel; 

public class DirectPanel extends AbsolutePanel implements HasClickHandlers { 
     public DirectPanel(Element elem) { 
       super(elem.<com.google.gwt.user.client.Element> cast()); 
       onAttach(); 
     } 

     @Override 
     public HandlerRegistration addClickHandler(ClickHandler handler) { 
       return addDomHandler(handler, ClickEvent.getType()); 
     } 
} 

あなたはその後、ウィジェット容器に、任意のコンテナを作ることができるようになります:

Element root = Document.get().getElementById("target"); 
    DirectPanel p = new DirectPanel(root); 
    Button register = new Button("Register"); 
    register.addClickHandler(new ClickHandler() { 
    @Override 
    public void onClick(ClickEvent event) { 
     // ... 
    } 
    }); 
    p.add(register); 

そして任意の要素にイベントをバインドします

Element root = Document.get().getElementById("target"); 
    DirectPanel p = new DirectPanel(root); 
    p.addClickHandler(new ClickHandler() { 
    @Override 
    public void onClick(ClickEvent event) { 
     // ... 
    } 
    }); 

具体的には、次のように試してみてください。

IFrameElement frm = Document.get().createIFrameElement(); 
Document d = frm.getContentDocument(); 
NodeList<Element> inputs = d.getElementsByTagName("input"); 
InputElement target = null; 
for(int i = 0; i < inputs.getLength(); ++i) { 
    Element e = inputs.getItem(0); 
    if (e.getNodeName().equals("submit")) { 
    target = InputElement.as(e); 
    break; 
    } 
} 
if (target != null) { 
    DirectPanel p = new DirectPanel(target); 
    p.addClickHandler(new ClickHandler() { 
    @Override 
    public void onClick(ClickEvent event) { 
     // TODO Auto-generated method stub 
    } 
    }); 
} 

GWTではこれを非常に難しく、貧弱に文書化しています。

1

iframeを使用する代わりに、com.google.gwt.http.client.RequestBuilder経由でGWTからhttpリクエストを送信することをおすすめします。ように:

private void getHtml(String url) { 
     RequestBuilder rb = new RequestBuilder(RequestBuilder.GET, url); 

     rb.setCallback(new RequestCallback() { 

      @Override 
      public void onResponseReceived(Request request, Response response) { 
       HTMLPanel html = new HTMLPanel(response.getText()); 

       // Now you have a widget with the requested page 
       // thus you may do whatever you want with it. 
      } 

      @Override 
      public void onError(Request request, Throwable exception) { 
       Log.error("error " + exception); 
      } 
     }); 

     try { 
      rb.send(); 
     } catch (RequestException e) { 
      Log.error("error " + e); 
     } 
    } 
関連する問題