2009-07-16 33 views
11

我正在編寫一個涉及與iframe中的外部文檔進行交互的GWT應用程序。作爲一個概念證明,我試圖將一個點擊處理程序附加到一個按鈕上。將GWT事件掛接到外部iframe中的元素上

JavaScript中的以下作品

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!"); 
}; 

試圖做的GWT等價,我做了以下內容:

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()不叫。

我實現了原來的解決方案,把下面的方法來ElementWrapper

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

,並呼籲ElementWrapper後添加wrapper.onAttach()創建。奇蹟般有效!

+0

謝謝!我知道必須有一個更清潔的方式:) – triggerNZ 2009-12-01 01:55:44

0

你可以使用JSNI重用你的JavaScript代碼段。你的javascript代碼會在一個對象上調用gwt方法,該方法會代表iframe中的按鈕拋出它。

至於爲什麼GWT代碼不工作 - 我想這是因爲他們對可能不能跨越超過1幀普通瀏覽器事件的頂部使用一些層。這只是一個猜測。你可以把它作爲GWT團隊的一個功能/ bug請求。如果我是對的,你的代碼看起來很好。

+0

很酷,感謝您的回覆。我想我會探索JSNI路徑,儘管我想遠離編寫自定義JavaScript儘可能。 – triggerNZ 2009-07-19 21:02:05

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 2011-08-02 15:11:04

4

我想到的問題是,當您使用的包裝作爲你的第一個例子中,GWT方法onAttach()不叫。您可以嘗試在Button小部件上使用靜態wrap方法。雖然要使用這個input必須是button類型。或者查看wrap方法的實現。下面是使用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); 
     } 
    } 
相關問題